├── .gitignore ├── CHANGELOG.markdown ├── LICENSE ├── README.markdown ├── build.gradle └── src ├── main └── java │ └── org │ └── I0Itec │ └── zkclient │ ├── ContentWatcher.java │ ├── DataUpdater.java │ ├── DistributedQueue.java │ ├── ExceptionUtil.java │ ├── Gateway.java │ ├── GatewayThread.java │ ├── Holder.java │ ├── IDefaultNameSpace.java │ ├── IZkChildListener.java │ ├── IZkConnection.java │ ├── IZkDataListener.java │ ├── IZkStateListener.java │ ├── InMemoryConnection.java │ ├── NetworkUtil.java │ ├── ZkClient.java │ ├── ZkConnection.java │ ├── ZkEventThread.java │ ├── ZkLock.java │ ├── ZkServer.java │ ├── exception │ ├── ZkBadVersionException.java │ ├── ZkException.java │ ├── ZkInterruptedException.java │ ├── ZkMarshallingError.java │ ├── ZkNoNodeException.java │ ├── ZkNodeExistsException.java │ └── ZkTimeoutException.java │ ├── serialize │ ├── BytesPushThroughSerializer.java │ ├── SerializableSerializer.java │ ├── TcclAwareObjectIputStream.java │ └── ZkSerializer.java │ └── util │ └── ZkPathUtil.java └── test ├── java └── org │ └── I0Itec │ └── zkclient │ ├── AbstractAuthTest.java │ ├── AbstractBaseZkClientTest.java │ ├── AbstractConnectionTest.java │ ├── ContentWatcherTest.java │ ├── DeferredGatewayStarter.java │ ├── DistributedQueueTest.java │ ├── InMemoryAuthTest.java │ ├── InMemoryConnectionTest.java │ ├── MemoryZkClientTest.java │ ├── SaslAuthenticatedTest.java │ ├── ServerZkClientTest.java │ ├── TestUtil.java │ ├── ZkAuthTest.java │ ├── ZkClientSerializationTest.java │ ├── ZkConnectionTest.java │ ├── ZkStateChangeTest.java │ ├── testutil │ └── ZkTestSystem.java │ └── util │ └── ZkPathUtilTest.java └── resources └── log4j.properties /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .classpath 3 | .project 4 | .settings 5 | .gradle 6 | build-eclipse 7 | build 8 | *.iml 9 | gradle 10 | *.bat -------------------------------------------------------------------------------- /CHANGELOG.markdown: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | ===== 3 | 4 | ZkClient 0.8.1 (Feb,2016) 5 | --------------- 6 | -- Update log4j to log4j2 7 | 8 | ZkClient 0.8 (???) 9 | --------------- 10 | 11 | 12 | 13 | ZkClient 0.7 (Nov 2015) 14 | --------------- 15 | - #38: wait on SaslAuthenticated event when SASL is enabled 16 | 17 | 18 | ZkClient 0.6 (Aug 2015) 19 | --------------- 20 | - Adding setAcl and getAcl methods to zkClient so users can setAcls not just during creation but after creation of node as well. 21 | - Upgrade to Zookeeper 3.4.6 (from 3.4.3) 22 | 23 | 24 | ZkClient 0.5 (Apr, 2015) 25 | --------------- 26 | - Upgrade to zookeeper 3.4.3 (from 3.3.1) 27 | - Added support for multiops support 28 | - Add an option to ZkClient to specify operation retry timeout 29 | - Support for ACLs 30 | - #25: fail retryUntilConnected actions with clear exception in case client gets closed 31 | 32 | 33 | ZkClient 0.4 (Oct, 2013) 34 | --------------- 35 | - Support for handling SessionEstablishmentErrors -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2009 Stefan Groschupf 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | ZkClient: a zookeeper client, that makes life a little easier. 2 | ===== 3 | 4 | + Website: https://github.com/sgroschupf/zkclient 5 | + Apache 2.0 License 6 | 7 | ==> see [CHANGELOG][] for recent work 8 | 9 | 10 | Build ZkClient from sources: 11 | --------------- 12 | 13 | + git clone https://github.com/sgroschupf/zkclient.git 14 | + ./gradlew test _(run the test suite)_ 15 | + ./gradlew jars _(build the jars)_ 16 | + (see available build targets by executing './gradlew tasks' ) 17 | 18 | 19 | Howto release ZkClient as maven artifact 20 | --------------- 21 | - sonatype repository is already configured: https://issues.sonatype.org/browse/OSSRH-4783 22 | - generate gpg key and publish it to _hkp://pool.sks-keyservers.net_ (https://docs.sonatype.org/display/Repository/How+To+Generate+PGP+Signatures+With+Maven may be of help) 23 | - tell gradle about the gpg key and sonatype credentials, e.g. through ~/.gradle/gradle.properties: 24 | - sonatypeUsername=$yourSonatypeUser 25 | - sonatypePassword=$yourSonatypePassword 26 | - signing.keyId=$yourKeyId 27 | - signing.password=$yourKeyPassphrase 28 | - signing.secretKeyRingFile=/Users/$username/.gnupg/secring.gpg 29 | - set version in build.gradle to the release version (e.g. 0.5-dev to 0.5) and commit 30 | - upload the signed artifacts to the Sonatype repository 31 | - _gradle clean uploadArchives_ 32 | - go to https://oss.sonatype.org/index.html#stagingRepositories and close the repository 33 | - check the artifacts and if everything is ok, release the repository (on the same page) 34 | - syncing to central maven repository will then be activated (might take around 2h) 35 | - tag with 36 | - _git tag -a $releaseVersion -m "Tag for $releaseVersion release"_ 37 | - _git push --tags_ 38 | - set version in build.gradle to the next dev version (e.g 0.5 to 0.6-dev) and commit 39 | 40 | 41 | [CHANGELOG]: ./CHANGELOG.markdown 42 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'idea' 3 | apply plugin: 'maven' 4 | 5 | group = 'com.101tec' 6 | version = '0.8.1' 7 | 8 | targetCompatibility = 1.8 9 | sourceCompatibility = 1.8 10 | 11 | [compileJava, compileTestJava].each() { 12 | it.options.compilerArgs += ["-Xlint:unchecked", "-Xlint:deprecation", "-Xlint:-options"] 13 | it.options.encoding = "UTF-8" 14 | } 15 | 16 | jar { 17 | manifest { 18 | attributes 'Implementation-Title': 'ZkClient', 'Implementation-Version': version 19 | } 20 | } 21 | 22 | repositories { 23 | maven { 24 | url 'http://maven.oschina.net/content/groups/public/' 25 | } 26 | mavenCentral() 27 | } 28 | 29 | dependencies { 30 | 31 | compile ('org.apache.zookeeper:zookeeper:3.4.6'){ 32 | exclude(module: 'log4j') 33 | exclude(module: 'slf4j-log4j12') 34 | } 35 | compile 'org.slf4j:slf4j-api:1.7.15' 36 | compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.5' 37 | compile 'org.apache.logging.log4j:log4j-core:2.5' 38 | 39 | testCompile 'junit:junit:4.12' 40 | testCompile 'org.assertj:assertj-core:2.0.0' 41 | testCompile 'commons-io:commons-io:1.4' 42 | testCompile 'org.mockito:mockito-core:1.8.0' 43 | 44 | //dependencies of mockito 45 | //testCompile files('lib/objenesis-1.0.jar', 'lib/hamcrest-core-1.1.jar') 46 | } 47 | 48 | 49 | //-------------------- 50 | // Source Jar 51 | //-------------------- 52 | task sourceJar(type: Jar) { 53 | classifier = 'sources' 54 | from sourceSets.main.allSource 55 | } 56 | 57 | task javadocJar(type: Jar, dependsOn:javadoc) { 58 | classifier = 'javadoc' 59 | from javadoc.destinationDir 60 | } 61 | 62 | artifacts { 63 | archives sourceJar 64 | archives javadocJar 65 | } -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/ContentWatcher.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import org.I0Itec.zkclient.exception.ZkNoNodeException; 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | import java.util.concurrent.locks.Condition; 23 | import java.util.concurrent.locks.Lock; 24 | import java.util.concurrent.locks.ReentrantLock; 25 | 26 | //import org.apache.log4j.Logger; 27 | 28 | /** 29 | * @param 30 | * The data type that is being watched. 31 | */ 32 | public final class ContentWatcher implements IZkDataListener { 33 | 34 | //private static final Logger LOG = Logger.getLogger(ContentWatcher.class); 35 | private static final Logger LOG = LoggerFactory.getLogger(ContentWatcher.class); 36 | 37 | private Lock _contentLock = new ReentrantLock(true); 38 | private Condition _contentAvailable = _contentLock.newCondition(); 39 | 40 | private Holder _content; 41 | private String _fileName; 42 | private ZkClient _zkClient; 43 | 44 | public ContentWatcher(ZkClient zkClient, String fileName) { 45 | _fileName = fileName; 46 | _zkClient = zkClient; 47 | } 48 | 49 | public void start() { 50 | _zkClient.subscribeDataChanges(_fileName, this); 51 | readData(); 52 | LOG.debug("Started ContentWatcher"); 53 | } 54 | 55 | @SuppressWarnings("unchecked") 56 | private void readData() { 57 | try { 58 | setContent((T) _zkClient.readData(_fileName)); 59 | } catch (ZkNoNodeException e) { 60 | // ignore if the node has not yet been created 61 | } 62 | } 63 | 64 | public void stop() { 65 | _zkClient.unsubscribeDataChanges(_fileName, this); 66 | } 67 | 68 | public void setContent(T data) { 69 | LOG.debug("Received new data: " + data); 70 | _contentLock.lock(); 71 | try { 72 | _content = new Holder(data); 73 | _contentAvailable.signalAll(); 74 | } finally { 75 | _contentLock.unlock(); 76 | } 77 | } 78 | 79 | @SuppressWarnings("unchecked") 80 | @Override 81 | public void handleDataChange(String dataPath, Object data) { 82 | setContent((T) data); 83 | } 84 | 85 | @Override 86 | public void handleDataDeleted(String dataPath) { 87 | // ignore 88 | } 89 | 90 | public T getContent() throws InterruptedException { 91 | _contentLock.lock(); 92 | try { 93 | while (_content == null) { 94 | _contentAvailable.await(); 95 | } 96 | return _content.get(); 97 | } finally { 98 | _contentLock.unlock(); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/DataUpdater.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | /** 19 | * Updates the data of a znode. This is used together with {@link ZkClient#updateDataSerialized(String, DataUpdater)}. 20 | * 21 | * @param 22 | */ 23 | public interface DataUpdater { 24 | 25 | /** 26 | * Updates the current data of a znode. 27 | * 28 | * @param currentData 29 | * The current contents. 30 | * @return the new data that should be written back to ZooKeeper. 31 | */ 32 | public T update(T currentData); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/DistributedQueue.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import java.io.Serializable; 19 | import java.util.List; 20 | 21 | import org.I0Itec.zkclient.exception.ZkNoNodeException; 22 | 23 | public class DistributedQueue { 24 | 25 | private static class Element { 26 | private String _name; 27 | private T _data; 28 | 29 | public Element(String name, T data) { 30 | _name = name; 31 | _data = data; 32 | } 33 | 34 | public String getName() { 35 | return _name; 36 | } 37 | 38 | public T getData() { 39 | return _data; 40 | } 41 | } 42 | 43 | private ZkClient _zkClient; 44 | private String _root; 45 | 46 | private static final String ELEMENT_NAME = "element"; 47 | 48 | public DistributedQueue(ZkClient zkClient, String root) { 49 | _zkClient = zkClient; 50 | _root = root; 51 | } 52 | 53 | public boolean offer(T element) { 54 | try { 55 | _zkClient.createPersistentSequential(_root + "/" + ELEMENT_NAME + "-", element); 56 | } catch (Exception e) { 57 | throw ExceptionUtil.convertToRuntimeException(e); 58 | } 59 | return true; 60 | } 61 | 62 | public T poll() { 63 | while (true) { 64 | Element element = getFirstElement(); 65 | if (element == null) { 66 | return null; 67 | } 68 | 69 | try { 70 | _zkClient.delete(element.getName()); 71 | return element.getData(); 72 | } catch (ZkNoNodeException e) { 73 | // somebody else picked up the element first, so we have to 74 | // retry with the new first element 75 | } catch (Exception e) { 76 | throw ExceptionUtil.convertToRuntimeException(e); 77 | } 78 | } 79 | } 80 | 81 | private String getSmallestElement(List list) { 82 | String smallestElement = list.get(0); 83 | for (String element : list) { 84 | if (element.compareTo(smallestElement) < 0) { 85 | smallestElement = element; 86 | } 87 | } 88 | 89 | return smallestElement; 90 | } 91 | 92 | public boolean isEmpty() { 93 | return _zkClient.getChildren(_root).size() == 0; 94 | } 95 | 96 | @SuppressWarnings("unchecked") 97 | private Element getFirstElement() { 98 | try { 99 | while (true) { 100 | List list = _zkClient.getChildren(_root); 101 | if (list.size() == 0) { 102 | return null; 103 | } 104 | String elementName = getSmallestElement(list); 105 | 106 | try { 107 | return new Element(_root + "/" + elementName, (T) _zkClient.readData(_root + "/" + elementName)); 108 | } catch (ZkNoNodeException e) { 109 | // somebody else picked up the element first, so we have to 110 | // retry with the new first element 111 | } 112 | } 113 | } catch (Exception e) { 114 | throw ExceptionUtil.convertToRuntimeException(e); 115 | } 116 | } 117 | 118 | public T peek() { 119 | Element element = getFirstElement(); 120 | if (element == null) { 121 | return null; 122 | } 123 | return element.getData(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/ExceptionUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import org.I0Itec.zkclient.exception.ZkInterruptedException; 19 | 20 | public class ExceptionUtil { 21 | 22 | public static RuntimeException convertToRuntimeException(Throwable e) { 23 | if (e instanceof RuntimeException) { 24 | return (RuntimeException) e; 25 | } 26 | retainInterruptFlag(e); 27 | return new RuntimeException(e); 28 | } 29 | 30 | /** 31 | * This sets the interrupt flag if the catched exception was an {@link InterruptedException}. Catching such an 32 | * exception always clears the interrupt flag. 33 | * 34 | * @param catchedException 35 | * The catched exception. 36 | */ 37 | public static void retainInterruptFlag(Throwable catchedException) { 38 | if (catchedException instanceof InterruptedException) { 39 | Thread.currentThread().interrupt(); 40 | } 41 | } 42 | 43 | public static void rethrowInterruptedException(Throwable e) throws InterruptedException { 44 | if (e instanceof InterruptedException) { 45 | throw (InterruptedException) e; 46 | } 47 | if (e instanceof ZkInterruptedException) { 48 | throw (ZkInterruptedException) e; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/Gateway.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | public class Gateway { 19 | 20 | private GatewayThread _thread; 21 | private final int _port; 22 | private final int _destinationPort; 23 | 24 | public Gateway(int port, int destinationPort) { 25 | _port = port; 26 | _destinationPort = destinationPort; 27 | } 28 | 29 | public synchronized void start() { 30 | if (_thread != null) { 31 | throw new IllegalStateException("Gateway already running"); 32 | } 33 | _thread = new GatewayThread(_port, _destinationPort); 34 | _thread.start(); 35 | _thread.awaitUp(); 36 | } 37 | 38 | public synchronized void stop() { 39 | if (_thread != null) { 40 | try { 41 | _thread.interruptAndJoin(); 42 | } catch (InterruptedException e) { 43 | Thread.currentThread().interrupt(); 44 | } 45 | _thread = null; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/GatewayThread.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import org.slf4j.Logger; 19 | import org.slf4j.LoggerFactory; 20 | 21 | import java.io.Closeable; 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.io.OutputStream; 25 | import java.net.ServerSocket; 26 | import java.net.Socket; 27 | import java.net.SocketException; 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | import java.util.Vector; 31 | import java.util.concurrent.locks.Condition; 32 | import java.util.concurrent.locks.Lock; 33 | import java.util.concurrent.locks.ReentrantLock; 34 | 35 | 36 | 37 | public class GatewayThread extends Thread { 38 | 39 | protected final static Logger LOG = LoggerFactory.getLogger(GatewayThread.class); 40 | 41 | private final int _port; 42 | private final int _destinationPort; 43 | private ServerSocket _serverSocket; 44 | private Lock _lock = new ReentrantLock(); 45 | private Condition _runningCondition = _lock.newCondition(); 46 | private boolean _running = false; 47 | 48 | public GatewayThread(int port, int destinationPort) { 49 | _port = port; 50 | _destinationPort = destinationPort; 51 | setDaemon(true); 52 | } 53 | 54 | @Override 55 | public void run() { 56 | final List runningThreads = new Vector(); 57 | try { 58 | LOG.info("Starting gateway on port " + _port + " pointing to port " + _destinationPort); 59 | _serverSocket = new ServerSocket(_port); 60 | _lock.lock(); 61 | try { 62 | _running = true; 63 | _runningCondition.signalAll(); 64 | } finally { 65 | _lock.unlock(); 66 | } 67 | while (true) { 68 | final Socket socket = _serverSocket.accept(); 69 | LOG.info("new client is connected " + socket.getInetAddress()); 70 | final InputStream incomingInputStream = socket.getInputStream(); 71 | final OutputStream incomingOutputStream = socket.getOutputStream(); 72 | 73 | final Socket outgoingSocket; 74 | try { 75 | outgoingSocket = new Socket("localhost", _destinationPort); 76 | } catch (Exception e) { 77 | LOG.warn("could not connect to " + _destinationPort); 78 | continue; 79 | } 80 | final InputStream outgoingInputStream = outgoingSocket.getInputStream(); 81 | final OutputStream outgoingOutputStream = outgoingSocket.getOutputStream(); 82 | 83 | Thread writeThread = new Thread() { 84 | @Override 85 | public void run() { 86 | runningThreads.add(this); 87 | try { 88 | int read = -1; 89 | while ((read = incomingInputStream.read()) != -1) { 90 | outgoingOutputStream.write(read); 91 | } 92 | } catch (IOException e) { 93 | // ignore 94 | } finally { 95 | closeQuietly(outgoingOutputStream); 96 | runningThreads.remove(this); 97 | } 98 | } 99 | 100 | @Override 101 | public void interrupt() { 102 | try { 103 | socket.close(); 104 | outgoingSocket.close(); 105 | } catch (IOException e) { 106 | LOG.error("error on stopping closing sockets", e); 107 | } 108 | 109 | super.interrupt(); 110 | } 111 | }; 112 | 113 | Thread readThread = new Thread() { 114 | @Override 115 | public void run() { 116 | runningThreads.add(this); 117 | try { 118 | int read = -1; 119 | while ((read = outgoingInputStream.read()) != -1) { 120 | incomingOutputStream.write(read); 121 | } 122 | } catch (IOException e) { 123 | // ignore 124 | } finally { 125 | closeQuietly(incomingOutputStream); 126 | runningThreads.remove(this); 127 | } 128 | } 129 | }; 130 | 131 | writeThread.setDaemon(true); 132 | readThread.setDaemon(true); 133 | 134 | writeThread.start(); 135 | readThread.start(); 136 | } 137 | } catch (SocketException e) { 138 | if (!_running) { 139 | throw ExceptionUtil.convertToRuntimeException(e); 140 | } 141 | LOG.info("Stopping gateway"); 142 | } catch (Exception e) { 143 | LOG.error("error on gateway execution", e); 144 | } 145 | 146 | for (Thread thread : new ArrayList(runningThreads)) { 147 | thread.interrupt(); 148 | try { 149 | thread.join(); 150 | } catch (InterruptedException e) { 151 | // ignore 152 | } 153 | } 154 | } 155 | 156 | protected void closeQuietly(Closeable closable) { 157 | try { 158 | closable.close(); 159 | } catch (IOException e) { 160 | // ignore 161 | } 162 | } 163 | 164 | @Override 165 | public void interrupt() { 166 | try { 167 | _serverSocket.close(); 168 | } catch (Exception cE) { 169 | LOG.error("error on stopping gateway", cE); 170 | } 171 | super.interrupt(); 172 | } 173 | 174 | public void interruptAndJoin() throws InterruptedException { 175 | interrupt(); 176 | join(); 177 | } 178 | 179 | public void awaitUp() { 180 | _lock.lock(); 181 | try { 182 | while (!_running) { 183 | _runningCondition.await(); 184 | } 185 | } catch (InterruptedException e) { 186 | Thread.currentThread().interrupt(); 187 | } finally { 188 | _lock.unlock(); 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/Holder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | public class Holder { 19 | 20 | private T _value; 21 | 22 | public Holder() { 23 | // do nothing 24 | } 25 | 26 | public Holder(T value) { 27 | _value = value; 28 | } 29 | 30 | public T get() { 31 | return _value; 32 | } 33 | 34 | public void set(T value) { 35 | _value = value; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/IDefaultNameSpace.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | public interface IDefaultNameSpace { 19 | 20 | /** 21 | * Creates a set of default folder structure within a zookeeper . 22 | * 23 | * @param zkClient 24 | * The zkclient. 25 | */ 26 | public void createDefaultNameSpace(ZkClient zkClient); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/IZkChildListener.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import java.util.List; 19 | 20 | /** 21 | * An {@link IZkChildListener} can be registered at a {@link ZkClient} for listening on zk child changes for a given 22 | * path. 23 | * 24 | * Node: Also this listener re-subscribes it watch for the path on each zk event (zk watches are one-timers) is is not 25 | * guaranteed that events on the path are missing (see http://zookeeper.wiki.sourceforge.net/ZooKeeperWatches). An 26 | * implementation of this class should take that into account. 27 | * 28 | */ 29 | public interface IZkChildListener { 30 | 31 | /** 32 | * Called when the children of the given path changed. 33 | * 34 | * @param parentPath 35 | * The parent path 36 | * @param currentChilds 37 | * The children or null if the root node (parent path) was deleted. 38 | * @throws Exception 39 | */ 40 | public void handleChildChange(String parentPath, List currentChilds) throws Exception; 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/IZkConnection.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | import org.apache.zookeeper.CreateMode; 22 | import org.apache.zookeeper.KeeperException; 23 | import org.apache.zookeeper.Op; 24 | import org.apache.zookeeper.OpResult; 25 | import org.apache.zookeeper.Watcher; 26 | import org.apache.zookeeper.ZooKeeper.States; 27 | import org.apache.zookeeper.data.ACL; 28 | import org.apache.zookeeper.data.Stat; 29 | 30 | public interface IZkConnection { 31 | 32 | public void connect(Watcher watcher); 33 | 34 | void close() throws InterruptedException; 35 | 36 | public String create(String path, byte[] data, CreateMode mode) throws KeeperException, InterruptedException; 37 | 38 | public String create(String path, byte[] data, List acl, CreateMode mode) throws KeeperException, InterruptedException; 39 | 40 | public void delete(String path) throws InterruptedException, KeeperException; 41 | 42 | boolean exists(final String path, final boolean watch) throws KeeperException, InterruptedException; 43 | 44 | List getChildren(final String path, final boolean watch) throws KeeperException, InterruptedException; 45 | 46 | public byte[] readData(String path, Stat stat, boolean watch) throws KeeperException, InterruptedException; 47 | 48 | public void writeData(String path, byte[] data, int expectedVersion) throws KeeperException, InterruptedException; 49 | 50 | public Stat writeDataReturnStat(String path, byte[] data, int expectedVersion) throws KeeperException, InterruptedException; 51 | 52 | public States getZookeeperState(); 53 | 54 | public long getCreateTime(String path) throws KeeperException, InterruptedException; 55 | 56 | public String getServers(); 57 | 58 | public List multi(Iterable ops) throws KeeperException, InterruptedException; 59 | 60 | public void addAuthInfo(String scheme, byte[] auth); 61 | 62 | public void setAcl(final String path, List acl, int version) throws KeeperException, InterruptedException; 63 | 64 | public Map.Entry, Stat> getAcl(final String path) throws KeeperException, InterruptedException; 65 | } -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/IZkDataListener.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | /** 19 | * An {@link IZkDataListener} can be registered at a {@link ZkClient} for listening on zk data changes for a given path. 20 | * 21 | * Node: Also this listener re-subscribes it watch for the path on each zk event (zk watches are one-timers) is is not 22 | * guaranteed that events on the path are missing (see http://zookeeper.wiki.sourceforge.net/ZooKeeperWatches). An 23 | * implementation of this class should take that into account. 24 | */ 25 | public interface IZkDataListener { 26 | 27 | public void handleDataChange(String dataPath, Object data) throws Exception; 28 | 29 | public void handleDataDeleted(String dataPath) throws Exception; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/IZkStateListener.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import org.apache.zookeeper.Watcher.Event.KeeperState; 19 | 20 | public interface IZkStateListener { 21 | 22 | /** 23 | * Called when the zookeeper connection state has changed. 24 | * 25 | * @param state 26 | * The new state. 27 | * @throws Exception 28 | * On any error. 29 | */ 30 | public void handleStateChanged(KeeperState state) throws Exception; 31 | 32 | /** 33 | * Called after the zookeeper session has expired and a new session has been created. You would have to re-create 34 | * any ephemeral nodes here. 35 | * 36 | * @throws Exception 37 | * On any error. 38 | */ 39 | public void handleNewSession() throws Exception; 40 | 41 | /** 42 | * Called when a session cannot be re-established. This should be used to implement connection 43 | * failure handling e.g. retry to connect or pass the error up 44 | * 45 | * @param error 46 | * The error that prevents a session from being established 47 | * @throws Exception 48 | * On any error. 49 | */ 50 | public void handleSessionEstablishmentError(final Throwable error) throws Exception; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/InMemoryConnection.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import java.util.*; 19 | import java.util.concurrent.BlockingQueue; 20 | import java.util.concurrent.LinkedBlockingDeque; 21 | import java.util.concurrent.atomic.AtomicInteger; 22 | import java.util.concurrent.locks.Lock; 23 | import java.util.concurrent.locks.ReentrantLock; 24 | 25 | import org.I0Itec.zkclient.exception.ZkException; 26 | import org.I0Itec.zkclient.exception.ZkInterruptedException; 27 | import org.I0Itec.zkclient.exception.ZkNoNodeException; 28 | import org.I0Itec.zkclient.util.ZkPathUtil; 29 | import org.apache.zookeeper.CreateMode; 30 | import org.apache.zookeeper.KeeperException; 31 | import org.apache.zookeeper.KeeperException.Code; 32 | import org.apache.zookeeper.Op; 33 | import org.apache.zookeeper.OpResult; 34 | import org.apache.zookeeper.WatchedEvent; 35 | import org.apache.zookeeper.Watcher; 36 | import org.apache.zookeeper.Watcher.Event.EventType; 37 | import org.apache.zookeeper.Watcher.Event.KeeperState; 38 | import org.apache.zookeeper.ZooDefs; 39 | import org.apache.zookeeper.ZooKeeper.States; 40 | import org.apache.zookeeper.data.ACL; 41 | import org.apache.zookeeper.data.Id; 42 | import org.apache.zookeeper.data.Stat; 43 | import org.apache.zookeeper.proto.CheckVersionRequest; 44 | import org.apache.zookeeper.proto.CreateRequest; 45 | import org.apache.zookeeper.proto.DeleteRequest; 46 | import org.apache.zookeeper.proto.SetDataRequest; 47 | 48 | /** 49 | * Emulating a ZooKeeper server with few hash tables. Basically a mock class used for testing. Please avoid using this 50 | * as your ZK in production :) 51 | * 52 | * Note that the addAuth is even more mocked than usual Since we have no authentication provider (i.e. Kerberos) around 53 | * we simply take the auth byte[] and convert it to string to get the Id scheme remains the same 54 | */ 55 | public class InMemoryConnection implements IZkConnection { 56 | 57 | public static class DataAndVersion { 58 | private byte[] _data; 59 | private int _version; 60 | private List _acl; 61 | 62 | public DataAndVersion(byte[] data, int version, List acl) { 63 | _data = data; 64 | _version = version; 65 | _acl = acl; 66 | } 67 | 68 | public DataAndVersion(byte[] data, int version) { 69 | this(data, version, null); 70 | } 71 | 72 | public byte[] getData() { 73 | return _data; 74 | } 75 | 76 | public int getVersion() { 77 | return _version; 78 | } 79 | 80 | public List getAcl() { 81 | return _acl; 82 | } 83 | } 84 | 85 | private Lock _lock = new ReentrantLock(true); 86 | private Map _data = new HashMap(); 87 | private Map _creationTime = new HashMap(); 88 | private List _ids = new ArrayList(); 89 | private final AtomicInteger sequence = new AtomicInteger(0); 90 | 91 | private Set _dataWatches = new HashSet(); 92 | private Set _nodeWatches = new HashSet(); 93 | private EventThread _eventThread; 94 | 95 | private class EventThread extends Thread { 96 | 97 | private Watcher _watcher; 98 | private BlockingQueue _blockingQueue = new LinkedBlockingDeque(); 99 | 100 | public EventThread(Watcher watcher) { 101 | _watcher = watcher; 102 | } 103 | 104 | @Override 105 | public void run() { 106 | try { 107 | while (true) { 108 | _watcher.process(_blockingQueue.take()); 109 | } 110 | } catch (InterruptedException e) { 111 | // stop event thread 112 | } 113 | } 114 | 115 | public void send(WatchedEvent event) { 116 | _blockingQueue.add(event); 117 | } 118 | } 119 | 120 | public InMemoryConnection() { 121 | try { 122 | create("/", null, CreateMode.PERSISTENT); 123 | } catch (KeeperException e) { 124 | throw ZkException.create(e); 125 | } catch (InterruptedException e) { 126 | Thread.currentThread().interrupt(); 127 | throw new ZkInterruptedException(e); 128 | } 129 | } 130 | 131 | @Override 132 | public void close() throws InterruptedException { 133 | _lock.lockInterruptibly(); 134 | try { 135 | if (_eventThread != null) { 136 | _eventThread.interrupt(); 137 | _eventThread.join(); 138 | _eventThread = null; 139 | } 140 | } finally { 141 | _lock.unlock(); 142 | } 143 | } 144 | 145 | @Override 146 | public void connect(Watcher watcher) { 147 | _lock.lock(); 148 | try { 149 | if (_eventThread != null) { 150 | throw new IllegalStateException("Already connected."); 151 | } 152 | _eventThread = new EventThread(watcher); 153 | _eventThread.start(); 154 | _eventThread.send(new WatchedEvent(null, KeeperState.SyncConnected, null)); 155 | } finally { 156 | _lock.unlock(); 157 | } 158 | } 159 | 160 | @Override 161 | public String create(String path, byte[] data, List acl, CreateMode mode) throws KeeperException, InterruptedException { 162 | _lock.lock(); 163 | try { 164 | 165 | if (mode.isSequential()) { 166 | final int newSequence = sequence.getAndIncrement(); 167 | path = path + ZkPathUtil.leadingZeros(newSequence, 10); 168 | } 169 | 170 | if (exists(path, false)) { 171 | throw new KeeperException.NodeExistsException(); 172 | } 173 | String parentPath = getParentPath(path); 174 | checkACL(parentPath, ZooDefs.Perms.CREATE); 175 | 176 | _data.put(path, new DataAndVersion(data, 0, acl)); 177 | _creationTime.put(path, System.currentTimeMillis()); 178 | checkWatch(_nodeWatches, path, EventType.NodeCreated); 179 | // we also need to send a child change event for the parent 180 | if (parentPath != null) { 181 | checkWatch(_nodeWatches, parentPath, EventType.NodeChildrenChanged); 182 | } 183 | return path; 184 | } finally { 185 | _lock.unlock(); 186 | } 187 | } 188 | 189 | @Override 190 | public String create(String path, byte[] data, CreateMode mode) throws KeeperException, InterruptedException { 191 | return create(path, data, null, mode); 192 | } 193 | 194 | private String getParentPath(String path) { 195 | int lastIndexOf = path.lastIndexOf("/"); 196 | if (lastIndexOf == -1 || lastIndexOf == 0) { 197 | return null; 198 | } 199 | return path.substring(0, lastIndexOf); 200 | } 201 | 202 | @Override 203 | public void delete(String path) throws InterruptedException, KeeperException { 204 | _lock.lock(); 205 | try { 206 | if (!exists(path, false)) { 207 | throw new KeeperException.NoNodeException(); 208 | } 209 | String parentPath = getParentPath(path); 210 | checkACL(parentPath, ZooDefs.Perms.DELETE); 211 | _data.remove(path); 212 | _creationTime.remove(path); 213 | checkWatch(_nodeWatches, path, EventType.NodeDeleted); 214 | if (parentPath != null) { 215 | checkWatch(_nodeWatches, parentPath, EventType.NodeChildrenChanged); 216 | } 217 | } finally { 218 | _lock.unlock(); 219 | } 220 | } 221 | 222 | @Override 223 | public boolean exists(String path, boolean watch) throws KeeperException, InterruptedException { 224 | _lock.lock(); 225 | try { 226 | if (watch) { 227 | installWatch(_nodeWatches, path); 228 | } 229 | return _data.containsKey(path); 230 | } finally { 231 | _lock.unlock(); 232 | } 233 | } 234 | 235 | private void installWatch(Set watches, String path) { 236 | watches.add(path); 237 | } 238 | 239 | @Override 240 | public List getChildren(String path, boolean watch) throws KeeperException, InterruptedException { 241 | if (!exists(path, false)) { 242 | throw KeeperException.create(Code.NONODE, path); 243 | } 244 | if (exists(path, false) && watch) { 245 | installWatch(_nodeWatches, path); 246 | } 247 | 248 | checkACL(path, ZooDefs.Perms.READ); 249 | ArrayList children = new ArrayList(); 250 | String[] directoryStack = path.split("/"); 251 | Set keySet = _data.keySet(); 252 | 253 | for (String string : keySet) { 254 | if (string.startsWith(path)) { 255 | String[] stack = string.split("/"); 256 | // is one folder level below the one we loockig for and starts 257 | // with path... 258 | if (stack.length == directoryStack.length + 1) { 259 | children.add(stack[stack.length - 1]); 260 | } 261 | } 262 | 263 | } 264 | return children; 265 | } 266 | 267 | @Override 268 | public States getZookeeperState() { 269 | _lock.lock(); 270 | try { 271 | if (_eventThread == null) { 272 | return States.CLOSED; 273 | } 274 | return States.CONNECTED; 275 | } finally { 276 | _lock.unlock(); 277 | } 278 | } 279 | 280 | @Override 281 | public byte[] readData(String path, Stat stat, boolean watch) throws KeeperException, InterruptedException { 282 | if (watch) { 283 | installWatch(_dataWatches, path); 284 | } 285 | _lock.lock(); 286 | try { 287 | DataAndVersion dataAndVersion = _data.get(path); 288 | if (dataAndVersion == null) { 289 | throw new ZkNoNodeException(new KeeperException.NoNodeException()); 290 | } 291 | checkACL(path, ZooDefs.Perms.READ); 292 | byte[] bs = dataAndVersion.getData(); 293 | if (stat != null) 294 | stat.setVersion(dataAndVersion.getVersion()); 295 | return bs; 296 | } finally { 297 | _lock.unlock(); 298 | } 299 | } 300 | 301 | @Override 302 | public void writeData(String path, byte[] data, int expectedVersion) throws KeeperException, InterruptedException { 303 | writeDataReturnStat(path, data, expectedVersion); 304 | } 305 | 306 | @Override 307 | public Stat writeDataReturnStat(String path, byte[] data, int expectedVersion) throws KeeperException, InterruptedException { 308 | int newVersion = -1; 309 | _lock.lock(); 310 | try { 311 | checkWatch(_dataWatches, path, EventType.NodeDataChanged); 312 | if (!exists(path, false)) { 313 | throw new KeeperException.NoNodeException(); 314 | } 315 | checkACL(path, ZooDefs.Perms.WRITE); 316 | newVersion = _data.get(path).getVersion() + 1; 317 | _data.put(path, new DataAndVersion(data, newVersion)); 318 | String parentPath = getParentPath(path); 319 | if (parentPath != null) { 320 | checkWatch(_nodeWatches, parentPath, EventType.NodeChildrenChanged); 321 | } 322 | } finally { 323 | _lock.unlock(); 324 | } 325 | Stat stat = new Stat(); 326 | stat.setVersion(newVersion); 327 | return stat; 328 | } 329 | 330 | private void checkWatch(Set watches, String path, EventType eventType) { 331 | if (watches.contains(path)) { 332 | watches.remove(path); 333 | _eventThread.send(new WatchedEvent(eventType, KeeperState.SyncConnected, path)); 334 | } 335 | } 336 | 337 | @Override 338 | public long getCreateTime(String path) { 339 | Long time = _creationTime.get(path); 340 | if (time == null) { 341 | return -1; 342 | } 343 | return time; 344 | } 345 | 346 | @Override 347 | public String getServers() { 348 | return "mem"; 349 | } 350 | 351 | public List multi(Iterable ops) throws KeeperException, InterruptedException { 352 | List opResults = new ArrayList(); 353 | for (Op op : ops) { 354 | if (Op.Check.class.isAssignableFrom(op.getClass())) { 355 | CheckVersionRequest check = (CheckVersionRequest) op.toRequestRecord(); 356 | exists(check.getPath(), false); 357 | opResults.add(new OpResult.CheckResult()); 358 | } else if (Op.Create.class.isAssignableFrom(op.getClass())) { 359 | CreateRequest create = (CreateRequest) op.toRequestRecord(); 360 | String path = create(create.getPath(), create.getData(), CreateMode.fromFlag(create.getFlags())); 361 | opResults.add(new OpResult.CreateResult(path)); 362 | } else if (Op.Delete.class.isAssignableFrom(op.getClass())) { 363 | DeleteRequest delete = (DeleteRequest) op.toRequestRecord(); 364 | delete(delete.getPath()); 365 | opResults.add(new OpResult.DeleteResult()); 366 | } else if (Op.SetData.class.isAssignableFrom(op.getClass())) { 367 | SetDataRequest setData = (SetDataRequest) op.toRequestRecord(); 368 | writeData(setData.getPath(), setData.getData(), setData.getVersion()); 369 | opResults.add(new OpResult.SetDataResult(null)); 370 | } 371 | } 372 | return opResults; 373 | } 374 | 375 | @Override 376 | public void addAuthInfo(String scheme, byte[] auth) { 377 | _ids.add(new Id(scheme, new String(auth))); 378 | } 379 | 380 | @Override 381 | public void setAcl(String path, List acl, int version) throws KeeperException, InterruptedException { 382 | if (!exists(path, false)) { 383 | throw new KeeperException.NoNodeException(); 384 | } 385 | 386 | DataAndVersion dataAndVersion = _data.get(path); 387 | if(version != dataAndVersion._version) { 388 | throw new KeeperException.BadVersionException(); 389 | } 390 | 391 | checkACL(path, ZooDefs.Perms.ADMIN); 392 | 393 | _lock.lock(); 394 | try { 395 | _data.put(path, new DataAndVersion(dataAndVersion.getData(), dataAndVersion.getVersion() + 1, acl)); 396 | } finally { 397 | _lock.unlock(); 398 | } 399 | } 400 | 401 | @Override 402 | public Map.Entry, Stat> getAcl(String path) throws KeeperException, InterruptedException { 403 | if (!exists(path, false)) { 404 | throw new KeeperException.NoNodeException(); 405 | } 406 | 407 | DataAndVersion dataAndVersion = _data.get(path); 408 | 409 | Stat stat = new Stat(); 410 | stat.setVersion(dataAndVersion.getVersion()); 411 | stat.setCtime(_creationTime.get(path)); 412 | 413 | return new AbstractMap.SimpleEntry, Stat>(dataAndVersion.getAcl(), stat); 414 | } 415 | 416 | /*** 417 | * 418 | * @param path 419 | * - path of znode we are accessing 420 | * @param perm 421 | * - Privileges required for the action 422 | * @throws KeeperException.NoAuthException 423 | */ 424 | private void checkACL(String path, int perm) throws KeeperException.NoAuthException { 425 | DataAndVersion node = _data.get(path); 426 | if (node == null) { 427 | return; 428 | } 429 | List acl = node.getAcl(); 430 | if (acl == null || acl.size() == 0) { 431 | return; 432 | } 433 | for (Id authId : _ids) { 434 | if (authId.getScheme().equals("super")) { 435 | return; 436 | } 437 | } 438 | for (ACL a : acl) { 439 | Id id = a.getId(); 440 | if ((a.getPerms() & perm) != 0) { 441 | if (id.getScheme().equals("world") && id.getId().equals("anyone")) { 442 | return; 443 | } 444 | for (Id authId : _ids) { 445 | if (authId.getScheme().equals(id.getScheme()) && authId.getId().equals(id.getId())) { 446 | return; 447 | } 448 | } 449 | } 450 | } 451 | throw new KeeperException.NoAuthException(); 452 | } 453 | } 454 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/NetworkUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import java.io.IOException; 19 | import java.net.ConnectException; 20 | import java.net.InetAddress; 21 | import java.net.NetworkInterface; 22 | import java.net.Socket; 23 | import java.net.SocketException; 24 | import java.net.UnknownHostException; 25 | import java.util.Enumeration; 26 | import java.util.HashSet; 27 | import java.util.Set; 28 | 29 | public class NetworkUtil { 30 | 31 | public final static String OVERWRITE_HOSTNAME_SYSTEM_PROPERTY = "zkclient.hostname.overwritten"; 32 | 33 | public static String[] getLocalHostNames() { 34 | final Set hostNames = new HashSet(); 35 | // we add localhost to this set manually, because if the ip 127.0.0.1 is 36 | // configured with more than one name in the /etc/hosts, only the first 37 | // name 38 | // is returned 39 | hostNames.add("localhost"); 40 | try { 41 | final Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); 42 | for (final Enumeration ifaces = networkInterfaces; ifaces.hasMoreElements();) { 43 | final NetworkInterface iface = ifaces.nextElement(); 44 | InetAddress ia = null; 45 | for (final Enumeration ips = iface.getInetAddresses(); ips.hasMoreElements();) { 46 | ia = ips.nextElement(); 47 | hostNames.add(ia.getCanonicalHostName()); 48 | hostNames.add(ipToString(ia.getAddress())); 49 | } 50 | } 51 | } catch (final SocketException e) { 52 | throw new RuntimeException("unable to retrieve host names of localhost"); 53 | } 54 | return hostNames.toArray(new String[hostNames.size()]); 55 | } 56 | 57 | private static String ipToString(final byte[] bytes) { 58 | final StringBuffer addrStr = new StringBuffer(); 59 | for (int cnt = 0; cnt < bytes.length; cnt++) { 60 | final int uByte = bytes[cnt] < 0 ? bytes[cnt] + 256 : bytes[cnt]; 61 | addrStr.append(uByte); 62 | if (cnt < 3) 63 | addrStr.append('.'); 64 | } 65 | return addrStr.toString(); 66 | } 67 | 68 | public static int hostNamesInList(final String serverList, final String[] hostNames) { 69 | final String[] serverNames = serverList.split(","); 70 | for (int i = 0; i < hostNames.length; i++) { 71 | final String hostname = hostNames[i]; 72 | for (int j = 0; j < serverNames.length; j++) { 73 | final String serverNameAndPort = serverNames[j]; 74 | final String serverName = serverNameAndPort.split(":")[0]; 75 | if (serverName.equalsIgnoreCase(hostname)) { 76 | return j; 77 | } 78 | } 79 | } 80 | return -1; 81 | } 82 | 83 | public static boolean hostNameInArray(final String[] hostNames, final String hostName) { 84 | for (final String name : hostNames) { 85 | if (name.equalsIgnoreCase(hostName)) { 86 | return true; 87 | } 88 | } 89 | return false; 90 | } 91 | 92 | public static boolean isPortFree(int port) { 93 | try { 94 | Socket socket = new Socket("localhost", port); 95 | socket.close(); 96 | return false; 97 | } catch (ConnectException e) { 98 | return true; 99 | } catch (SocketException e) { 100 | if (e.getMessage().equals("Connection reset by peer")) { 101 | return true; 102 | } 103 | throw new RuntimeException(e); 104 | } catch (UnknownHostException e) { 105 | throw new RuntimeException(e); 106 | } catch (IOException e) { 107 | throw new RuntimeException(e); 108 | } 109 | } 110 | 111 | public static String getLocalhostName() { 112 | String property = System.getProperty(OVERWRITE_HOSTNAME_SYSTEM_PROPERTY); 113 | if (property != null && property.trim().length() > 0) { 114 | return property; 115 | } 116 | try { 117 | return InetAddress.getLocalHost().getHostName(); 118 | } catch (final UnknownHostException e) { 119 | throw new RuntimeException("unable to retrieve localhost name"); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/ZkConnection.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import org.I0Itec.zkclient.exception.ZkException; 19 | import org.apache.zookeeper.*; 20 | import org.apache.zookeeper.ZooDefs.Ids; 21 | import org.apache.zookeeper.ZooKeeper.States; 22 | import org.apache.zookeeper.data.ACL; 23 | import org.apache.zookeeper.data.Stat; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | import java.io.IOException; 28 | import java.util.AbstractMap.SimpleEntry; 29 | import java.util.List; 30 | import java.util.Map; 31 | import java.util.concurrent.locks.Lock; 32 | import java.util.concurrent.locks.ReentrantLock; 33 | 34 | public class ZkConnection implements IZkConnection { 35 | 36 | //private static final Logger LOG = Logger.getLogger(ZkConnection.class); 37 | 38 | private static final Logger LOG = LoggerFactory.getLogger(ZkConnection.class); 39 | /** It is recommended to use quite large sessions timeouts for ZooKeeper. */ 40 | private static final int DEFAULT_SESSION_TIMEOUT = 30000; 41 | 42 | private ZooKeeper _zk = null; 43 | private Lock _zookeeperLock = new ReentrantLock(); 44 | 45 | private final String _servers; 46 | private final int _sessionTimeOut; 47 | 48 | public ZkConnection(String zkServers) { 49 | this(zkServers, DEFAULT_SESSION_TIMEOUT); 50 | } 51 | 52 | public ZkConnection(String zkServers, int sessionTimeOut) { 53 | _servers = zkServers; 54 | _sessionTimeOut = sessionTimeOut; 55 | } 56 | 57 | @Override 58 | public void connect(Watcher watcher) { 59 | _zookeeperLock.lock(); 60 | try { 61 | if (_zk != null) { 62 | throw new IllegalStateException("zk client has already been started"); 63 | } 64 | try { 65 | LOG.debug("Creating new ZookKeeper instance to connect to " + _servers + "."); 66 | _zk = new ZooKeeper(_servers, _sessionTimeOut, watcher); 67 | } catch (IOException e) { 68 | throw new ZkException("Unable to connect to " + _servers, e); 69 | } 70 | } finally { 71 | _zookeeperLock.unlock(); 72 | } 73 | } 74 | 75 | @Override 76 | public void close() throws InterruptedException { 77 | _zookeeperLock.lock(); 78 | try { 79 | if (_zk != null) { 80 | LOG.debug("Closing ZooKeeper connected to " + _servers); 81 | _zk.close(); 82 | _zk = null; 83 | } 84 | } finally { 85 | _zookeeperLock.unlock(); 86 | } 87 | } 88 | 89 | @Override 90 | public String create(String path, byte[] data, CreateMode mode) throws KeeperException, InterruptedException { 91 | return _zk.create(path, data, Ids.OPEN_ACL_UNSAFE, mode); 92 | } 93 | 94 | @Override 95 | public String create(String path, byte[] data, List acl, CreateMode mode) throws KeeperException, InterruptedException { 96 | return _zk.create(path, data, acl, mode); 97 | } 98 | 99 | @Override 100 | public void delete(String path) throws InterruptedException, KeeperException { 101 | _zk.delete(path, -1); 102 | } 103 | 104 | @Override 105 | public boolean exists(String path, boolean watch) throws KeeperException, InterruptedException { 106 | return _zk.exists(path, watch) != null; 107 | } 108 | 109 | @Override 110 | public List getChildren(final String path, final boolean watch) throws KeeperException, InterruptedException { 111 | return _zk.getChildren(path, watch); 112 | } 113 | 114 | @Override 115 | public byte[] readData(String path, Stat stat, boolean watch) throws KeeperException, InterruptedException { 116 | return _zk.getData(path, watch, stat); 117 | } 118 | 119 | public void writeData(String path, byte[] data) throws KeeperException, InterruptedException { 120 | writeData(path, data, -1); 121 | } 122 | 123 | @Override 124 | public void writeData(String path, byte[] data, int version) throws KeeperException, InterruptedException { 125 | _zk.setData(path, data, version); 126 | } 127 | 128 | @Override 129 | public Stat writeDataReturnStat(String path, byte[] data, int version) throws KeeperException, InterruptedException { 130 | return _zk.setData(path, data, version); 131 | } 132 | 133 | @Override 134 | public States getZookeeperState() { 135 | return _zk != null ? _zk.getState() : null; 136 | } 137 | 138 | public ZooKeeper getZookeeper() { 139 | return _zk; 140 | } 141 | 142 | @Override 143 | public long getCreateTime(String path) throws KeeperException, InterruptedException { 144 | Stat stat = _zk.exists(path, false); 145 | if (stat != null) { 146 | return stat.getCtime(); 147 | } 148 | return -1; 149 | } 150 | 151 | @Override 152 | public String getServers() { 153 | return _servers; 154 | } 155 | 156 | @Override 157 | public List multi(Iterable ops) throws KeeperException, InterruptedException { 158 | return _zk.multi(ops); 159 | } 160 | 161 | @Override 162 | public void addAuthInfo(String scheme, byte[] auth) { 163 | _zk.addAuthInfo(scheme, auth); 164 | } 165 | 166 | @Override 167 | public void setAcl(String path, List acl, int version) throws KeeperException, InterruptedException { 168 | _zk.setACL(path, acl, version); 169 | } 170 | 171 | @Override 172 | public Map.Entry, Stat> getAcl(String path) throws KeeperException, InterruptedException { 173 | Stat stat = new Stat(); 174 | List acl = _zk.getACL(path, stat); 175 | return new SimpleEntry(acl, stat); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/ZkEventThread.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import org.I0Itec.zkclient.exception.ZkInterruptedException; 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | import java.util.concurrent.BlockingQueue; 23 | import java.util.concurrent.LinkedBlockingQueue; 24 | import java.util.concurrent.atomic.AtomicInteger; 25 | 26 | 27 | /** 28 | * All listeners registered at the {@link ZkClient} will be notified from this event thread. This is to prevent 29 | * dead-lock situations. The {@link ZkClient} pulls some information out of the {@link ZooKeeper} events to signal 30 | * {@link ZkLock} conditions. Re-using the {@link ZooKeeper} event thread to also notify {@link ZkClient} listeners, 31 | * would stop the ZkClient from receiving events from {@link ZooKeeper} as soon as one of the listeners blocks (because 32 | * it is waiting for something). {@link ZkClient} would then for instance not be able to maintain it's connection state 33 | * anymore. 34 | */ 35 | class ZkEventThread extends Thread { 36 | 37 | //private static final Logger LOG = Logger.getLogger(ZkEventThread.class); 38 | 39 | private static final Logger LOG = LoggerFactory.getLogger(ZkEventThread.class); 40 | 41 | private BlockingQueue _events = new LinkedBlockingQueue(); 42 | 43 | private static AtomicInteger _eventId = new AtomicInteger(0); 44 | 45 | static abstract class ZkEvent { 46 | 47 | private String _description; 48 | 49 | public ZkEvent(String description) { 50 | _description = description; 51 | } 52 | 53 | public abstract void run() throws Exception; 54 | 55 | @Override 56 | public String toString() { 57 | return "ZkEvent[" + _description + "]"; 58 | } 59 | } 60 | 61 | ZkEventThread(String name) { 62 | setDaemon(true); 63 | setName("ZkClient-EventThread-" + getId() + "-" + name); 64 | } 65 | 66 | @Override 67 | public void run() { 68 | LOG.info("Starting ZkClient event thread."); 69 | try { 70 | while (!isInterrupted()) { 71 | ZkEvent zkEvent = _events.take(); 72 | int eventId = _eventId.incrementAndGet(); 73 | LOG.debug("Delivering event #" + eventId + " " + zkEvent); 74 | try { 75 | zkEvent.run(); 76 | } catch (InterruptedException e) { 77 | interrupt(); 78 | } catch (ZkInterruptedException e) { 79 | interrupt(); 80 | } catch (Throwable e) { 81 | LOG.error("Error handling event " + zkEvent, e); 82 | } 83 | LOG.debug("Delivering event #" + eventId + " done"); 84 | } 85 | } catch (InterruptedException e) { 86 | LOG.info("Terminate ZkClient event thread."); 87 | } 88 | } 89 | 90 | public void send(ZkEvent event) { 91 | if (!isInterrupted()) { 92 | LOG.debug("New event: " + event); 93 | _events.add(event); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/ZkLock.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import java.util.concurrent.locks.Condition; 19 | import java.util.concurrent.locks.ReentrantLock; 20 | 21 | public class ZkLock extends ReentrantLock { 22 | 23 | private static final long serialVersionUID = 1L; 24 | 25 | private Condition _dataChangedCondition = newCondition(); 26 | private Condition _stateChangedCondition = newCondition(); 27 | private Condition _zNodeEventCondition = newCondition(); 28 | 29 | /** 30 | * This condition will be signaled if a zookeeper event was processed and the event contains a data/child change. 31 | * 32 | * @return the condition. 33 | */ 34 | public Condition getDataChangedCondition() { 35 | return _dataChangedCondition; 36 | } 37 | 38 | /** 39 | * This condition will be signaled if a zookeeper event was processed and the event contains a state change 40 | * (connected, disconnected, session expired, etc ...). 41 | * 42 | * @return the condition. 43 | */ 44 | public Condition getStateChangedCondition() { 45 | return _stateChangedCondition; 46 | } 47 | 48 | /** 49 | * This condition will be signaled if any znode related zookeeper event was received. 50 | * 51 | * @return the condition. 52 | */ 53 | public Condition getZNodeEventCondition() { 54 | return _zNodeEventCondition; 55 | } 56 | } -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/ZkServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import org.I0Itec.zkclient.exception.ZkException; 19 | import org.I0Itec.zkclient.exception.ZkInterruptedException; 20 | import org.apache.zookeeper.server.NIOServerCnxnFactory; 21 | import org.apache.zookeeper.server.ZooKeeperServer; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import javax.annotation.PostConstruct; 26 | import javax.annotation.PreDestroy; 27 | import java.io.File; 28 | import java.io.IOException; 29 | import java.net.InetSocketAddress; 30 | import java.util.Arrays; 31 | 32 | public class ZkServer { 33 | 34 | //private final static Logger LOG = Logger.getLogger(ZkServer.class); 35 | private final static Logger LOG = LoggerFactory.getLogger(ZkServer.class); 36 | 37 | public static final int DEFAULT_PORT = 2181; 38 | public static final int DEFAULT_TICK_TIME = 5000; 39 | public static final int DEFAULT_MIN_SESSION_TIMEOUT = 2 * DEFAULT_TICK_TIME; 40 | 41 | private String _dataDir; 42 | private String _logDir; 43 | 44 | private IDefaultNameSpace _defaultNameSpace; 45 | 46 | private ZooKeeperServer _zk; 47 | private NIOServerCnxnFactory _nioFactory; 48 | private ZkClient _zkClient; 49 | private int _port; 50 | private int _tickTime; 51 | private int _minSessionTimeout; 52 | 53 | public ZkServer(String dataDir, String logDir, IDefaultNameSpace defaultNameSpace) { 54 | this(dataDir, logDir, defaultNameSpace, DEFAULT_PORT); 55 | } 56 | 57 | public ZkServer(String dataDir, String logDir, IDefaultNameSpace defaultNameSpace, int port) { 58 | this(dataDir, logDir, defaultNameSpace, port, DEFAULT_TICK_TIME); 59 | } 60 | 61 | public ZkServer(String dataDir, String logDir, IDefaultNameSpace defaultNameSpace, int port, int tickTime) { 62 | this(dataDir, logDir, defaultNameSpace, port, tickTime, DEFAULT_MIN_SESSION_TIMEOUT); 63 | } 64 | 65 | public ZkServer(String dataDir, String logDir, IDefaultNameSpace defaultNameSpace, int port, int tickTime, int minSessionTimeout) { 66 | _dataDir = dataDir; 67 | _logDir = logDir; 68 | _defaultNameSpace = defaultNameSpace; 69 | _port = port; 70 | _tickTime = tickTime; 71 | _minSessionTimeout = minSessionTimeout; 72 | } 73 | 74 | public int getPort() { 75 | return _port; 76 | } 77 | 78 | @PostConstruct 79 | public void start() { 80 | final String[] localHostNames = NetworkUtil.getLocalHostNames(); 81 | String names = ""; 82 | for (int i = 0; i < localHostNames.length; i++) { 83 | final String name = localHostNames[i]; 84 | names += " " + name; 85 | if (i + 1 != localHostNames.length) { 86 | names += ","; 87 | } 88 | } 89 | LOG.info("Starting ZkServer on: [" + names + "] port " + _port + "..."); 90 | try { 91 | startZooKeeperServer(); 92 | _zkClient = new ZkClient("localhost:" + _port, 10000); 93 | _defaultNameSpace.createDefaultNameSpace(_zkClient); 94 | } catch (RuntimeException e) { 95 | shutdown(); 96 | throw e; 97 | } 98 | } 99 | 100 | private void startZooKeeperServer() { 101 | final String[] localhostHostNames = NetworkUtil.getLocalHostNames(); 102 | final String servers = "localhost:" + _port; 103 | // check if this server needs to start a _client server. 104 | int pos = -1; 105 | LOG.debug("check if hostNames " + servers + " is in list: " + Arrays.asList(localhostHostNames)); 106 | if ((pos = NetworkUtil.hostNamesInList(servers, localhostHostNames)) != -1) { 107 | // yes this server needs to start a zookeeper server 108 | final String[] hosts = servers.split(","); 109 | final String[] hostSplitted = hosts[pos].split(":"); 110 | int port = _port; 111 | if (hostSplitted.length > 1) { 112 | port = Integer.parseInt(hostSplitted[1]); 113 | } 114 | // check if this machine is already something running.. 115 | if (NetworkUtil.isPortFree(port)) { 116 | final File dataDir = new File(_dataDir); 117 | final File dataLogDir = new File(_logDir); 118 | dataDir.mkdirs(); 119 | dataLogDir.mkdirs(); 120 | 121 | if (hosts.length > 1) { 122 | // multiple zk servers 123 | LOG.info("Start distributed zookeeper server..."); 124 | throw new IllegalArgumentException("Unable to start distributed zookeeper server"); 125 | } 126 | // single zk server 127 | LOG.info("Start single zookeeper server..."); 128 | LOG.info("data dir: " + dataDir.getAbsolutePath()); 129 | LOG.info("data log dir: " + dataLogDir.getAbsolutePath()); 130 | LOG.info("JAAS login file: " + System.getProperty("java.security.auth.login.config", "none")); 131 | startSingleZkServer(_tickTime, dataDir, dataLogDir, port); 132 | } else { 133 | throw new IllegalStateException("Zookeeper port " + port + " was already in use. Running in single machine mode?"); 134 | } 135 | } 136 | } 137 | 138 | private void startSingleZkServer(final int tickTime, final File dataDir, final File dataLogDir, final int port) { 139 | try { 140 | _zk = new ZooKeeperServer(dataDir, dataLogDir, tickTime); 141 | _zk.setMinSessionTimeout(_minSessionTimeout); 142 | _nioFactory = new NIOServerCnxnFactory(); 143 | int maxClientConnections = 0; // 0 means unlimited 144 | _nioFactory.configure(new InetSocketAddress(port), maxClientConnections); 145 | _nioFactory.startup(_zk); 146 | } catch (IOException e) { 147 | throw new ZkException("Unable to start single ZooKeeper server.", e); 148 | } catch (InterruptedException e) { 149 | throw new ZkInterruptedException(e); 150 | } 151 | } 152 | 153 | @PreDestroy 154 | public void shutdown() { 155 | LOG.info("Shutting down ZkServer..."); 156 | try { 157 | if(_zkClient != null) { 158 | _zkClient.close(); 159 | } 160 | } catch (ZkException e) { 161 | LOG.warn("Error on closing zkclient: " + e.getClass().getName()); 162 | } 163 | if (_nioFactory != null) { 164 | _nioFactory.shutdown(); 165 | try { 166 | _nioFactory.join(); 167 | } catch (InterruptedException e) { 168 | Thread.currentThread().interrupt(); 169 | } 170 | _nioFactory = null; 171 | } 172 | if (_zk != null) { 173 | _zk.shutdown(); 174 | _zk = null; 175 | } 176 | LOG.info("Shutting down ZkServer...done"); 177 | } 178 | 179 | public ZkClient getZkClient() { 180 | return _zkClient; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/exception/ZkBadVersionException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient.exception; 17 | 18 | import org.apache.zookeeper.KeeperException; 19 | 20 | public class ZkBadVersionException extends ZkException { 21 | 22 | private static final long serialVersionUID = 1L; 23 | 24 | public ZkBadVersionException() { 25 | super(); 26 | } 27 | 28 | public ZkBadVersionException(KeeperException cause) { 29 | super(cause); 30 | } 31 | 32 | public ZkBadVersionException(String message, KeeperException cause) { 33 | super(message, cause); 34 | } 35 | 36 | public ZkBadVersionException(String message) { 37 | super(message); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/exception/ZkException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient.exception; 17 | 18 | import org.apache.zookeeper.KeeperException; 19 | 20 | public class ZkException extends RuntimeException { 21 | 22 | private static final long serialVersionUID = 1L; 23 | 24 | public ZkException() { 25 | super(); 26 | } 27 | 28 | public ZkException(String message, Throwable cause) { 29 | super(message, cause); 30 | } 31 | 32 | public ZkException(String message) { 33 | super(message); 34 | } 35 | 36 | public ZkException(Throwable cause) { 37 | super(cause); 38 | } 39 | 40 | public static ZkException create(KeeperException e) { 41 | switch (e.code()) { 42 | // case DATAINCONSISTENCY: 43 | // return new DataInconsistencyException(); 44 | // case CONNECTIONLOSS: 45 | // return new ConnectionLossException(); 46 | case NONODE: 47 | return new ZkNoNodeException(e); 48 | // case NOAUTH: 49 | // return new ZkNoAuthException(); 50 | case BADVERSION: 51 | return new ZkBadVersionException(e); 52 | // case NOCHILDRENFOREPHEMERALS: 53 | // return new NoChildrenForEphemeralsException(); 54 | case NODEEXISTS: 55 | return new ZkNodeExistsException(e); 56 | // case INVALIDACL: 57 | // return new ZkInvalidACLException(); 58 | // case AUTHFAILED: 59 | // return new AuthFailedException(); 60 | // case NOTEMPTY: 61 | // return new NotEmptyException(); 62 | // case SESSIONEXPIRED: 63 | // return new SessionExpiredException(); 64 | // case INVALIDCALLBACK: 65 | // return new InvalidCallbackException(); 66 | 67 | default: 68 | return new ZkException(e); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/exception/ZkInterruptedException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient.exception; 17 | 18 | public class ZkInterruptedException extends ZkException { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | public ZkInterruptedException(InterruptedException e) { 23 | super(e); 24 | Thread.currentThread().interrupt(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/exception/ZkMarshallingError.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient.exception; 17 | 18 | public class ZkMarshallingError extends ZkException { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | public ZkMarshallingError() { 23 | super(); 24 | } 25 | 26 | public ZkMarshallingError(Throwable cause) { 27 | super(cause); 28 | } 29 | 30 | public ZkMarshallingError(String message, Throwable cause) { 31 | super(message, cause); 32 | } 33 | 34 | public ZkMarshallingError(String message) { 35 | super(message); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/exception/ZkNoNodeException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient.exception; 17 | 18 | import org.apache.zookeeper.KeeperException; 19 | 20 | public class ZkNoNodeException extends ZkException { 21 | 22 | private static final long serialVersionUID = 1L; 23 | 24 | public ZkNoNodeException() { 25 | super(); 26 | } 27 | 28 | public ZkNoNodeException(KeeperException cause) { 29 | super(cause); 30 | } 31 | 32 | public ZkNoNodeException(String message, KeeperException cause) { 33 | super(message, cause); 34 | } 35 | 36 | public ZkNoNodeException(String message) { 37 | super(message); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/exception/ZkNodeExistsException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient.exception; 17 | 18 | import org.apache.zookeeper.KeeperException; 19 | 20 | public class ZkNodeExistsException extends ZkException { 21 | 22 | private static final long serialVersionUID = 1L; 23 | 24 | public ZkNodeExistsException() { 25 | super(); 26 | } 27 | 28 | public ZkNodeExistsException(KeeperException cause) { 29 | super(cause); 30 | } 31 | 32 | public ZkNodeExistsException(String message, KeeperException cause) { 33 | super(message, cause); 34 | } 35 | 36 | public ZkNodeExistsException(String message) { 37 | super(message); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/exception/ZkTimeoutException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient.exception; 17 | 18 | public class ZkTimeoutException extends ZkException { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | public ZkTimeoutException() { 23 | super(); 24 | } 25 | 26 | public ZkTimeoutException(String message, Throwable cause) { 27 | super(message, cause); 28 | } 29 | 30 | public ZkTimeoutException(String message) { 31 | super(message); 32 | } 33 | 34 | public ZkTimeoutException(Throwable cause) { 35 | super(cause); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/serialize/BytesPushThroughSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient.serialize; 17 | 18 | import org.I0Itec.zkclient.exception.ZkMarshallingError; 19 | 20 | /** 21 | * A {@link ZkSerializer} which simply passes byte arrays to zk and back. 22 | */ 23 | public class BytesPushThroughSerializer implements ZkSerializer { 24 | 25 | @Override 26 | public Object deserialize(byte[] bytes) throws ZkMarshallingError { 27 | return bytes; 28 | } 29 | 30 | @Override 31 | public byte[] serialize(Object bytes) throws ZkMarshallingError { 32 | return (byte[]) bytes; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/serialize/SerializableSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient.serialize; 17 | 18 | import java.io.ByteArrayInputStream; 19 | import java.io.ByteArrayOutputStream; 20 | import java.io.IOException; 21 | import java.io.ObjectInputStream; 22 | import java.io.ObjectOutputStream; 23 | 24 | import org.I0Itec.zkclient.exception.ZkMarshallingError; 25 | 26 | public class SerializableSerializer implements ZkSerializer { 27 | 28 | @Override 29 | public Object deserialize(byte[] bytes) throws ZkMarshallingError { 30 | try { 31 | ObjectInputStream inputStream = new TcclAwareObjectIputStream(new ByteArrayInputStream(bytes)); 32 | Object object = inputStream.readObject(); 33 | return object; 34 | } catch (ClassNotFoundException e) { 35 | throw new ZkMarshallingError("Unable to find object class.", e); 36 | } catch (IOException e) { 37 | throw new ZkMarshallingError(e); 38 | } 39 | } 40 | 41 | @Override 42 | public byte[] serialize(Object serializable) throws ZkMarshallingError { 43 | try { 44 | ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream(); 45 | ObjectOutputStream stream = new ObjectOutputStream(byteArrayOS); 46 | stream.writeObject(serializable); 47 | stream.close(); 48 | return byteArrayOS.toByteArray(); 49 | } catch (IOException e) { 50 | throw new ZkMarshallingError(e); 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/serialize/TcclAwareObjectIputStream.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient.serialize; 17 | 18 | import java.io.IOException; 19 | import java.io.InputStream; 20 | import java.io.ObjectInputStream; 21 | import java.io.ObjectStreamClass; 22 | import java.lang.reflect.Proxy; 23 | 24 | /** 25 | * An ObjectInputStream that is aware of the TCCL. 26 | */ 27 | public class TcclAwareObjectIputStream extends ObjectInputStream { 28 | 29 | public TcclAwareObjectIputStream(InputStream in) throws IOException { 30 | super(in); 31 | } 32 | 33 | /** 34 | * Load the local class equivalent of the specified stream class 35 | * description. 36 | * Uses the current class {@link ClassLoader} and falls back to the {@link Thread} context {@link ClassLoader}. 37 | */ 38 | protected Class resolveClass(ObjectStreamClass classDesc) throws IOException, ClassNotFoundException { 39 | try { 40 | return getClass().getClassLoader().loadClass(classDesc.getName()); 41 | } catch (ClassNotFoundException ex) { 42 | ClassLoader tccl = Thread.currentThread().getContextClassLoader(); 43 | if (tccl != null) { 44 | return tccl.loadClass(classDesc.getName()); 45 | } else { 46 | throw ex; 47 | } 48 | } 49 | } 50 | 51 | /** 52 | * Returns a proxy class that implements the interfaces named in a proxy 53 | * class descriptor; subclasses may implement this method to read custom 54 | * data from the stream along with the descriptors for dynamic proxy 55 | * classes, allowing them to use an alternate loading mechanism for the 56 | * interfaces and the proxy class. 57 | * 58 | * For each interface uses the current class {@link ClassLoader} and falls back to the {@link Thread} context {@link ClassLoader}. 59 | */ 60 | protected Class resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { 61 | ClassLoader cl = getClass().getClassLoader(); 62 | Class[] cinterfaces = new Class[interfaces.length]; 63 | 64 | for (int i = 0; i < interfaces.length; i++) { 65 | try { 66 | cinterfaces[i] = cl.loadClass(interfaces[i]); 67 | } catch (ClassNotFoundException ex) { 68 | ClassLoader tccl = Thread.currentThread().getContextClassLoader(); 69 | if (tccl != null) { 70 | return tccl.loadClass(interfaces[i]); 71 | } else { 72 | throw ex; 73 | } 74 | } 75 | } 76 | try { 77 | return Proxy.getProxyClass(cinterfaces[0].getClassLoader(), cinterfaces); 78 | } catch (IllegalArgumentException e) { 79 | throw new ClassNotFoundException(null, e); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/serialize/ZkSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient.serialize; 17 | 18 | import org.I0Itec.zkclient.exception.ZkMarshallingError; 19 | 20 | /** 21 | * Zookeeper is able to store data in form of byte arrays. This interfacte is a bridge between those byte-array format 22 | * and higher level objects. 23 | * 24 | * @see BytesPushThroughSerializer 25 | * @see SerializableSerializer 26 | */ 27 | public interface ZkSerializer { 28 | 29 | public byte[] serialize(Object data) throws ZkMarshallingError; 30 | 31 | public Object deserialize(byte[] bytes) throws ZkMarshallingError; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/I0Itec/zkclient/util/ZkPathUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient.util; 17 | 18 | import java.util.List; 19 | 20 | import org.I0Itec.zkclient.ZkClient; 21 | 22 | public class ZkPathUtil { 23 | 24 | public static String leadingZeros(long number, int numberOfLeadingZeros) { 25 | return String.format("%0" + numberOfLeadingZeros + "d", number); 26 | } 27 | 28 | public static String toString(ZkClient zkClient) { 29 | return toString(zkClient, "/", PathFilter.ALL); 30 | } 31 | 32 | public static String toString(ZkClient zkClient, String startPath, PathFilter pathFilter) { 33 | final int level = 1; 34 | final StringBuilder builder = new StringBuilder("+ (" + startPath + ")"); 35 | builder.append("\n"); 36 | addChildrenToStringBuilder(zkClient, pathFilter, level, builder, startPath); 37 | return builder.toString(); 38 | } 39 | 40 | private static void addChildrenToStringBuilder(ZkClient zkClient, PathFilter pathFilter, final int level, final StringBuilder builder, final String startPath) { 41 | final List children = zkClient.getChildren(startPath); 42 | for (final String node : children) { 43 | String nestedPath; 44 | if (startPath.endsWith("/")) { 45 | nestedPath = startPath + node; 46 | } else { 47 | nestedPath = startPath + "/" + node; 48 | } 49 | if (pathFilter.showChilds(nestedPath)) { 50 | builder.append(getSpaces(level - 1) + "'-" + "+" + node + "\n"); 51 | addChildrenToStringBuilder(zkClient, pathFilter, level + 1, builder, nestedPath); 52 | } else { 53 | builder.append(getSpaces(level - 1) + "'-" + "-" + node + " (contents hidden)\n"); 54 | } 55 | } 56 | } 57 | 58 | private static String getSpaces(final int level) { 59 | String s = ""; 60 | for (int i = 0; i < level; i++) { 61 | s += " "; 62 | } 63 | return s; 64 | } 65 | 66 | public static interface PathFilter { 67 | 68 | public static PathFilter ALL = new PathFilter() { 69 | 70 | @Override 71 | public boolean showChilds(String path) { 72 | return true; 73 | } 74 | }; 75 | 76 | boolean showChilds(String path); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/AbstractAuthTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.I0Itec.zkclient; 19 | 20 | import org.I0Itec.zkclient.exception.ZkException; 21 | import org.apache.zookeeper.CreateMode; 22 | import org.apache.zookeeper.KeeperException; 23 | import org.apache.zookeeper.ZooDefs; 24 | import org.apache.zookeeper.data.ACL; 25 | import org.apache.zookeeper.data.Id; 26 | import org.junit.After; 27 | import org.junit.Before; 28 | import org.junit.Test; 29 | import org.slf4j.Logger; 30 | import org.slf4j.LoggerFactory; 31 | 32 | import java.util.ArrayList; 33 | import java.util.List; 34 | 35 | import static org.junit.Assert.fail; 36 | 37 | public abstract class AbstractAuthTest { 38 | protected ZkClient _client; 39 | protected ZkServer _zkServer; 40 | //protected static final Logger LOG = Logger.getLogger(AbstractAuthTest.class); 41 | protected static final Logger LOG = LoggerFactory.getLogger(AbstractAuthTest.class); 42 | 43 | @Before 44 | public void setUp() throws Exception { 45 | LOG.info("------------ BEFORE -------------"); 46 | 47 | } 48 | 49 | @After 50 | public void tearDown() throws Exception { 51 | LOG.info("------------ AFTER -------------"); 52 | } 53 | 54 | @Test 55 | public void testBadAuth() { 56 | try { 57 | List acl = new ArrayList(); 58 | acl.add(new ACL(ZooDefs.Perms.ALL, new Id("digest", "pat:pass"))); 59 | _client.create("/path1", null, acl, CreateMode.EPHEMERAL); 60 | _client.addAuthInfo("digest", "pat:pass2".getBytes()); 61 | _client.readData("/path1"); 62 | fail("Should get auth error"); 63 | } catch (ZkException e) { 64 | if (e.getCause() instanceof KeeperException && ((KeeperException) e.getCause()).code() == KeeperException.Code.NOAUTH) { 65 | // do nothing, this is expected 66 | } else { 67 | fail("wrong exception"); 68 | } 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/AbstractBaseZkClientTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import org.I0Itec.zkclient.exception.ZkTimeoutException; 19 | import org.junit.After; 20 | import org.junit.Assert; 21 | import org.junit.Before; 22 | import org.junit.Test; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | import java.util.List; 27 | import java.util.concurrent.Callable; 28 | import java.util.concurrent.TimeUnit; 29 | import java.util.concurrent.atomic.AtomicInteger; 30 | 31 | import static org.junit.Assert.*; 32 | import static org.mockito.Mockito.mock; 33 | 34 | //import org.apache.log4j.Logger; 35 | 36 | public abstract class AbstractBaseZkClientTest { 37 | 38 | //protected static final Logger LOG = Logger.getLogger(AbstractBaseZkClientTest.class); 39 | protected static final Logger LOG = LoggerFactory.getLogger(AbstractBaseZkClientTest.class); 40 | protected ZkServer _zkServer; 41 | protected ZkClient _client; 42 | 43 | @Before 44 | public void setUp() throws Exception { 45 | LOG.info("------------ BEFORE -------------"); 46 | 47 | } 48 | 49 | @After 50 | public void tearDown() throws Exception { 51 | LOG.info("------------ AFTER -------------"); 52 | } 53 | 54 | @Test(expected = ZkTimeoutException.class, timeout = 15000) 55 | public void testUnableToConnect() throws Exception { 56 | LOG.info("--- testUnableToConnect"); 57 | // we are using port 4711 to avoid conflicts with the zk server that is 58 | // started by the Spring context 59 | new ZkClient("localhost:4712", 5000); 60 | } 61 | 62 | @Test 63 | public void testWriteAndRead() throws Exception { 64 | LOG.info("--- testWriteAndRead"); 65 | String data = "something"; 66 | String path = "/a"; 67 | _client.createPersistent(path, data); 68 | String data2 = _client.readData(path); 69 | Assert.assertEquals(data, data2); 70 | _client.delete(path); 71 | } 72 | 73 | @Test 74 | public void testDelete() throws Exception { 75 | LOG.info("--- testDelete"); 76 | String path = "/a"; 77 | assertFalse(_client.delete(path)); 78 | _client.createPersistent(path, null); 79 | assertTrue(_client.delete(path)); 80 | assertFalse(_client.delete(path)); 81 | } 82 | 83 | @Test 84 | public void testDeleteRecursive() throws Exception { 85 | LOG.info("--- testDeleteRecursive"); 86 | 87 | // should be able to call this on a not existing directory 88 | _client.deleteRecursive("/doesNotExist"); 89 | } 90 | 91 | @Test 92 | public void testWaitUntilExists() { 93 | LOG.info("--- testWaitUntilExists"); 94 | // create /gaga node asynchronously 95 | new Thread() { 96 | @Override 97 | public void run() { 98 | try { 99 | Thread.sleep(100); 100 | _client.createPersistent("/gaga"); 101 | } catch (Exception e) { 102 | // ignore 103 | } 104 | } 105 | }.start(); 106 | 107 | // wait until this was created 108 | assertTrue(_client.waitUntilExists("/gaga", TimeUnit.SECONDS, 5)); 109 | assertTrue(_client.exists("/gaga")); 110 | 111 | // waiting for /neverCreated should timeout 112 | assertFalse(_client.waitUntilExists("/neverCreated", TimeUnit.MILLISECONDS, 100)); 113 | } 114 | 115 | @Test 116 | public void testDataChanges1() throws Exception { 117 | LOG.info("--- testDataChanges1"); 118 | String path = "/a"; 119 | final Holder holder = new Holder(); 120 | 121 | IZkDataListener listener = new IZkDataListener() { 122 | 123 | @Override 124 | public void handleDataChange(String dataPath, Object data) throws Exception { 125 | holder.set((String) data); 126 | } 127 | 128 | @Override 129 | public void handleDataDeleted(String dataPath) throws Exception { 130 | holder.set(null); 131 | } 132 | }; 133 | _client.subscribeDataChanges(path, listener); 134 | _client.createPersistent(path, "aaa"); 135 | 136 | // wait some time to make sure the event was triggered 137 | String contentFromHolder = TestUtil.waitUntil("b", new Callable() { 138 | 139 | @Override 140 | public String call() throws Exception { 141 | return holder.get(); 142 | } 143 | }, TimeUnit.SECONDS, 5); 144 | 145 | assertEquals("aaa", contentFromHolder); 146 | } 147 | 148 | @Test 149 | public void testDataChanges2() throws Exception { 150 | LOG.info("--- testDataChanges2"); 151 | String path = "/a"; 152 | final AtomicInteger countChanged = new AtomicInteger(0); 153 | final AtomicInteger countDeleted = new AtomicInteger(0); 154 | 155 | IZkDataListener listener = new IZkDataListener() { 156 | 157 | @Override 158 | public void handleDataChange(String dataPath, Object data) throws Exception { 159 | countChanged.incrementAndGet(); 160 | } 161 | 162 | @Override 163 | public void handleDataDeleted(String dataPath) throws Exception { 164 | countDeleted.incrementAndGet(); 165 | } 166 | }; 167 | _client.subscribeDataChanges(path, listener); 168 | 169 | // create node 170 | _client.createPersistent(path, "aaa"); 171 | 172 | // wait some time to make sure the event was triggered 173 | TestUtil.waitUntil(1, new Callable() { 174 | 175 | @Override 176 | public Integer call() throws Exception { 177 | return countChanged.get(); 178 | } 179 | }, TimeUnit.SECONDS, 5); 180 | assertEquals(1, countChanged.get()); 181 | assertEquals(0, countDeleted.get()); 182 | 183 | countChanged.set(0); 184 | countDeleted.set(0); 185 | // delete node, this should trigger a delete event 186 | _client.delete(path); 187 | // wait some time to make sure the event was triggered 188 | TestUtil.waitUntil(1, new Callable() { 189 | 190 | @Override 191 | public Integer call() throws Exception { 192 | return countDeleted.get(); 193 | } 194 | }, TimeUnit.SECONDS, 5); 195 | assertEquals(0, countChanged.get()); 196 | assertEquals(1, countDeleted.get()); 197 | 198 | // test if watch was reinstalled after the file got deleted 199 | countChanged.set(0); 200 | _client.createPersistent(path, "aaa"); 201 | 202 | // wait some time to make sure the event was triggered 203 | TestUtil.waitUntil(1, new Callable() { 204 | 205 | @Override 206 | public Integer call() throws Exception { 207 | return countChanged.get(); 208 | } 209 | }, TimeUnit.SECONDS, 5); 210 | assertEquals(1, countChanged.get()); 211 | 212 | // test if changing the contents notifies the listener 213 | _client.writeData(path, "bbb"); 214 | 215 | // wait some time to make sure the event was triggered 216 | TestUtil.waitUntil(2, new Callable() { 217 | 218 | @Override 219 | public Integer call() throws Exception { 220 | return countChanged.get(); 221 | } 222 | }, TimeUnit.SECONDS, 5); 223 | assertEquals(2, countChanged.get()); 224 | } 225 | 226 | @Test(timeout = 15000) 227 | public void testHandleChildChanges() throws Exception { 228 | LOG.info("--- testHandleChildChanges"); 229 | String path = "/a"; 230 | final AtomicInteger count = new AtomicInteger(0); 231 | final Holder> children = new Holder>(); 232 | 233 | IZkChildListener listener = new IZkChildListener() { 234 | 235 | @Override 236 | public void handleChildChange(String parentPath, List currentChilds) throws Exception { 237 | count.incrementAndGet(); 238 | children.set(currentChilds); 239 | } 240 | }; 241 | _client.subscribeChildChanges(path, listener); 242 | 243 | // ---- 244 | // Create the root node should throw the first child change event 245 | // ---- 246 | _client.createPersistent(path); 247 | 248 | // wait some time to make sure the event was triggered 249 | TestUtil.waitUntil(1, new Callable() { 250 | 251 | @Override 252 | public Integer call() throws Exception { 253 | return count.get(); 254 | } 255 | }, TimeUnit.SECONDS, 5); 256 | assertEquals(1, count.get()); 257 | assertEquals(0, children.get().size()); 258 | 259 | // ---- 260 | // Creating a child node should throw another event 261 | // ---- 262 | count.set(0); 263 | _client.createPersistent(path + "/child1"); 264 | 265 | // wait some time to make sure the event was triggered 266 | TestUtil.waitUntil(1, new Callable() { 267 | 268 | @Override 269 | public Integer call() throws Exception { 270 | return count.get(); 271 | } 272 | }, TimeUnit.SECONDS, 5); 273 | assertEquals(1, count.get()); 274 | assertEquals(1, children.get().size()); 275 | assertEquals("child1", children.get().get(0)); 276 | 277 | // ---- 278 | // Creating another child and deleting the node should also throw an event 279 | // ---- 280 | count.set(0); 281 | _client.createPersistent(path + "/child2"); 282 | _client.deleteRecursive(path); 283 | 284 | // wait some time to make sure the event was triggered 285 | Boolean eventReceived = TestUtil.waitUntil(true, new Callable() { 286 | 287 | @Override 288 | public Boolean call() throws Exception { 289 | return count.get() > 0 && children.get() == null; 290 | } 291 | }, TimeUnit.SECONDS, 5); 292 | assertTrue(eventReceived); 293 | assertNull(children.get()); 294 | 295 | // ---- 296 | // Creating root again should throw an event 297 | // ---- 298 | count.set(0); 299 | _client.createPersistent(path); 300 | 301 | // wait some time to make sure the event was triggered 302 | eventReceived = TestUtil.waitUntil(true, new Callable() { 303 | 304 | @Override 305 | public Boolean call() throws Exception { 306 | return count.get() > 0 && children.get() != null; 307 | } 308 | }, TimeUnit.SECONDS, 5); 309 | assertTrue(eventReceived); 310 | assertEquals(0, children.get().size()); 311 | 312 | // ---- 313 | // Creating child now should throw an event 314 | // ---- 315 | count.set(0); 316 | _client.createPersistent(path + "/child"); 317 | 318 | // wait some time to make sure the event was triggered 319 | eventReceived = TestUtil.waitUntil(true, new Callable() { 320 | 321 | @Override 322 | public Boolean call() throws Exception { 323 | return count.get() > 0; 324 | } 325 | }, TimeUnit.SECONDS, 5); 326 | assertTrue(eventReceived); 327 | assertEquals(1, children.get().size()); 328 | assertEquals("child", children.get().get(0)); 329 | 330 | // ---- 331 | // Deleting root node should throw an event 332 | // ---- 333 | count.set(0); 334 | _client.deleteRecursive(path); 335 | 336 | // wait some time to make sure the event was triggered 337 | eventReceived = TestUtil.waitUntil(true, new Callable() { 338 | 339 | @Override 340 | public Boolean call() throws Exception { 341 | return count.get() > 0 && children.get() == null; 342 | } 343 | }, TimeUnit.SECONDS, 5); 344 | assertTrue(eventReceived); 345 | assertNull(children.get()); 346 | } 347 | 348 | @Test 349 | public void testGetCreationTime() throws Exception { 350 | long start = System.currentTimeMillis(); 351 | Thread.sleep(100); 352 | String path = "/a"; 353 | _client.createPersistent(path); 354 | Thread.sleep(100); 355 | long end = System.currentTimeMillis(); 356 | long creationTime = _client.getCreationTime(path); 357 | assertTrue(start < creationTime && end > creationTime); 358 | } 359 | 360 | @Test 361 | public void testNumberOfListeners() { 362 | IZkChildListener zkChildListener = mock(IZkChildListener.class); 363 | _client.subscribeChildChanges("/", zkChildListener); 364 | assertEquals(1, _client.numberOfListeners()); 365 | 366 | IZkDataListener zkDataListener = mock(IZkDataListener.class); 367 | _client.subscribeDataChanges("/a", zkDataListener); 368 | assertEquals(2, _client.numberOfListeners()); 369 | 370 | _client.subscribeDataChanges("/b", zkDataListener); 371 | assertEquals(3, _client.numberOfListeners()); 372 | 373 | IZkStateListener zkStateListener = mock(IZkStateListener.class); 374 | _client.subscribeStateChanges(zkStateListener); 375 | assertEquals(4, _client.numberOfListeners()); 376 | 377 | _client.unsubscribeChildChanges("/", zkChildListener); 378 | assertEquals(3, _client.numberOfListeners()); 379 | 380 | _client.unsubscribeDataChanges("/b", zkDataListener); 381 | assertEquals(2, _client.numberOfListeners()); 382 | 383 | _client.unsubscribeDataChanges("/a", zkDataListener); 384 | assertEquals(1, _client.numberOfListeners()); 385 | 386 | _client.unsubscribeStateChanges(zkStateListener); 387 | assertEquals(0, _client.numberOfListeners()); 388 | } 389 | } 390 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/AbstractConnectionTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import java.util.List; 19 | 20 | import org.I0Itec.zkclient.util.ZkPathUtil; 21 | import org.apache.zookeeper.CreateMode; 22 | import org.apache.zookeeper.KeeperException; 23 | import org.junit.Test; 24 | 25 | import static org.junit.Assert.assertEquals; 26 | 27 | public abstract class AbstractConnectionTest { 28 | 29 | private final IZkConnection _connection; 30 | 31 | public AbstractConnectionTest(IZkConnection connection) { 32 | _connection = connection; 33 | } 34 | 35 | @Test 36 | public void testGetChildren_OnEmptyFileSystem() throws KeeperException, InterruptedException { 37 | InMemoryConnection connection = new InMemoryConnection(); 38 | List children = connection.getChildren("/", false); 39 | assertEquals(0, children.size()); 40 | } 41 | 42 | @Test 43 | public void testSequentials() throws KeeperException, InterruptedException { 44 | String sequentialPath = _connection.create("/a", new byte[0], CreateMode.EPHEMERAL_SEQUENTIAL); 45 | int firstSequential = Integer.parseInt(sequentialPath.substring(2)); 46 | assertEquals("/a" + ZkPathUtil.leadingZeros(firstSequential++, 10), sequentialPath); 47 | assertEquals("/a" + ZkPathUtil.leadingZeros(firstSequential++, 10), _connection.create("/a", new byte[0], CreateMode.EPHEMERAL_SEQUENTIAL)); 48 | assertEquals("/a" + ZkPathUtil.leadingZeros(firstSequential++, 10), _connection.create("/a", new byte[0], CreateMode.PERSISTENT_SEQUENTIAL)); 49 | assertEquals("/b" + ZkPathUtil.leadingZeros(firstSequential++, 10), _connection.create("/b", new byte[0], CreateMode.EPHEMERAL_SEQUENTIAL)); 50 | assertEquals("/b" + ZkPathUtil.leadingZeros(firstSequential++, 10), _connection.create("/b", new byte[0], CreateMode.PERSISTENT_SEQUENTIAL)); 51 | assertEquals("/a" + ZkPathUtil.leadingZeros(firstSequential++, 10), _connection.create("/a", new byte[0], CreateMode.EPHEMERAL_SEQUENTIAL)); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/ContentWatcherTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import org.junit.After; 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import java.util.concurrent.Callable; 25 | import java.util.concurrent.TimeUnit; 26 | 27 | import static org.junit.Assert.assertEquals; 28 | 29 | //import org.apache.log4j.Logger; 30 | 31 | public class ContentWatcherTest { 32 | 33 | private static final Logger LOG = LoggerFactory.getLogger(ContentWatcherTest.class); 34 | 35 | 36 | private static final String FILE_NAME = "/ContentWatcherTest"; 37 | private ZkServer _zkServer; 38 | private ZkClient _zkClient; 39 | 40 | @Before 41 | public void setUp() throws Exception { 42 | LOG.info("------------ BEFORE -------------"); 43 | _zkServer = TestUtil.startZkServer("ContentWatcherTest", 4711); 44 | _zkClient = _zkServer.getZkClient(); 45 | } 46 | 47 | @After 48 | public void tearDown() throws Exception { 49 | if (_zkServer != null) { 50 | _zkServer.shutdown(); 51 | } 52 | LOG.info("------------ AFTER -------------"); 53 | } 54 | 55 | @Test 56 | public void testGetContent() throws Exception { 57 | LOG.info("--- testGetContent"); 58 | _zkClient.createPersistent(FILE_NAME, "a"); 59 | final ContentWatcher watcher = new ContentWatcher(_zkClient, FILE_NAME); 60 | watcher.start(); 61 | assertEquals("a", watcher.getContent()); 62 | 63 | // update the content 64 | _zkClient.writeData(FILE_NAME, "b"); 65 | 66 | String contentFromWatcher = TestUtil.waitUntil("b", new Callable() { 67 | 68 | @Override 69 | public String call() throws Exception { 70 | return watcher.getContent(); 71 | } 72 | }, TimeUnit.SECONDS, 5); 73 | 74 | assertEquals("b", contentFromWatcher); 75 | watcher.stop(); 76 | } 77 | 78 | @Test 79 | public void testGetContentWaitTillCreated() throws InterruptedException { 80 | LOG.info("--- testGetContentWaitTillCreated"); 81 | final Holder contentHolder = new Holder(); 82 | 83 | Thread thread = new Thread() { 84 | @Override 85 | public void run() { 86 | ContentWatcher watcher = new ContentWatcher(_zkClient, FILE_NAME); 87 | try { 88 | watcher.start(); 89 | contentHolder.set(watcher.getContent()); 90 | watcher.stop(); 91 | } catch (Exception e) { 92 | e.printStackTrace(); 93 | } 94 | } 95 | }; 96 | 97 | thread.start(); 98 | 99 | // create content after 200ms 100 | Thread.sleep(200); 101 | _zkClient.createPersistent(FILE_NAME, "aaa"); 102 | 103 | // we give the thread some time to pick up the change 104 | thread.join(1000); 105 | assertEquals("aaa", contentHolder.get()); 106 | } 107 | 108 | @Test 109 | public void testHandlingNullContent() throws InterruptedException { 110 | LOG.info("--- testHandlingNullContent"); 111 | _zkClient.createPersistent(FILE_NAME, null); 112 | ContentWatcher watcher = new ContentWatcher(_zkClient, FILE_NAME); 113 | watcher.start(); 114 | assertEquals(null, watcher.getContent()); 115 | watcher.stop(); 116 | } 117 | 118 | @Test(timeout = 20000) 119 | public void testHandlingOfConnectionLoss() throws Exception { 120 | LOG.info("--- testHandlingOfConnectionLoss"); 121 | final Gateway gateway = new Gateway(4712, 4711); 122 | gateway.start(); 123 | final ZkClient zkClient = new ZkClient("localhost:4712", 30000); 124 | 125 | // disconnect 126 | gateway.stop(); 127 | 128 | // reconnect after 250ms and create file with content 129 | new Thread() { 130 | @Override 131 | public void run() { 132 | try { 133 | Thread.sleep(250); 134 | gateway.start(); 135 | zkClient.createPersistent(FILE_NAME, "aaa"); 136 | zkClient.writeData(FILE_NAME, "b"); 137 | } catch (Exception e) { 138 | // ignore 139 | } 140 | } 141 | }.start(); 142 | 143 | final ContentWatcher watcher = new ContentWatcher(zkClient, FILE_NAME); 144 | watcher.start(); 145 | 146 | TestUtil.waitUntil("b", new Callable() { 147 | 148 | @Override 149 | public String call() throws Exception { 150 | return watcher.getContent(); 151 | } 152 | }, TimeUnit.SECONDS, 5); 153 | assertEquals("b", watcher.getContent()); 154 | 155 | watcher.stop(); 156 | zkClient.close(); 157 | gateway.stop(); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/DeferredGatewayStarter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | public class DeferredGatewayStarter extends Thread { 19 | 20 | private final Gateway _zkServer; 21 | private int _delay; 22 | 23 | public DeferredGatewayStarter(Gateway gateway, int delay) { 24 | _zkServer = gateway; 25 | _delay = delay; 26 | } 27 | 28 | @Override 29 | public void run() { 30 | try { 31 | Thread.sleep(_delay); 32 | _zkServer.start(); 33 | } catch (Exception e) { 34 | // ignore 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/DistributedQueueTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import static org.junit.Assert.assertEquals; 19 | import static org.junit.Assert.assertNull; 20 | 21 | import java.io.IOException; 22 | import java.util.ArrayList; 23 | import java.util.Collections; 24 | import java.util.HashSet; 25 | import java.util.List; 26 | import java.util.Set; 27 | import java.util.Vector; 28 | 29 | import org.junit.After; 30 | import org.junit.Before; 31 | import org.junit.Test; 32 | 33 | public class DistributedQueueTest { 34 | 35 | private ZkServer _zkServer; 36 | private ZkClient _zkClient; 37 | 38 | @Before 39 | public void setUp() throws IOException { 40 | _zkServer = TestUtil.startZkServer("ZkClientTest-testDistributedQueue", 4711); 41 | _zkClient = _zkServer.getZkClient(); 42 | } 43 | 44 | @After 45 | public void tearDown() { 46 | if (_zkServer != null) { 47 | _zkServer.shutdown(); 48 | } 49 | } 50 | 51 | @Test(timeout = 15000) 52 | public void testDistributedQueue() { 53 | _zkClient.createPersistent("/queue"); 54 | 55 | DistributedQueue distributedQueue = new DistributedQueue(_zkClient, "/queue"); 56 | distributedQueue.offer(17L); 57 | distributedQueue.offer(18L); 58 | distributedQueue.offer(19L); 59 | 60 | assertEquals(Long.valueOf(17L), distributedQueue.poll()); 61 | assertEquals(Long.valueOf(18L), distributedQueue.poll()); 62 | assertEquals(Long.valueOf(19L), distributedQueue.poll()); 63 | assertNull(distributedQueue.poll()); 64 | } 65 | 66 | @Test(timeout = 15000) 67 | public void testPeek() { 68 | _zkClient.createPersistent("/queue"); 69 | 70 | DistributedQueue distributedQueue = new DistributedQueue(_zkClient, "/queue"); 71 | distributedQueue.offer(17L); 72 | distributedQueue.offer(18L); 73 | 74 | assertEquals(Long.valueOf(17L), distributedQueue.peek()); 75 | assertEquals(Long.valueOf(17L), distributedQueue.peek()); 76 | assertEquals(Long.valueOf(17L), distributedQueue.poll()); 77 | assertEquals(Long.valueOf(18L), distributedQueue.peek()); 78 | assertEquals(Long.valueOf(18L), distributedQueue.poll()); 79 | assertNull(distributedQueue.peek()); 80 | } 81 | 82 | @Test(timeout = 30000) 83 | public void testMultipleReadingThreads() throws InterruptedException { 84 | _zkClient.createPersistent("/queue"); 85 | 86 | final DistributedQueue distributedQueue = new DistributedQueue(_zkClient, "/queue"); 87 | 88 | // insert 100 elements 89 | for (int i = 0; i < 100; i++) { 90 | distributedQueue.offer(new Long(i)); 91 | } 92 | 93 | // 3 reading threads 94 | final Set readElements = Collections.synchronizedSet(new HashSet()); 95 | List threads = new ArrayList(); 96 | final List exceptions = new Vector(); 97 | 98 | for (int i = 0; i < 3; i++) { 99 | Thread thread = new Thread() { 100 | @Override 101 | public void run() { 102 | try { 103 | while (true) { 104 | Long value = distributedQueue.poll(); 105 | if (value == null) { 106 | return; 107 | } 108 | readElements.add(value); 109 | } 110 | } catch (Exception e) { 111 | exceptions.add(e); 112 | e.printStackTrace(); 113 | } 114 | } 115 | }; 116 | threads.add(thread); 117 | thread.start(); 118 | } 119 | 120 | for (Thread thread : threads) { 121 | thread.join(); 122 | } 123 | 124 | assertEquals(0, exceptions.size()); 125 | assertEquals(100, readElements.size()); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/InMemoryAuthTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.I0Itec.zkclient; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | import org.apache.zookeeper.CreateMode; 24 | import org.apache.zookeeper.ZooDefs; 25 | import org.apache.zookeeper.data.ACL; 26 | import org.apache.zookeeper.data.Id; 27 | import org.junit.Test; 28 | 29 | public class InMemoryAuthTest extends AbstractAuthTest { 30 | 31 | @Override 32 | public void setUp() throws Exception { 33 | super.setUp(); 34 | _client = new ZkClient(new InMemoryConnection()); 35 | } 36 | 37 | @Override 38 | public void tearDown() throws Exception { 39 | super.tearDown(); 40 | _client.close(); 41 | } 42 | 43 | @Test 44 | public void testAuthorized() { 45 | List acl = new ArrayList(); 46 | acl.add(new ACL(ZooDefs.Perms.ALL, new Id("digest", "pat:pass"))); 47 | _client.addAuthInfo("digest", "pat:pass".getBytes()); 48 | _client.create("/path1", null, acl, CreateMode.PERSISTENT); 49 | _client.readData("/path1"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/InMemoryConnectionTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | 19 | public class InMemoryConnectionTest extends AbstractConnectionTest { 20 | 21 | public InMemoryConnectionTest() { 22 | super(new InMemoryConnection()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/MemoryZkClientTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import org.apache.zookeeper.CreateMode; 19 | import org.junit.Assert; 20 | import org.junit.Test; 21 | 22 | public class MemoryZkClientTest extends AbstractBaseZkClientTest { 23 | 24 | @Override 25 | public void setUp() throws Exception { 26 | super.setUp(); 27 | _client = new ZkClient(new InMemoryConnection()); 28 | } 29 | 30 | @Override 31 | public void tearDown() throws Exception { 32 | super.tearDown(); 33 | _client.close(); 34 | } 35 | 36 | @Test 37 | public void testGetChildren() throws Exception { 38 | String path1 = "/a"; 39 | String path2 = "/a/a"; 40 | String path3 = "/a/a/a"; 41 | 42 | _client.create(path1, null, CreateMode.PERSISTENT); 43 | _client.create(path2, null, CreateMode.PERSISTENT); 44 | _client.create(path3, null, CreateMode.PERSISTENT); 45 | Assert.assertEquals(1, _client.getChildren(path1).size()); 46 | Assert.assertEquals(1, _client.getChildren(path2).size()); 47 | Assert.assertEquals(0, _client.getChildren(path3).size()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/SaslAuthenticatedTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package org.I0Itec.zkclient; 20 | 21 | import org.I0Itec.zkclient.exception.ZkException; 22 | import org.I0Itec.zkclient.exception.ZkTimeoutException; 23 | import org.apache.zookeeper.ZooDefs.Ids; 24 | import org.junit.After; 25 | import org.junit.Before; 26 | import org.junit.Rule; 27 | import org.junit.Test; 28 | import org.junit.rules.TemporaryFolder; 29 | import org.slf4j.Logger; 30 | import org.slf4j.LoggerFactory; 31 | 32 | import javax.security.auth.login.Configuration; 33 | import java.io.File; 34 | import java.io.FileOutputStream; 35 | import java.io.IOException; 36 | 37 | import static org.assertj.core.api.Assertions.assertThat; 38 | import static org.junit.Assert.fail; 39 | 40 | public class SaslAuthenticatedTest { 41 | protected static final Logger LOG = LoggerFactory.getLogger(SaslAuthenticatedTest.class); 42 | static final String ZK_AUTH_PROVIDER = "zookeeper.authProvider.1"; 43 | static final String ZK_ALLOW_FAILED_SASL = "zookeeper.allowSaslFailedClients"; 44 | 45 | @Rule 46 | public TemporaryFolder _temporaryFolder = new TemporaryFolder(); 47 | private int _port = 4700; 48 | private ZkClient _client; 49 | private ZkServer _zkServer; 50 | private String _zkServerContextName = "Server"; 51 | private String _zkClientContextName = "Client"; 52 | private String _userSuperPasswd = "adminpasswd"; 53 | private String _userServerSide = "fpj"; 54 | private String _userClientSide = "fpj"; 55 | private String _userServerSidePasswd = "fpjsecret"; 56 | private String _userClientSidePasswd = "fpjsecret"; 57 | private String _zkModule = "org.apache.zookeeper.server.auth.DigestLoginModule"; 58 | 59 | private String createJaasFile() throws IOException { 60 | File jaasFile = _temporaryFolder.newFile("jaas.conf"); 61 | FileOutputStream jaasOutputStream = new java.io.FileOutputStream(jaasFile); 62 | jaasOutputStream.write(String.format("%s {\n\t%s required\n", _zkServerContextName, _zkModule).getBytes()); 63 | jaasOutputStream.write(String.format("\tuser_super=\"%s\"\n", _userSuperPasswd).getBytes()); 64 | jaasOutputStream.write(String.format("\tuser_%s=\"%s\";\n};\n\n", _userServerSide, _userServerSidePasswd).getBytes()); 65 | jaasOutputStream.write(String.format("%s {\n\t%s required\n", _zkClientContextName, _zkModule).getBytes()); 66 | jaasOutputStream.write(String.format("\tusername=\"%s\"\n", _userClientSide).getBytes()); 67 | jaasOutputStream.write(String.format("\tpassword=\"%s\";\n};", _userClientSidePasswd).getBytes()); 68 | jaasOutputStream.close(); 69 | return jaasFile.getAbsolutePath(); 70 | } 71 | 72 | @Before 73 | public void setUp() throws IOException { 74 | // Reset all variables used for the jaas login file 75 | _zkServerContextName = "Server"; 76 | _zkClientContextName = "Client"; 77 | _userSuperPasswd = "adminpasswd"; 78 | _userServerSide = "fpj"; 79 | _userClientSide = "fpj"; 80 | _userServerSidePasswd = "fpjsecret"; 81 | _userClientSidePasswd = "fpjsecret"; 82 | _zkModule = "org.apache.zookeeper.server.auth.DigestLoginModule"; 83 | } 84 | 85 | @After 86 | public void tearDown() { 87 | if (_client != null) { 88 | _client.close(); 89 | } 90 | if (_zkServer != null) { 91 | _zkServer.shutdown(); 92 | } 93 | System.clearProperty(ZK_AUTH_PROVIDER); 94 | System.clearProperty(ZkClient.JAVA_LOGIN_CONFIG_PARAM); 95 | Configuration.setConfiguration(null); 96 | } 97 | 98 | private void bootstrap() throws IOException { 99 | Configuration.setConfiguration(null); 100 | String jaasFileName = createJaasFile(); 101 | System.setProperty(ZK_AUTH_PROVIDER, "org.apache.zookeeper.server.auth.SASLAuthenticationProvider"); 102 | System.setProperty(ZkClient.JAVA_LOGIN_CONFIG_PARAM, jaasFileName); 103 | _zkServer = TestUtil.startZkServer(_temporaryFolder, _port); 104 | _client = _zkServer.getZkClient(); 105 | } 106 | 107 | private void bootstrapWithAuthFailure() throws IOException { 108 | _userServerSide = "otheruser"; 109 | bootstrap(); 110 | } 111 | 112 | /** 113 | * Tests that a connection authenticates successfully. 114 | * 115 | * @throws IOException 116 | */ 117 | @Test 118 | public void testConnection() throws IOException { 119 | bootstrap(); 120 | _client.createPersistent("/test", new byte[0], Ids.CREATOR_ALL_ACL); 121 | assertThat(_client.exists("/test")).isTrue(); 122 | } 123 | 124 | /** 125 | * Tests that ZkClient throws an exception in the case ZooKeeper keeps dropping the connection due to authentication 126 | * failures. 127 | * 128 | * @throws IOException 129 | */ 130 | @Test 131 | public void testAuthFailure() throws IOException { 132 | try { 133 | bootstrapWithAuthFailure(); 134 | fail("Expected to fail!"); 135 | } catch (ZkException e) { 136 | assertThat(e).isInstanceOf(ZkTimeoutException.class); 137 | } 138 | } 139 | 140 | /** 141 | * Tests that ZkClient spots the AuthFailed event in the case the property to allow failed SASL connections is 142 | * enabled. 143 | * 144 | * @throws IOException 145 | */ 146 | @Test 147 | public void testAuthFailure_AllowFailedSasl() throws IOException { 148 | System.setProperty(ZK_ALLOW_FAILED_SASL, "true"); 149 | try { 150 | bootstrapWithAuthFailure(); 151 | fail("Expected to fail!"); 152 | } catch (ZkException e) { 153 | assertThat(e).isInstanceOf(ZkTimeoutException.class); 154 | } finally { 155 | System.clearProperty(ZK_ALLOW_FAILED_SASL); 156 | } 157 | } 158 | 159 | /** 160 | * Tests that ZkClient spots the AuthFailed event in the case the property to allow failed SASL connections is 161 | * enabled. 162 | * 163 | * @throws IOException 164 | */ 165 | @Test 166 | public void testAuthFailure_DisabledSasl() throws IOException { 167 | System.setProperty(ZkClient.ZK_SASL_CLIENT, "false"); 168 | try { 169 | bootstrapWithAuthFailure(); 170 | } finally { 171 | System.clearProperty(ZkClient.ZK_SASL_CLIENT); 172 | } 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/ServerZkClientTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import static org.assertj.core.api.Assertions.assertThat; 19 | import static org.junit.Assert.assertEquals; 20 | import static org.junit.Assert.assertFalse; 21 | import static org.junit.Assert.assertTrue; 22 | import static org.junit.Assert.fail; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | import java.util.concurrent.Callable; 27 | import java.util.concurrent.TimeUnit; 28 | 29 | import org.I0Itec.zkclient.exception.ZkBadVersionException; 30 | import org.I0Itec.zkclient.exception.ZkInterruptedException; 31 | import org.I0Itec.zkclient.exception.ZkNoNodeException; 32 | import org.I0Itec.zkclient.exception.ZkTimeoutException; 33 | import org.I0Itec.zkclient.serialize.SerializableSerializer; 34 | import org.apache.zookeeper.Watcher.Event.KeeperState; 35 | import org.apache.zookeeper.data.Stat; 36 | import org.junit.After; 37 | import org.junit.Before; 38 | import org.junit.Rule; 39 | import org.junit.Test; 40 | import org.junit.rules.TemporaryFolder; 41 | 42 | public class ServerZkClientTest extends AbstractBaseZkClientTest { 43 | 44 | private static final int CONNECTION_TIMEOUT = 30000; 45 | 46 | @Rule 47 | public TemporaryFolder _temporaryFolder = new TemporaryFolder(); 48 | 49 | @Override 50 | @Before 51 | public void setUp() throws Exception { 52 | super.setUp(); 53 | _zkServer = TestUtil.startZkServer(_temporaryFolder, 4711); 54 | _client = new ZkClient("localhost:4711", CONNECTION_TIMEOUT); 55 | } 56 | 57 | @Override 58 | @After 59 | public void tearDown() throws Exception { 60 | super.tearDown(); 61 | _client.close(); 62 | _zkServer.shutdown(); 63 | } 64 | 65 | @Test(timeout = 15000) 66 | public void testRetryUntilConnected() throws Exception { 67 | LOG.info("--- testRetryUntilConnected"); 68 | Gateway gateway = new Gateway(4712, 4711); 69 | gateway.start(); 70 | final ZkConnection zkConnection = new ZkConnection("localhost:4712"); 71 | final ZkClient zkClient = new ZkClient(zkConnection, CONNECTION_TIMEOUT); 72 | 73 | gateway.stop(); 74 | 75 | // start server in 250ms 76 | new DeferredGatewayStarter(gateway, 250).start(); 77 | 78 | // this should work as soon as the connection is reestablished, if it 79 | // fails it throws a ConnectionLossException 80 | zkClient.retryUntilConnected(new Callable() { 81 | 82 | @Override 83 | public Object call() throws Exception { 84 | zkConnection.exists("/a", false); 85 | return null; 86 | } 87 | }); 88 | 89 | zkClient.close(); 90 | gateway.stop(); 91 | } 92 | 93 | /** 94 | * Test for reproducing #25 / https://issues.apache.org/jira/browse/KAFKA-824 95 | * 96 | * @throws Exception 97 | */ 98 | @Test(timeout = 15000) 99 | public void testOperationInRetryLoopWhileClientGetsClosed() throws Exception { 100 | LOG.info("--- testRetryUntilConnected"); 101 | Gateway gateway = new Gateway(4712, 4711); 102 | gateway.start(); 103 | final ZkConnection zkConnection = new ZkConnection("localhost:4712"); 104 | final ZkClient zkClient = new ZkClient(zkConnection, CONNECTION_TIMEOUT); 105 | 106 | gateway.stop(); 107 | final Holder exceptionHolder = new Holder(); 108 | Thread actionThread = new Thread() { 109 | @Override 110 | public void run() { 111 | try { 112 | zkClient.createPersistent("/root"); 113 | } catch (Exception e) { 114 | exceptionHolder.set(e); 115 | } 116 | } 117 | }; 118 | actionThread.start(); 119 | zkClient.close(); 120 | actionThread.join(); 121 | 122 | assertThat(exceptionHolder.get()).isNotNull().isInstanceOf(IllegalStateException.class).hasMessageContaining("ZkClient already closed!"); 123 | } 124 | 125 | @Test(timeout = 10000) 126 | public void testReadWithTimeout() throws Exception { 127 | final ZkClient zkClient = new ZkClient("localhost:4711", 5000, CONNECTION_TIMEOUT, new SerializableSerializer(), 5000); 128 | // shutdown the server 129 | LOG.info("Shutting down zookeeper server " + _zkServer); 130 | _zkServer.shutdown(); 131 | // now invoke read operation through the client 132 | try { 133 | LOG.info("Invoking read on ZkClient when ZK server is down"); 134 | zkClient.readData("/b"); 135 | fail("A timeout exception was expected while performing a read through ZkClient, when ZK server is down"); 136 | } catch (ZkTimeoutException zkte) { 137 | // expected 138 | LOG.info("Received the *expected* timeout exception while doing an operation through ZkClient", zkte); 139 | } 140 | } 141 | 142 | @Test(timeout = 30000) 143 | public void testRetryWithTimeout() throws Exception { 144 | final ZkClient zkClient = new ZkClient("localhost:4711", CONNECTION_TIMEOUT, CONNECTION_TIMEOUT, new SerializableSerializer(), 5000); 145 | // shutdown the server 146 | LOG.info("Shutting down zookeeper server " + _zkServer); 147 | _zkServer.shutdown(); 148 | // test the retry method directly 149 | try { 150 | LOG.info("Invoking retryUntilConnected on ZkClient when ZK server is down"); 151 | zkClient.retryUntilConnected(new Callable() { 152 | @Override 153 | public Boolean call() throws Exception { 154 | return zkClient._connection.exists("/b", true); 155 | } 156 | }); 157 | fail("A timeout exception was expected while performing an operation through ZkClient with the ZK server down"); 158 | } catch (ZkTimeoutException zkte) { 159 | // expected 160 | LOG.info("Received the *expected* timeout exception from ZkClient.retryUntilConnected", zkte); 161 | } 162 | } 163 | 164 | @Test(timeout = 15000) 165 | public void testWaitUntilConnected() throws Exception { 166 | LOG.info("--- testWaitUntilConnected"); 167 | ZkClient _client = new ZkClient("localhost:4711", CONNECTION_TIMEOUT); 168 | 169 | _zkServer.shutdown(); 170 | 171 | // the _client state should change to KeeperState.Disconnected 172 | assertTrue(_client.waitForKeeperState(KeeperState.Disconnected, 1, TimeUnit.SECONDS)); 173 | 174 | // connection should not be possible and timeout after 100ms 175 | assertFalse(_client.waitUntilConnected(100, TimeUnit.MILLISECONDS)); 176 | } 177 | 178 | @Test(timeout = 15000) 179 | public void testRetryUntilConnected_SessionExpiredException() { 180 | LOG.info("--- testRetryUntilConnected_SessionExpiredException"); 181 | 182 | // Use a tick time of 100ms, because the minimum session timeout is 2 x tick-time. 183 | // ZkServer zkServer = TestUtil.startZkServer("ZkClientTest-testSessionExpiredException", 4711, 100); 184 | Gateway gateway = new Gateway(4712, 4711); 185 | gateway.start(); 186 | 187 | // Use a session timeout of 200ms 188 | final ZkClient zkClient = new ZkClient("localhost:4712", 200, CONNECTION_TIMEOUT); 189 | 190 | gateway.stop(); 191 | 192 | // Start server in 600ms, the session should have expired by then 193 | new DeferredGatewayStarter(gateway, 600).start(); 194 | 195 | // This should work as soon as a new session has been created (and the connection is reestablished), if it fails 196 | // it throws a SessionExpiredException 197 | zkClient.retryUntilConnected(new Callable() { 198 | 199 | @Override 200 | public Object call() throws Exception { 201 | zkClient.exists("/a"); 202 | return null; 203 | } 204 | }); 205 | 206 | zkClient.close(); 207 | // zkServer.shutdown(); 208 | gateway.stop(); 209 | } 210 | 211 | @Test(timeout = 15000) 212 | public void testChildListenerAfterSessionExpiredException() throws Exception { 213 | LOG.info("--- testChildListenerAfterSessionExpiredException"); 214 | 215 | int sessionTimeout = 200; 216 | ZkClient connectedClient = _zkServer.getZkClient(); 217 | connectedClient.createPersistent("/root"); 218 | 219 | Gateway gateway = new Gateway(4712, 4711); 220 | gateway.start(); 221 | 222 | final ZkClient disconnectedZkClient = new ZkClient("localhost:4712", sessionTimeout, CONNECTION_TIMEOUT); 223 | final Holder> children = new Holder>(); 224 | disconnectedZkClient.subscribeChildChanges("/root", new IZkChildListener() { 225 | 226 | @Override 227 | public void handleChildChange(String parentPath, List currentChilds) throws Exception { 228 | children.set(currentChilds); 229 | } 230 | }); 231 | 232 | gateway.stop(); 233 | 234 | // The connected client now created a new child node 235 | connectedClient.createPersistent("/root/node"); 236 | 237 | // Wait for 3 x sessionTimeout, the session should have expired by then and start the gateway again 238 | Thread.sleep(sessionTimeout * 3); 239 | gateway.start(); 240 | 241 | Boolean hasOneChild = TestUtil.waitUntil(true, new Callable() { 242 | 243 | @Override 244 | public Boolean call() throws Exception { 245 | return children.get() != null && children.get().size() == 1; 246 | } 247 | }, TimeUnit.SECONDS, 30); 248 | 249 | assertTrue(hasOneChild); 250 | 251 | disconnectedZkClient.close(); 252 | gateway.stop(); 253 | } 254 | 255 | @Test(timeout = 10000) 256 | public void testZkClientConnectedToGatewayClosesQuickly() throws Exception { 257 | LOG.info("--- testZkClientConnectedToGatewayClosesQuickly"); 258 | final Gateway gateway = new Gateway(4712, 4711); 259 | gateway.start(); 260 | 261 | ZkClient zkClient = new ZkClient("localhost:4712", CONNECTION_TIMEOUT); 262 | zkClient.close(); 263 | 264 | gateway.stop(); 265 | } 266 | 267 | @Test 268 | public void testCountChildren() throws InterruptedException { 269 | assertEquals(0, _client.countChildren("/a")); 270 | _client.createPersistent("/a"); 271 | assertEquals(0, _client.countChildren("/a")); 272 | _client.createPersistent("/a/b"); 273 | assertEquals(1, _client.countChildren("/a")); 274 | 275 | // test concurrent access 276 | Thread thread = new Thread() { 277 | @Override 278 | public void run() { 279 | try { 280 | while (!isInterrupted()) { 281 | _client.createPersistent("/test"); 282 | _client.delete("/test"); 283 | } 284 | } catch (ZkInterruptedException e) { 285 | // ignore and finish 286 | } 287 | } 288 | }; 289 | 290 | thread.start(); 291 | for (int i = 0; i < 1000; i++) { 292 | assertEquals(0, _client.countChildren("/test")); 293 | } 294 | thread.interrupt(); 295 | thread.join(); 296 | } 297 | 298 | @Test 299 | public void testReadDataWithStat() { 300 | _client.createPersistent("/a", "data"); 301 | Stat stat = new Stat(); 302 | _client.readData("/a", stat); 303 | assertEquals(0, stat.getVersion()); 304 | assertTrue(stat.getDataLength() > 0); 305 | } 306 | 307 | @Test 308 | public void testWriteDataWithExpectedVersion() { 309 | _client.createPersistent("/a", "data"); 310 | _client.writeData("/a", "data2", 0); 311 | 312 | try { 313 | _client.writeData("/a", "data3", 0); 314 | fail("expected exception"); 315 | } catch (ZkBadVersionException e) { 316 | // expected 317 | } 318 | } 319 | 320 | @Test 321 | public void testCreateWithParentDirs() { 322 | String path = "/a/b"; 323 | try { 324 | _client.createPersistent(path, false); 325 | fail("should throw exception"); 326 | } catch (ZkNoNodeException e) { 327 | assertFalse(_client.exists(path)); 328 | } 329 | 330 | _client.createPersistent(path, true); 331 | assertTrue(_client.exists(path)); 332 | } 333 | 334 | @Test 335 | public void testUpdateSerialized() throws InterruptedException { 336 | _client.createPersistent("/a", 0); 337 | 338 | int numberOfThreads = 2; 339 | final int numberOfIncrementsPerThread = 100; 340 | 341 | List threads = new ArrayList(); 342 | for (int i = 0; i < numberOfThreads; i++) { 343 | Thread thread = new Thread() { 344 | @Override 345 | public void run() { 346 | for (int j = 0; j < numberOfIncrementsPerThread; j++) { 347 | _client.updateDataSerialized("/a", new DataUpdater() { 348 | 349 | @Override 350 | public Integer update(Integer integer) { 351 | return integer + 1; 352 | } 353 | }); 354 | } 355 | } 356 | }; 357 | thread.start(); 358 | threads.add(thread); 359 | } 360 | 361 | for (Thread thread : threads) { 362 | thread.join(); 363 | } 364 | 365 | Integer finalValue = _client.readData("/a"); 366 | assertEquals(numberOfIncrementsPerThread * numberOfThreads, finalValue.intValue()); 367 | } 368 | } 369 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/TestUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import static org.mockito.Mockito.mock; 19 | 20 | import java.io.File; 21 | import java.io.IOException; 22 | import java.util.concurrent.Callable; 23 | import java.util.concurrent.TimeUnit; 24 | 25 | import org.apache.commons.io.FileUtils; 26 | import org.junit.rules.TemporaryFolder; 27 | import org.mockito.exceptions.base.MockitoAssertionError; 28 | 29 | public class TestUtil { 30 | 31 | /** 32 | * This waits until the provided {@link Callable} returns an object that is equals to the given expected value or 33 | * the timeout has been reached. In both cases this method will return the return value of the latest 34 | * {@link Callable} execution. 35 | * 36 | * @param expectedValue 37 | * The expected value of the callable. 38 | * @param callable 39 | * The callable. 40 | * @param 41 | * The return type of the callable. 42 | * @param timeUnit 43 | * The timeout timeunit. 44 | * @param timeout 45 | * The timeout. 46 | * @return the return value of the latest {@link Callable} execution. 47 | * @throws Exception 48 | * @throws InterruptedException 49 | */ 50 | public static T waitUntil(T expectedValue, Callable callable, TimeUnit timeUnit, long timeout) throws Exception { 51 | long startTime = System.currentTimeMillis(); 52 | do { 53 | T actual = callable.call(); 54 | if (expectedValue.equals(actual)) { 55 | return actual; 56 | } 57 | if (System.currentTimeMillis() > startTime + timeUnit.toMillis(timeout)) { 58 | return actual; 59 | } 60 | Thread.sleep(50); 61 | } while (true); 62 | } 63 | 64 | /** 65 | * This waits until a mockito verification passed (which is provided in the runnable). This waits until the 66 | * virification passed or the timeout has been reached. If the timeout has been reached this method will rethrow the 67 | * {@link MockitoAssertionError} that comes from the mockito verification code. 68 | * 69 | * @param runnable 70 | * The runnable containing the mockito verification. 71 | * @param timeUnit 72 | * The timeout timeunit. 73 | * @param timeout 74 | * The timeout. 75 | * @throws InterruptedException 76 | */ 77 | public static void waitUntilVerified(Runnable runnable, TimeUnit timeUnit, int timeout) throws InterruptedException { 78 | long startTime = System.currentTimeMillis(); 79 | do { 80 | MockitoAssertionError exception = null; 81 | try { 82 | runnable.run(); 83 | } catch (MockitoAssertionError e) { 84 | exception = e; 85 | } 86 | if (exception == null) { 87 | return; 88 | } 89 | if (System.currentTimeMillis() > startTime + timeUnit.toMillis(timeout)) { 90 | throw exception; 91 | } 92 | Thread.sleep(50); 93 | } while (true); 94 | } 95 | 96 | public static ZkServer startZkServer(TemporaryFolder temporaryFolder, int port) throws IOException { 97 | File dataFolder = temporaryFolder.newFolder("data"); 98 | File logFolder = temporaryFolder.newFolder("log"); 99 | return startServer(port, dataFolder.getAbsolutePath(), logFolder.getAbsolutePath()); 100 | } 101 | 102 | public static ZkServer startZkServer(String testName, int port) throws IOException { 103 | String dataPath = "./build/test/" + testName + "/data"; 104 | String logPath = "./build/test/" + testName + "/log"; 105 | FileUtils.deleteDirectory(new File(dataPath)); 106 | FileUtils.deleteDirectory(new File(logPath)); 107 | return startServer(port, dataPath, logPath); 108 | } 109 | 110 | private static ZkServer startServer(int port, String dataPath, String logPath) { 111 | ZkServer zkServer = new ZkServer(dataPath, logPath, mock(IDefaultNameSpace.class), port, ZkServer.DEFAULT_TICK_TIME, 100); 112 | zkServer.start(); 113 | return zkServer; 114 | } 115 | } -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/ZkAuthTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.I0Itec.zkclient; 19 | 20 | import static org.assertj.core.api.Assertions.assertThat; 21 | 22 | import org.apache.zookeeper.CreateMode; 23 | import org.apache.zookeeper.ZooDefs; 24 | import org.junit.After; 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | 28 | public class ZkAuthTest extends AbstractAuthTest { 29 | @Override 30 | @Before 31 | public void setUp() throws Exception { 32 | super.setUp(); 33 | _zkServer = TestUtil.startZkServer("ZkClientTest", 4711); 34 | _client = new ZkClient("localhost:4711", 25000); 35 | } 36 | 37 | @Override 38 | @After 39 | public void tearDown() throws Exception { 40 | super.tearDown(); 41 | if (_client != null) { 42 | _client.close(); 43 | } 44 | _zkServer.shutdown(); 45 | } 46 | 47 | @Test 48 | public void testAuthorized() { 49 | _client.addAuthInfo("digest", "pat:pass".getBytes()); 50 | _client.create("/path1", null, ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT); 51 | _client.readData("/path1"); 52 | } 53 | 54 | @Test 55 | public void testSetAndGetAcls() { 56 | _client.addAuthInfo("digest", "pat:pass".getBytes()); 57 | 58 | _client.create("/path1", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 59 | assertThat(_client.getAcl("/path1").getKey()).isEqualTo(ZooDefs.Ids.OPEN_ACL_UNSAFE); 60 | 61 | for (int i = 0; i < 100; i++) { 62 | _client.setAcl("/path1", ZooDefs.Ids.OPEN_ACL_UNSAFE); 63 | assertThat(_client.getAcl("/path1").getKey()).isEqualTo(ZooDefs.Ids.OPEN_ACL_UNSAFE); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/ZkClientSerializationTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import static org.junit.Assert.assertArrayEquals; 19 | import static org.junit.Assert.assertEquals; 20 | 21 | import java.util.Random; 22 | 23 | import org.I0Itec.zkclient.serialize.BytesPushThroughSerializer; 24 | import org.I0Itec.zkclient.serialize.SerializableSerializer; 25 | import org.I0Itec.zkclient.testutil.ZkTestSystem; 26 | import org.junit.Rule; 27 | import org.junit.Test; 28 | 29 | public class ZkClientSerializationTest { 30 | 31 | @Rule 32 | public ZkTestSystem _zk = ZkTestSystem.getInstance(); 33 | 34 | @Test 35 | public void testBytes() throws Exception { 36 | ZkClient zkClient = new ZkClient(_zk.getZkServerAddress(), 2000, 30000, new BytesPushThroughSerializer()); 37 | byte[] bytes = new byte[100]; 38 | new Random().nextBytes(bytes); 39 | zkClient.createPersistent("/a", bytes); 40 | byte[] readBytes = zkClient.readData("/a"); 41 | assertArrayEquals(bytes, readBytes); 42 | } 43 | 44 | @Test 45 | public void testSerializables() throws Exception { 46 | ZkClient zkClient = new ZkClient(_zk.getZkServerAddress(), 2000, 30000, new SerializableSerializer()); 47 | String data = "hello world"; 48 | zkClient.createPersistent("/a", data); 49 | String readData = zkClient.readData("/a"); 50 | assertEquals(data, readData); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/ZkConnectionTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient; 17 | 18 | import org.I0Itec.zkclient.testutil.ZkTestSystem; 19 | import org.junit.Rule; 20 | 21 | public class ZkConnectionTest extends AbstractConnectionTest { 22 | 23 | @Rule 24 | public ZkTestSystem _zk = ZkTestSystem.getInstance(); 25 | 26 | public ZkConnectionTest() { 27 | super(establishConnection()); 28 | } 29 | 30 | private static ZkConnection establishConnection() { 31 | ZkConnection zkConnection = new ZkConnection("localhost:" + ZkTestSystem.getInstance().getZkServer().getPort()); 32 | new ZkClient(zkConnection);// connect 33 | return zkConnection; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/ZkStateChangeTest.java: -------------------------------------------------------------------------------- 1 | package org.I0Itec.zkclient; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.concurrent.Callable; 8 | import java.util.concurrent.TimeUnit; 9 | 10 | import org.apache.zookeeper.CreateMode; 11 | import org.apache.zookeeper.KeeperException; 12 | import org.apache.zookeeper.WatchedEvent; 13 | import org.apache.zookeeper.Watcher; 14 | import org.apache.zookeeper.Watcher.Event.KeeperState; 15 | import org.apache.zookeeper.ZooKeeper.States; 16 | import org.apache.zookeeper.data.ACL; 17 | import org.apache.zookeeper.data.Stat; 18 | import org.apache.zookeeper.Op; 19 | import org.apache.zookeeper.OpResult; 20 | import org.junit.After; 21 | import org.junit.Before; 22 | import org.junit.Test; 23 | 24 | public class ZkStateChangeTest { 25 | 26 | private StateOnlyConnection zkConn; 27 | private ZkClient client; 28 | private TestStateListener listener; 29 | 30 | @Before 31 | public void setUp() { 32 | zkConn = new StateOnlyConnection(); 33 | client = new ZkClient(zkConn); 34 | listener = new TestStateListener(); 35 | client.subscribeStateChanges(listener); 36 | } 37 | 38 | @After 39 | public void tearDown() { 40 | client.close(); 41 | } 42 | 43 | @Test 44 | public void testNewSessionEvent() throws Exception { 45 | zkConn.expireSession(); 46 | assertTimed(1, new Callable() { 47 | @Override 48 | public Integer call() throws Exception { 49 | return listener.expiredEvents; 50 | } 51 | }); 52 | 53 | assertTimed(0, new Callable() { 54 | @Override 55 | public Integer call() throws Exception { 56 | return listener.sessionEstablishErrors; 57 | } 58 | }); 59 | 60 | assertTimed(1, new Callable() { 61 | @Override 62 | public Integer call() throws Exception { 63 | return listener.newSessionEvent; 64 | } 65 | }); 66 | } 67 | 68 | @Test 69 | public void testFailConnectEvent() throws Exception { 70 | zkConn.setFailOnConnect(true); 71 | zkConn.expireSession(); 72 | assertTimed(1, new Callable() { 73 | @Override 74 | public Integer call() throws Exception { 75 | return listener.expiredEvents; 76 | } 77 | }); 78 | 79 | assertTimed(1, new Callable() { 80 | @Override 81 | public Integer call() throws Exception { 82 | return listener.sessionEstablishErrors; 83 | } 84 | }); 85 | 86 | assertTimed(0, new Callable() { 87 | @Override 88 | public Integer call() throws Exception { 89 | return listener.newSessionEvent; 90 | } 91 | }); 92 | 93 | client.close(); 94 | } 95 | 96 | private void assertTimed(T expectedVal, Callable condition) throws Exception { 97 | assertEquals(expectedVal, TestUtil.waitUntil(expectedVal, condition, TimeUnit.SECONDS, 5)); 98 | } 99 | 100 | private static class StateOnlyConnection implements IZkConnection { 101 | private Watcher _watcher; 102 | private boolean failOnConnect = false; 103 | 104 | @Override 105 | public void connect(Watcher w) { 106 | _watcher = w; 107 | if (failOnConnect) { 108 | // As as example: 109 | throw new RuntimeException("Testing connection failure"); 110 | } 111 | new Thread() { 112 | @Override 113 | public void run() { 114 | _watcher.process(new WatchedEvent(null, KeeperState.SyncConnected, null)); 115 | } 116 | }.start(); 117 | } 118 | 119 | public void expireSession() { 120 | _watcher.process(new WatchedEvent(null, KeeperState.Expired, null)); 121 | } 122 | 123 | public void setFailOnConnect(boolean failFlag) { 124 | this.failOnConnect = failFlag; 125 | } 126 | 127 | @Override 128 | public void close() throws InterruptedException { 129 | 130 | } 131 | 132 | @Override 133 | public String create(String path, byte[] data, CreateMode mode) throws KeeperException, InterruptedException { 134 | throw new RuntimeException("not implemented"); 135 | } 136 | 137 | @Override 138 | public String create(String path, byte[] data, List acl, CreateMode mode) throws KeeperException, InterruptedException { 139 | throw new RuntimeException("not implemented"); 140 | } 141 | 142 | @Override 143 | public void delete(String path) throws InterruptedException, KeeperException { 144 | throw new RuntimeException("not implemented"); 145 | } 146 | 147 | @Override 148 | public boolean exists(final String path, final boolean watch) throws KeeperException, InterruptedException { 149 | throw new RuntimeException("not implemented"); 150 | } 151 | 152 | public List getChildren(final String path, final boolean watch) throws KeeperException, InterruptedException { 153 | throw new RuntimeException("not implemented"); 154 | } 155 | 156 | @Override 157 | public byte[] readData(String path, Stat stat, boolean watch) throws KeeperException, InterruptedException { 158 | throw new RuntimeException("not implemented"); 159 | } 160 | 161 | @Override 162 | public void writeData(String path, byte[] data, int expectedVersion) throws KeeperException, InterruptedException { 163 | throw new RuntimeException("not implemented"); 164 | } 165 | 166 | @Override 167 | public Stat writeDataReturnStat(String path, byte[] data, int expectedVersion) throws KeeperException, InterruptedException { 168 | throw new RuntimeException("not implemented"); 169 | } 170 | 171 | @Override 172 | public States getZookeeperState() { 173 | throw new RuntimeException("not implemented"); 174 | } 175 | 176 | @Override 177 | public long getCreateTime(String path) throws KeeperException, InterruptedException { 178 | throw new RuntimeException("not implemented"); 179 | } 180 | 181 | @Override 182 | public String getServers() { 183 | return "test"; 184 | } 185 | 186 | @Override 187 | public List multi(Iterable ops) throws KeeperException, InterruptedException { 188 | throw new UnsupportedOperationException(); 189 | } 190 | 191 | @Override 192 | public void addAuthInfo(String scheme, byte[] auth) { 193 | throw new RuntimeException("not implemented"); 194 | } 195 | 196 | @Override 197 | public void setAcl(String path, List acl, int version) throws KeeperException, InterruptedException { 198 | throw new UnsupportedOperationException(); 199 | } 200 | 201 | @Override 202 | public Map.Entry, Stat> getAcl(String path) throws KeeperException, InterruptedException { 203 | throw new UnsupportedOperationException(); 204 | } 205 | } 206 | 207 | private static class TestStateListener implements IZkStateListener { 208 | public int expiredEvents = 0; 209 | public int newSessionEvent = 0; 210 | public int sessionEstablishErrors = 0; 211 | 212 | @Override 213 | public void handleStateChanged(KeeperState state) throws Exception { 214 | if (state == KeeperState.Expired) { 215 | expiredEvents++; 216 | } 217 | } 218 | 219 | @Override 220 | public void handleNewSession() throws Exception { 221 | newSessionEvent++; 222 | } 223 | 224 | @Override 225 | public void handleSessionEstablishmentError(final Throwable error) throws Exception { 226 | sessionEstablishErrors++; 227 | } 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/testutil/ZkTestSystem.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient.testutil; 17 | 18 | import org.I0Itec.zkclient.IDefaultNameSpace; 19 | import org.I0Itec.zkclient.ZkClient; 20 | import org.I0Itec.zkclient.ZkServer; 21 | import org.apache.commons.io.FileUtils; 22 | import org.junit.rules.ExternalResource; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | import java.io.File; 27 | import java.io.IOException; 28 | import java.util.List; 29 | 30 | import static org.mockito.Mockito.mock; 31 | 32 | public class ZkTestSystem extends ExternalResource { 33 | 34 | //protected static final Logger LOG = Logger.getLogger(ZkTestSystem.class); 35 | 36 | protected static final Logger LOG = LoggerFactory.getLogger(ZkTestSystem.class); 37 | 38 | private static int PORT = 10002; 39 | private static ZkTestSystem _instance; 40 | private ZkServer _zkServer; 41 | 42 | private ZkTestSystem() { 43 | LOG.info("~~~~~~~~~~~~~~~ starting zk system ~~~~~~~~~~~~~~~"); 44 | String baseDir = "build/zkdata"; 45 | try { 46 | FileUtils.deleteDirectory(new File(baseDir)); 47 | } catch (IOException e) { 48 | throw new RuntimeException(e); 49 | } 50 | String dataDir = baseDir + "/data"; 51 | String logDir = baseDir + "/log"; 52 | _zkServer = new ZkServer(dataDir, logDir, mock(IDefaultNameSpace.class), PORT); 53 | _zkServer.start(); 54 | LOG.info("~~~~~~~~~~~~~~~ zk system started ~~~~~~~~~~~~~~~"); 55 | } 56 | 57 | @Override 58 | // executed before every test method 59 | protected void before() throws Throwable { 60 | cleanupZk(); 61 | } 62 | 63 | @Override 64 | // executed after every test method 65 | protected void after() { 66 | cleanupZk(); 67 | } 68 | 69 | private void cleanupZk() { 70 | LOG.info("cleanup zk namespace"); 71 | List children = getZkClient().getChildren("/"); 72 | for (String child : children) { 73 | if (!child.equals("zookeeper")) { 74 | getZkClient().deleteRecursive("/" + child); 75 | } 76 | } 77 | LOG.info("unsubscribing " + getZkClient().numberOfListeners() + " listeners"); 78 | getZkClient().unsubscribeAll(); 79 | } 80 | 81 | public static ZkTestSystem getInstance() { 82 | if (_instance == null) { 83 | _instance = new ZkTestSystem(); 84 | _instance.cleanupZk(); 85 | Runtime.getRuntime().addShutdownHook(new Thread() { 86 | @Override 87 | public void run() { 88 | LOG.info("shutting zk down"); 89 | getInstance().getZkServer().shutdown(); 90 | } 91 | }); 92 | } 93 | return _instance; 94 | } 95 | 96 | public ZkServer getZkServer() { 97 | return _zkServer; 98 | } 99 | 100 | public String getZkServerAddress() { 101 | return "localhost:" + getServerPort(); 102 | } 103 | 104 | public ZkClient getZkClient() { 105 | return _zkServer.getZkClient(); 106 | } 107 | 108 | public int getServerPort() { 109 | return PORT; 110 | } 111 | 112 | public ZkClient createZkClient() { 113 | return new ZkClient("localhost:" + PORT); 114 | } 115 | 116 | public void showStructure() { 117 | getZkClient().showFolders(System.out); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/test/java/org/I0Itec/zkclient/util/ZkPathUtilTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.I0Itec.zkclient.util; 17 | 18 | import junit.framework.TestCase; 19 | 20 | import org.I0Itec.zkclient.TestUtil; 21 | import org.I0Itec.zkclient.ZkClient; 22 | import org.I0Itec.zkclient.ZkServer; 23 | 24 | public class ZkPathUtilTest extends TestCase { 25 | 26 | protected ZkServer _zkServer; 27 | protected ZkClient _client; 28 | 29 | public void testToString() throws Exception { 30 | _zkServer = TestUtil.startZkServer("ZkPathUtilTest", 4711); 31 | _client = new ZkClient("localhost:4711", 30000); 32 | final String file1 = "/files/file1"; 33 | final String file2 = "/files/file2"; 34 | final String file3 = "/files/file2/file3"; 35 | _client.createPersistent(file1, true); 36 | _client.createPersistent(file2, true); 37 | _client.createPersistent(file3, true); 38 | 39 | String stringRepresentation = ZkPathUtil.toString(_client); 40 | System.out.println(stringRepresentation); 41 | System.out.println("-------------------------"); 42 | assertTrue(stringRepresentation.contains("file1")); 43 | assertTrue(stringRepresentation.contains("file2")); 44 | assertTrue(stringRepresentation.contains("file3")); 45 | 46 | // path filtering 47 | stringRepresentation = ZkPathUtil.toString(_client, "/", new ZkPathUtil.PathFilter() { 48 | @Override 49 | public boolean showChilds(String path) { 50 | return !file2.equals(path); 51 | } 52 | }); 53 | assertTrue(stringRepresentation.contains("file1")); 54 | assertTrue(stringRepresentation.contains("file2")); 55 | assertFalse(stringRepresentation.contains("file3")); 56 | 57 | // start path 58 | stringRepresentation = ZkPathUtil.toString(_client, file2, ZkPathUtil.PathFilter.ALL); 59 | assertFalse(stringRepresentation.contains("file1")); 60 | assertTrue(stringRepresentation.contains("file2")); 61 | assertTrue(stringRepresentation.contains("file3")); 62 | 63 | _zkServer.shutdown(); 64 | } 65 | 66 | public void testLeadingZeros() throws Exception { 67 | assertEquals("0000000001", ZkPathUtil.leadingZeros(1, 10)); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=info, console 2 | log4j.logger.org.apache.zookeeper=error 3 | 4 | log4j.appender.console=org.apache.log4j.ConsoleAppender 5 | log4j.appender.console.target=System.out 6 | log4j.appender.console.layout=org.apache.log4j.PatternLayout 7 | log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %5p [%t] (%F:%L) - %m%n 8 | --------------------------------------------------------------------------------