();
41 |
42 | private static final AtomicInteger _eventId = new AtomicInteger(0);
43 |
44 | private volatile boolean shutdown = false;
45 |
46 | static abstract class ZkEvent {
47 |
48 | private final String _description;
49 |
50 | public ZkEvent(String description) {
51 | _description = description;
52 | }
53 |
54 | public abstract void run() throws Exception;
55 |
56 | @Override
57 | public String toString() {
58 | return "ZkEvent[" + _description + "]";
59 | }
60 | }
61 |
62 | ZkEventThread(String name) {
63 | setDaemon(true);
64 | setName("ZkClient-EventThread-" + getId() + "-" + name);
65 | }
66 |
67 | @Override
68 | public void run() {
69 | LOG.info("Starting ZkClient event thread.");
70 | try {
71 | while (!isShutdown()) {
72 | ZkEvent zkEvent = _events.take();
73 | int eventId = _eventId.incrementAndGet();
74 | LOG.debug("Delivering event #" + eventId + " " + zkEvent);
75 | try {
76 | zkEvent.run();
77 | } catch (InterruptedException e) {
78 | shutdown();
79 | } catch (ZkInterruptedException e) {
80 | shutdown();
81 | } catch (Throwable e) {
82 | LOG.error("Error handling event " + zkEvent, e);
83 | }
84 | LOG.debug("Delivering event #" + eventId + " done");
85 | }
86 | } catch (InterruptedException e) {
87 | LOG.info("Terminate ZkClient event thread.");
88 | }
89 | }
90 |
91 | /**
92 | * @return the shutdown
93 | */
94 | public boolean isShutdown() {
95 | return shutdown || isInterrupted();
96 | }
97 |
98 | public void shutdown() {
99 | this.shutdown = true;
100 | this.interrupt();
101 | }
102 |
103 | public void send(ZkEvent event) {
104 | if (!isShutdown()) {
105 | LOG.debug("New event: " + event);
106 | _events.add(event);
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/main/java/com/github/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 com.github.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 final Condition _dataChangedCondition = newCondition();
26 | private final Condition _stateChangedCondition = newCondition();
27 | private final 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/com/github/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 com.github.zkclient;
17 |
18 | import com.github.zkclient.exception.ZkException;
19 | import org.apache.zookeeper.client.FourLetterWordMain;
20 | import org.apache.zookeeper.server.ServerConfig;
21 | import org.apache.zookeeper.server.ZooKeeperServerMain;
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.net.ConnectException;
29 |
30 | public class ZkServer extends ZooKeeperServerMain {
31 |
32 | private final static Logger LOG = LoggerFactory.getLogger(ZkServer.class);
33 | ;
34 |
35 | public static final int DEFAULT_PORT = 2181;
36 |
37 | public static final int DEFAULT_TICK_TIME = 5000;
38 |
39 | public static final int DEFAULT_MIN_SESSION_TIMEOUT = 2 * DEFAULT_TICK_TIME;
40 |
41 | private final String _dataDir;
42 |
43 | private final String _logDir;
44 |
45 | private ZkClient _zkClient;
46 |
47 | private final int _port;
48 |
49 | private final int _tickTime;
50 |
51 | private final int _minSessionTimeout;
52 |
53 | private volatile boolean shutdown = false;
54 |
55 | private boolean daemon = true;
56 |
57 | public ZkServer(String dataDir, String logDir) {
58 | this(dataDir, logDir, DEFAULT_PORT);
59 | }
60 |
61 | public ZkServer(String dataDir, String logDir, int port) {
62 | this(dataDir, logDir, port, DEFAULT_TICK_TIME);
63 | }
64 |
65 | public ZkServer(String dataDir, String logDir, int port, int tickTime) {
66 | this(dataDir, logDir, port, tickTime, DEFAULT_MIN_SESSION_TIMEOUT);
67 | }
68 |
69 | public ZkServer(String dataDir, String logDir, int port, int tickTime, int minSessionTimeout) {
70 | _dataDir = dataDir;
71 | _logDir = logDir;
72 | _port = port;
73 | _tickTime = tickTime;
74 | _minSessionTimeout = minSessionTimeout;
75 | }
76 |
77 | public int getPort() {
78 | return _port;
79 | }
80 |
81 | @PostConstruct
82 | public void start() {
83 | shutdown = false;
84 | startZkServer();
85 | _zkClient = new ZkClient("localhost:" + _port, 10000);
86 | }
87 |
88 | private void startZkServer() {
89 | final int port = _port;
90 | if (ZkClientUtils.isPortFree(port)) {
91 | final File dataDir = new File(_dataDir);
92 | final File dataLogDir = new File(_logDir);
93 | dataDir.mkdirs();
94 |
95 | // single zk server
96 | LOG.info("Start single zookeeper server, port={} data={} ", port, dataDir.getAbsolutePath());
97 | //
98 | final ZooKeeperServerMain serverMain = this;
99 | final InnerServerConfig config = new InnerServerConfig();
100 | config.parse(new String[]{"" + port, dataDir.getAbsolutePath(), "" + _tickTime, "60"});
101 | config.setMinSessionTimeout(_minSessionTimeout);
102 | //
103 | final String threadName = "inner-zkserver-" + port;
104 | final Thread innerThread = new Thread(new Runnable() {
105 | @Override
106 | public void run() {
107 | try {
108 | serverMain.runFromConfig(config);
109 | } catch (Exception e) {
110 | throw new ZkException("Unable to start single ZooKeeper server.", e);
111 | }
112 | }
113 | }, threadName);
114 | innerThread.setDaemon(daemon);
115 | innerThread.start();
116 | //
117 | waitForServerUp(port, 30000, false);
118 |
119 | } else {
120 | throw new IllegalStateException("Zookeeper port " + port + " was already in use. Running in single machine mode?");
121 | }
122 | }
123 |
124 | @PreDestroy
125 | public void shutdown() {
126 | if (!shutdown) {
127 | shutdown = true;
128 | LOG.info("Shutting down ZkServer port={}...", _port);
129 | if (_zkClient != null) {
130 | try {
131 | _zkClient.close();
132 | } catch (ZkException e) {
133 | LOG.warn("Error on closing zkclient: " + e.getClass().getName());
134 | }
135 | _zkClient = null;
136 | }
137 | super.shutdown();
138 | waitForServerDown(_port, 30000, false);
139 | LOG.info("Shutting down ZkServer port={}...done", _port);
140 | }
141 | }
142 |
143 |
144 | public ZkClient getZkClient() {
145 | return _zkClient;
146 | }
147 |
148 | class InnerServerConfig extends ServerConfig {
149 | public void setMinSessionTimeout(int minSessionTimeout) {
150 | this.minSessionTimeout = minSessionTimeout;
151 | }
152 | }
153 |
154 | public static boolean waitForServerUp(int port, long timeout, boolean secure) {
155 | long start = System.currentTimeMillis();
156 | while (true) {
157 | try {
158 | // if there are multiple hostports, just take the first one
159 | String result = FourLetterWordMain.send4LetterWord("127.0.0.1", port, "stat");
160 | if (result.startsWith("Zookeeper version:") &&
161 | !result.contains("READ-ONLY")) {
162 | return true;
163 | }
164 | } catch (ConnectException e) {
165 | // ignore as this is expected, do not log stacktrace
166 | LOG.debug("server {} not up: {}", port, e.toString());
167 | } catch (Exception e) {
168 | // ignore as this is expected
169 | LOG.info("server {} not up", port, e);
170 | }
171 |
172 | if (System.currentTimeMillis() > start + timeout) {
173 | break;
174 | }
175 | try {
176 | Thread.sleep(250);
177 | } catch (InterruptedException e) {
178 | // ignore
179 | }
180 | }
181 | return false;
182 | }
183 |
184 | public static boolean waitForServerDown(int port, long timeout, boolean secure) {
185 | long start = System.currentTimeMillis();
186 | while (true) {
187 | try {
188 | FourLetterWordMain.send4LetterWord("127.0.0.1", port, "stat");
189 | } catch (Exception e) {
190 | return true;
191 | }
192 |
193 | if (System.currentTimeMillis() > start + timeout) {
194 | break;
195 | }
196 | try {
197 | Thread.sleep(250);
198 | } catch (InterruptedException e) {
199 | // ignore
200 | }
201 | }
202 | return false;
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/src/main/java/com/github/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 com.github.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/com/github/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 com.github.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/com/github/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 com.github.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/com/github/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 com.github.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/com/github/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 com.github.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/com/github/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 com.github.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/com/github/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 com.github.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/test/java/com/github/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 com.github.zkclient;
17 |
18 | import com.github.zkclient.Gateway;
19 |
20 | public class DeferredGatewayStarter extends Thread {
21 |
22 | private final Gateway _zkServer;
23 | private int _delay;
24 |
25 | public DeferredGatewayStarter(Gateway gateway, int delay) {
26 | _zkServer = gateway;
27 | _delay = delay;
28 | }
29 |
30 | @Override
31 | public void run() {
32 | try {
33 | Thread.sleep(_delay);
34 | _zkServer.start();
35 | } catch (Exception e) {
36 | // ignore
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/src/test/java/com/github/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 com.github.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/test/java/com/github/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 com.github.zkclient;
17 |
18 | import java.io.Closeable;
19 | import java.io.IOException;
20 | import java.io.InputStream;
21 | import java.io.OutputStream;
22 | import java.net.ServerSocket;
23 | import java.net.Socket;
24 | import java.net.SocketException;
25 | import java.util.ArrayList;
26 | import java.util.List;
27 | import java.util.Vector;
28 | import java.util.concurrent.locks.Condition;
29 | import java.util.concurrent.locks.Lock;
30 | import java.util.concurrent.locks.ReentrantLock;
31 |
32 | import org.slf4j.Logger;
33 | import org.slf4j.LoggerFactory;
34 |
35 | public class GatewayThread extends Thread {
36 |
37 | protected final static Logger LOG = LoggerFactory.getLogger(GatewayThread.class);
38 |
39 | private final int _port;
40 | private final int _destinationPort;
41 | private ServerSocket _serverSocket;
42 | private Lock _lock = new ReentrantLock();
43 | private Condition _runningCondition = _lock.newCondition();
44 | private boolean _running = false;
45 |
46 | public GatewayThread(int port, int destinationPort) {
47 | _port = port;
48 | _destinationPort = destinationPort;
49 | setDaemon(true);
50 | }
51 |
52 | @Override
53 | public void run() {
54 | final List runningThreads = new Vector();
55 | try {
56 | LOG.info("Starting gateway on port " + _port + " pointing to port " + _destinationPort);
57 | _serverSocket = new ServerSocket(_port);
58 | _lock.lock();
59 | try {
60 | _running = true;
61 | _runningCondition.signalAll();
62 | } finally {
63 | _lock.unlock();
64 | }
65 | while (true) {
66 | final Socket socket = _serverSocket.accept();
67 | LOG.info("new client is connected " + socket.getInetAddress().getHostAddress());
68 | final InputStream incomingInputStream = socket.getInputStream();
69 | final OutputStream incomingOutputStream = socket.getOutputStream();
70 |
71 | final Socket outgoingSocket;
72 | try {
73 | outgoingSocket = new Socket("localhost", _destinationPort);
74 | } catch (Exception e) {
75 | LOG.warn("could not connect to " + _destinationPort);
76 | continue;
77 | }
78 | final InputStream outgoingInputStream = outgoingSocket.getInputStream();
79 | final OutputStream outgoingOutputStream = outgoingSocket.getOutputStream();
80 |
81 | Thread writeThread = new Thread() {
82 | @Override
83 | public void run() {
84 | runningThreads.add(this);
85 | try {
86 | int read = -1;
87 | while ((read = incomingInputStream.read()) != -1) {
88 | outgoingOutputStream.write(read);
89 | }
90 | } catch (IOException e) {
91 | // ignore
92 | } finally {
93 | closeQuietly(outgoingOutputStream);
94 | runningThreads.remove(this);
95 | }
96 | }
97 |
98 | @Override
99 | public void interrupt() {
100 | try {
101 | socket.close();
102 | outgoingSocket.close();
103 | } catch (IOException e) {
104 | LOG.error("error on stopping closing sockets", e);
105 | }
106 |
107 | super.interrupt();
108 | }
109 | };
110 |
111 | Thread readThread = new Thread() {
112 | @Override
113 | public void run() {
114 | runningThreads.add(this);
115 | try {
116 | int read = -1;
117 | while ((read = outgoingInputStream.read()) != -1) {
118 | incomingOutputStream.write(read);
119 | }
120 | } catch (IOException e) {
121 | // ignore
122 | } finally {
123 | closeQuietly(incomingOutputStream);
124 | runningThreads.remove(this);
125 | }
126 | }
127 | };
128 |
129 | writeThread.setDaemon(true);
130 | readThread.setDaemon(true);
131 |
132 | writeThread.start();
133 | readThread.start();
134 | }
135 | } catch (SocketException e) {
136 | if (!_running) {
137 | throw new RuntimeException(e);
138 | }
139 | LOG.info("Stopping gateway");
140 | } catch (Exception e) {
141 | LOG.error("error on gateway execution", e);
142 | }
143 |
144 | for (Thread thread : new ArrayList(runningThreads)) {
145 | thread.interrupt();
146 | try {
147 | thread.join();
148 | } catch (InterruptedException e) {
149 | // ignore
150 | }
151 | }
152 | }
153 |
154 | protected void closeQuietly(Closeable closable) {
155 | try {
156 | closable.close();
157 | } catch (IOException e) {
158 | // ignore
159 | }
160 | }
161 |
162 | @Override
163 | public void interrupt() {
164 | try {
165 | _serverSocket.close();
166 | } catch (Exception cE) {
167 | LOG.error("error on stopping gateway", cE);
168 | }
169 | super.interrupt();
170 | }
171 |
172 | public void interruptAndJoin() throws InterruptedException {
173 | interrupt();
174 | join();
175 | }
176 |
177 | public void awaitUp() {
178 | _lock.lock();
179 | try {
180 | while (!_running) {
181 | _runningCondition.await();
182 | }
183 | } catch (InterruptedException e) {
184 | Thread.currentThread().interrupt();
185 | } finally {
186 | _lock.unlock();
187 | }
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/src/test/java/com/github/zkclient/PortUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.zkclient;
2 |
3 |
4 | import java.io.IOException;
5 | import java.net.ServerSocket;
6 |
7 | /**
8 | * copy from https://github.com/adyliu/jafka/blob/master/src/test/java/com/sohu/jafka/PortUtils.java
9 | *
10 | * @author adyliu (imxylz@gmail.com)
11 | * @since 2013-04-25
12 | */
13 | public class PortUtils {
14 |
15 | public static int checkAvailablePort(int port) {
16 | while (port < 65500) {
17 | ServerSocket serverSocket = null;
18 | try {
19 | serverSocket = new ServerSocket(port);
20 | return port;
21 | } catch (IOException e) {
22 | //ignore error
23 | } finally {
24 | try {
25 | if (serverSocket != null)
26 | serverSocket.close();
27 | } catch (IOException e) {
28 | //ignore
29 | }
30 | }
31 | port++;
32 | }
33 | throw new RuntimeException("no available port");
34 | }
35 |
36 | public static void main(String[] args) {
37 | int port = checkAvailablePort(80);
38 | System.out.println("The available port is " + port);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/test/java/com/github/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 com.github.zkclient;
17 |
18 |
19 | import java.io.File;
20 | import java.io.IOException;
21 | import java.util.concurrent.Callable;
22 | import java.util.concurrent.TimeUnit;
23 |
24 | import org.junit.Ignore;
25 |
26 | import com.github.zkclient.ZkServer;
27 |
28 | @Ignore
29 | public class TestUtil {
30 |
31 | static {
32 | System.setProperty("zookeeper.preAllocSize", "1024");//1M data log
33 | }
34 | /**
35 | * This waits until the provided {@link Callable} returns an object that is equals to the given expected value or
36 | * the timeout has been reached. In both cases this method will return the return value of the latest
37 | * {@link Callable} execution.
38 | *
39 | * @param expectedValue
40 | * The expected value of the callable.
41 | * @param callable
42 | * The callable.
43 | * @param
44 | * The return type of the callable.
45 | * @param timeUnit
46 | * The timeout timeunit.
47 | * @param timeout
48 | * The timeout.
49 | * @return the return value of the latest {@link Callable} execution.
50 | * @throws Exception
51 | * @throws InterruptedException
52 | */
53 | public static T waitUntil(T expectedValue, Callable callable, TimeUnit timeUnit, long timeout) throws Exception {
54 | long startTime = System.currentTimeMillis();
55 | do {
56 | T actual = callable.call();
57 | if (expectedValue.equals(actual)) {
58 | return actual;
59 | }
60 | if (System.currentTimeMillis() > startTime + timeUnit.toMillis(timeout)) {
61 | return actual;
62 | }
63 | Thread.sleep(50);
64 | } while (true);
65 | }
66 |
67 | }
--------------------------------------------------------------------------------
/src/test/java/com/github/zkclient/ZkClientTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package com.github.zkclient;
5 |
6 | import com.github.zkclient.exception.ZkNoNodeException;
7 | import org.apache.zookeeper.CreateMode;
8 | import org.apache.zookeeper.Watcher.Event.KeeperState;
9 | import org.apache.zookeeper.data.Stat;
10 | import org.junit.After;
11 | import org.junit.AfterClass;
12 | import org.junit.Before;
13 | import org.junit.Test;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 |
17 | import java.io.File;
18 | import java.io.IOException;
19 | import java.io.UnsupportedEncodingException;
20 | import java.util.ArrayList;
21 | import java.util.List;
22 | import java.util.concurrent.Callable;
23 | import java.util.concurrent.TimeUnit;
24 | import java.util.concurrent.atomic.AtomicInteger;
25 | import java.util.concurrent.locks.LockSupport;
26 |
27 | import static org.junit.Assert.assertArrayEquals;
28 | import static org.junit.Assert.assertEquals;
29 | import static org.junit.Assert.assertFalse;
30 | import static org.junit.Assert.assertNull;
31 | import static org.junit.Assert.assertTrue;
32 | import static org.junit.Assert.fail;
33 |
34 | /**
35 | * @author adyliu (imxylz@gmail.com)
36 | * @since 2012-12-3
37 | */
38 | public class ZkClientTest {
39 | static {
40 | System.setProperty("zookeeper.preAllocSize", "1024");// 1M data log
41 | }
42 |
43 | final Logger logger = LoggerFactory.getLogger(ZkClientTest.class);
44 | private static final AtomicInteger counter = new AtomicInteger();
45 | //
46 | private ZkServer server;
47 | private ZkClient client;
48 | final int TIMEOUT = 30;//30 second for loop timeout
49 |
50 | //
51 | private static void deleteFile(File f) throws IOException {
52 | if (f.isFile()) {
53 | f.delete();
54 | //System.out.println("[DELETE FILE] "+f.getPath());
55 | } else if (f.isDirectory()) {
56 | File[] files = f.listFiles();
57 | if (files != null) {
58 | for (File fs : files) {
59 | deleteFile(fs);
60 | }
61 | }
62 | f.delete();
63 | //System.out.println("[DELETE DIRECTORY] "+f.getPath());
64 | }
65 | }
66 |
67 | private static ZkServer startZkServer(String testName, int port) throws IOException {
68 | String dataPath = "build/test/" + testName + "/data";
69 | String logPath = "build/test/" + testName + "/log";
70 | File dataDir = new File(".", dataPath).getCanonicalFile();
71 | File logDir = new File(".", logPath).getCanonicalFile();
72 | deleteFile(dataDir);
73 | deleteFile(logDir);
74 | //start the server with 100ms session timeout
75 | ZkServer zkServer = new ZkServer(dataDir.getPath(), logDir.getPath(), port, ZkServer.DEFAULT_TICK_TIME, 100);
76 | zkServer.start();
77 | return zkServer;
78 | }
79 |
80 | @AfterClass
81 | public static void cleanup() throws IOException {
82 | deleteFile(new File(".", "build/test").getCanonicalFile());
83 | }
84 |
85 | @Before
86 | public void setUp() throws Exception {
87 | this.server = startZkServer("server_" + counter.incrementAndGet(), 4711);
88 | this.client = this.server.getZkClient();
89 | assertTrue(this.client.isConnected());
90 | }
91 |
92 | @After
93 | public void tearDown() throws Exception {
94 | if (this.server != null) {
95 | this.server.shutdown();
96 | }
97 | }
98 |
99 | /**
100 | * Test method for
101 | * {@link com.github.zkclient.ZkClient#subscribeChildChanges(java.lang.String, com.github.zkclient.IZkChildListener)}
102 | * .
103 | */
104 | @Test
105 | public void testSubscribeChildChanges() throws Exception {
106 | final String path = "/a";
107 | final AtomicInteger count = new AtomicInteger(0);
108 | final ArrayList children = new ArrayList();
109 | IZkChildListener listener = new IZkChildListener() {
110 | public void handleChildChange(String parentPath, List currentChildren) throws Exception {
111 | count.incrementAndGet();
112 | children.clear();
113 | if (currentChildren != null)
114 | children.addAll(currentChildren);
115 | logger.info("handle childchange " + parentPath + ", " + currentChildren);
116 | }
117 | };
118 | //
119 | client.subscribeChildChanges(path, listener);
120 | //
121 | logger.info("create the watcher node " + path);
122 | client.createPersistent(path);
123 | //wait some time to make sure the event was triggered
124 | TestUtil.waitUntil(1, new Callable() {
125 | @Override
126 | public Integer call() throws Exception {
127 | return count.get();
128 | }
129 | }, TimeUnit.SECONDS, TIMEOUT);
130 | //
131 | assertEquals(1, count.get());
132 | assertEquals(0, children.size());
133 | //
134 | //create a child node
135 | count.set(0);
136 | client.createPersistent(path + "/child1");
137 | logger.info("create the first child node " + path + "/child1");
138 | TestUtil.waitUntil(1, new Callable() {
139 | @Override
140 | public Integer call() throws Exception {
141 | return count.get();
142 | }
143 | }, TimeUnit.SECONDS, TIMEOUT);
144 | //
145 | assertEquals(1, count.get());
146 | assertEquals(1, children.size());
147 | assertEquals("child1", children.get(0));
148 | //
149 | // create another child node and delete the node
150 | count.set(0);
151 | logger.info("create the second child node " + path + "/child2");
152 | client.createPersistent(path + "/child2");
153 | //
154 | logger.info("delete the watcher node " + path);
155 | client.deleteRecursive(path);
156 | //
157 | Boolean eventReceived = TestUtil.waitUntil(true, new Callable() {
158 | @Override
159 | public Boolean call() throws Exception {
160 | return count.get() > 0 && children.size() == 0;
161 | }
162 | }, TimeUnit.SECONDS, TIMEOUT);
163 | assertTrue(eventReceived);
164 | assertEquals(0, children.size());
165 | // ===========================================
166 | // do it again and check the listener validate
167 | // ===========================================
168 | count.set(0);
169 | //
170 | logger.info("create the watcher node again " + path);
171 | client.createPersistent(path);
172 | //
173 | eventReceived = TestUtil.waitUntil(true, new Callable() {
174 | @Override
175 | public Boolean call() throws Exception {
176 | return count.get() > 0;
177 | }
178 | }, TimeUnit.SECONDS, TIMEOUT);
179 | assertTrue(eventReceived);
180 | assertEquals(0, children.size());
181 | //
182 | // now create the first node
183 | count.set(0);
184 | final String child3 = "/child3";
185 | client.createPersistent(path + child3);
186 | logger.info("create the first child node again " + path + child3);
187 | //
188 | eventReceived = TestUtil.waitUntil(true, new Callable() {
189 | @Override
190 | public Boolean call() throws Exception {
191 | return count.get() > 0;
192 | }
193 | }, TimeUnit.SECONDS, 15);
194 | assertTrue(eventReceived);
195 | assertEquals(1, children.size());
196 | assertEquals("child3", children.get(0));
197 | //
198 | // delete root node
199 | count.set(0);
200 | logger.info("delete the watcher node again " + path);
201 | client.deleteRecursive(path);
202 | // This will receive two message: (1) child was deleted (2) parent was deleted
203 | //
204 | eventReceived = TestUtil.waitUntil(true, new Callable() {
205 | @Override
206 | public Boolean call() throws Exception {
207 | return children.isEmpty();
208 | }
209 | }, TimeUnit.SECONDS, TIMEOUT);
210 | assertTrue(eventReceived);
211 | assertTrue(children.isEmpty());
212 | }
213 |
214 | static class Holder {
215 | T t;
216 |
217 | public void set(T t) {
218 | this.t = t;
219 | }
220 |
221 | public T get() {
222 | return t;
223 | }
224 | }
225 |
226 | static byte[] toBytes(String s) {
227 | try {
228 | return s != null ? s.getBytes("UTF-8") : null;
229 | } catch (UnsupportedEncodingException e) {
230 | throw new RuntimeException(e);
231 | }
232 | }
233 |
234 | static String toString(byte[] b) {
235 | try {
236 | return b != null ? new String(b, "UTF-8") : null;
237 | } catch (UnsupportedEncodingException e) {
238 | throw new RuntimeException(e);
239 | }
240 | }
241 |
242 | /**
243 | * Test method for
244 | * {@link com.github.zkclient.ZkClient#subscribeDataChanges(java.lang.String, com.github.zkclient.IZkDataListener)}
245 | * .
246 | */
247 | @Test
248 | public void testSubscribeDataChanges() throws Exception {
249 | String path = "/a";
250 | final AtomicInteger countChanged = new AtomicInteger(0);
251 | final AtomicInteger countDeleted = new AtomicInteger(0);
252 | final Holder holder = new Holder();
253 | IZkDataListener listener = new IZkDataListener() {
254 | public void handleDataDeleted(String dataPath) throws Exception {
255 | countDeleted.incrementAndGet();
256 | holder.set(null);
257 | }
258 |
259 | public void handleDataChange(String dataPath, byte[] data) throws Exception {
260 | countChanged.incrementAndGet();
261 | holder.set(ZkClientTest.toString(data));
262 | }
263 | };
264 | client.subscribeDataChanges(path, listener);
265 | //
266 | // create the node
267 | client.createPersistent(path, toBytes("aaa"));
268 | //
269 | //wait some time to make sure the event was triggered
270 | TestUtil.waitUntil(1, new Callable() {
271 | @Override
272 | public Integer call() throws Exception {
273 | return countChanged.get();
274 | }
275 | }, TimeUnit.SECONDS, TIMEOUT);
276 | assertEquals(1, countChanged.get());
277 | assertEquals(0, countDeleted.get());
278 | assertEquals("aaa", holder.get());
279 | //
280 | countChanged.set(0);
281 | countDeleted.set(0);
282 | //
283 | client.delete(path);
284 | TestUtil.waitUntil(1, new Callable() {
285 | @Override
286 | public Integer call() throws Exception {
287 | return countDeleted.get();
288 | }
289 | }, TimeUnit.SECONDS, TIMEOUT);
290 | assertEquals(0, countChanged.get());
291 | assertEquals(1, countDeleted.get());
292 | assertNull(holder.get());
293 | // ===========================================
294 | // do it again and check the listener validate
295 | // ===========================================
296 | countChanged.set(0);
297 | countDeleted.set(0);
298 | client.createPersistent(path, toBytes("bbb"));
299 | TestUtil.waitUntil(1, new Callable() {
300 | @Override
301 | public Integer call() throws Exception {
302 | return countChanged.get();
303 | }
304 | }, TimeUnit.SECONDS, TIMEOUT);
305 | assertEquals(1, countChanged.get());
306 | assertEquals("bbb", holder.get());
307 | //
308 | countChanged.set(0);
309 | client.writeData(path, toBytes("ccc"));
310 | //
311 | TestUtil.waitUntil(1, new Callable() {
312 | @Override
313 | public Integer call() throws Exception {
314 | return countChanged.get();
315 | }
316 | }, TimeUnit.SECONDS, TIMEOUT);
317 | assertEquals(1, countChanged.get());
318 | assertEquals("ccc", holder.get());
319 | }
320 |
321 |
322 | /**
323 | * Test method for
324 | * {@link com.github.zkclient.ZkClient#createPersistent(java.lang.String, boolean)}
325 | * .
326 | */
327 | @Test
328 | public void testCreatePersistent() {
329 | final String path = "/a/b";
330 | try {
331 | client.createPersistent(path, false);
332 | fail("should throw exception");
333 | } catch (ZkNoNodeException e) {
334 | assertFalse(client.exists(path));
335 | }
336 | client.createPersistent(path, true);
337 | assertTrue(client.exists(path));
338 | }
339 |
340 | /**
341 | * Test method for
342 | * {@link com.github.zkclient.ZkClient#createPersistent(java.lang.String, byte[])}
343 | * .
344 | */
345 | @Test
346 | public void testCreatePersistentStringByteArray() {
347 | String path = "/a";
348 | client.createPersistent(path, toBytes("abc"));
349 | assertEquals("abc", toString(client.readData(path)));
350 | //
351 | }
352 |
353 | /**
354 | * Test method for
355 | * {@link com.github.zkclient.ZkClient#createPersistentSequential(java.lang.String, byte[])}
356 | * .
357 | */
358 | @Test
359 | public void testCreatePersistentSequential() {
360 | String path = "/a";
361 | String npath = client.createPersistentSequential(path, toBytes("abc"));
362 | assertTrue(npath != null && npath.length() > 0);
363 | npath = client.createPersistentSequential(path, toBytes("abc"));
364 | assertEquals("abc", toString(client.readData(npath)));
365 | }
366 |
367 | /**
368 | * Test method for
369 | * {@link com.github.zkclient.ZkClient#createEphemeral(java.lang.String)}.
370 | */
371 | @Test
372 | public void testCreateEphemeralString() {
373 | String path = "/a";
374 | client.createEphemeral(path);
375 | Stat stat = new Stat();
376 | client.readData(path, stat);
377 | assertTrue(stat.getEphemeralOwner() > 0);
378 | }
379 |
380 | /**
381 | * Test method for
382 | * {@link com.github.zkclient.ZkClient#create(java.lang.String, byte[], org.apache.zookeeper.CreateMode)}
383 | * .
384 | */
385 | @Test
386 | public void testCreate() {
387 | String path = "/a";
388 | client.create(path, toBytes("abc"), CreateMode.PERSISTENT);
389 | assertEquals("abc", toString(client.readData(path)));
390 | }
391 |
392 |
393 | @Test
394 | public void testCreateEphemeralSequential() {
395 | String path = "/a";
396 | String npath = client.createEphemeralSequential(path, toBytes("abc"));
397 | assertTrue(npath != null && npath.startsWith("/a"));
398 | Stat stat = new Stat();
399 | assertArrayEquals(toBytes("abc"), client.readData(npath, stat));
400 | assertTrue(stat.getEphemeralOwner() > 0);
401 | }
402 |
403 |
404 | /**
405 | * Test method for
406 | * {@link com.github.zkclient.ZkClient#getChildren(java.lang.String)}.
407 | */
408 | @Test
409 | public void testGetChildrenString() {
410 | String path = "/a";
411 | client.createPersistent(path + "/ch1", true);
412 | client.createPersistent(path + "/ch2");
413 | client.createPersistent(path + "/ch3");
414 | List children = client.getChildren(path);
415 | assertEquals(3, children.size());
416 | assertEquals(3, client.countChildren(path));
417 | assertNull(client.getChildren("/aaa"));
418 | }
419 |
420 |
421 | /**
422 | * Test method for
423 | * {@link com.github.zkclient.ZkClient#exists(java.lang.String)}.
424 | */
425 | @Test
426 | public void testExistsString() {
427 | String path = "/a";
428 | assertFalse(client.exists(path));
429 | client.createPersistent(path);
430 | assertTrue(client.exists(path));
431 | client.delete(path);
432 | assertFalse(client.exists(path));
433 | }
434 |
435 | /**
436 | * Test method for
437 | * {@link com.github.zkclient.ZkClient#deleteRecursive(java.lang.String)}.
438 | */
439 | @Test
440 | public void testDeleteRecursive() {
441 | String path = "/a/b/c";
442 | client.createPersistent(path, true);
443 | assertTrue(client.exists(path));
444 | assertTrue(client.deleteRecursive("/a"));
445 | assertFalse(client.exists(path));
446 | assertFalse(client.exists("/a/b"));
447 | assertFalse(client.exists("/a"));
448 | }
449 |
450 | /**
451 | * Test method for
452 | * {@link com.github.zkclient.ZkClient#waitUntilExists(java.lang.String, java.util.concurrent.TimeUnit, long)}
453 | * .
454 | */
455 | @Test
456 | public void testWaitUntilExists() {
457 | final String path = "/a";
458 | new Thread() {
459 | public void run() {
460 | LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
461 | client.createPersistent(path);
462 | }
463 | }.start();
464 | assertTrue(client.waitUntilExists(path, TimeUnit.SECONDS, 10));
465 | assertTrue(client.exists(path));
466 | //
467 | assertFalse(client.waitUntilExists("/notexists", TimeUnit.SECONDS, 1));
468 | }
469 |
470 | /**
471 | * Test method for {@link com.github.zkclient.ZkClient#waitUntilConnected()}
472 | * .
473 | */
474 | @Test
475 | public void testWaitUntilConnected() {
476 | ZkClient client2 = new ZkClient("localhost:4711", 15000);
477 | assertTrue(client2.waitUntilConnected());
478 | server.shutdown();
479 | //
480 | assertTrue(client2.waitForKeeperState(KeeperState.Disconnected, 1, TimeUnit.SECONDS));
481 | //
482 | assertFalse(client2.waitUntilConnected(1, TimeUnit.SECONDS));
483 | client2.close();
484 | }
485 |
486 |
487 | /**
488 | * Test method for
489 | * {@link com.github.zkclient.ZkClient#readData(java.lang.String, org.apache.zookeeper.data.Stat)}
490 | * .
491 | */
492 | @Test
493 | public void testReadDataStringStat() {
494 | client.createPersistent("/a", "data".getBytes());
495 | Stat stat = new Stat();
496 | client.readData("/a", stat);
497 | assertEquals(0, stat.getVersion());
498 | assertTrue(stat.getDataLength() > 0);
499 | }
500 |
501 |
502 | /**
503 | * Test method for {@link com.github.zkclient.ZkClient#numberOfListeners()}.
504 | */
505 | @Test
506 | public void testNumberOfListeners() {
507 | IZkChildListener zkChildListener = new AbstractListener() {
508 | };
509 | client.subscribeChildChanges("/", zkChildListener);
510 | assertEquals(1, client.numberOfListeners());
511 | //
512 | IZkDataListener zkDataListener = new AbstractListener() {
513 | };
514 | client.subscribeDataChanges("/a", zkDataListener);
515 | assertEquals(2, client.numberOfListeners());
516 | //
517 | client.subscribeDataChanges("/b", zkDataListener);
518 | assertEquals(3, client.numberOfListeners());
519 | //
520 | IZkStateListener zkStateListener = new AbstractListener() {
521 | };
522 | client.subscribeStateChanges(zkStateListener);
523 | assertEquals(4, client.numberOfListeners());
524 | //
525 | client.unsubscribeChildChanges("/", zkChildListener);
526 | assertEquals(3, client.numberOfListeners());
527 | //
528 | client.unsubscribeAll();
529 | assertEquals(0, client.numberOfListeners());
530 | }
531 |
532 | /**
533 | * Test method for {@link com.github.zkclient.ZkClient#getZooKeeper()}.
534 | */
535 | @Test
536 | public void testGetZooKeeper() {
537 | assertTrue(client.getZooKeeper() != null);
538 | }
539 |
540 | @Test
541 | public void testRetryUnitConnected_SessionExpiredException() {
542 | int sessionTimeout = 200;
543 | int port = PortUtils.checkAvailablePort(4712);
544 | int dport = this.server.getPort();
545 | Gateway gateway = new Gateway(port, dport);
546 | gateway.start();
547 | //
548 | final ZkClient client2 = new ZkClient("localhost:" + port, sessionTimeout, 15000);
549 | gateway.stop();
550 | //
551 | //start the server after 600ms
552 | new DeferredGatewayStarter(gateway, sessionTimeout * 3).start();
553 | //
554 | final Boolean connected = client2.retryUntilConnected(new Callable() {
555 | @Override
556 | public Boolean call() throws Exception {
557 | client2.createPersistent("/abc");
558 | return Boolean.TRUE;
559 | }
560 | });
561 | assertTrue(connected);
562 | assertTrue(client2.exists("/abc"));
563 | client2.close();
564 | gateway.stop();
565 | //
566 | }
567 |
568 |
569 | @Test
570 | public void testChildListenerAfterSessionExpiredException() throws Exception {
571 | final int sessionTimeout = 200;
572 | ZkClient connectedClient = server.getZkClient();
573 | connectedClient.createPersistent("/root");
574 | //
575 | int port = PortUtils.checkAvailablePort(4712);
576 | int dport = this.server.getPort();
577 | Gateway gateway = new Gateway(port, dport);
578 | gateway.start();
579 | //
580 | final ZkClient disconnectedClient = new ZkClient("localhost:" + port, sessionTimeout, 15000);
581 | final Holder> children = new Holder>();
582 | disconnectedClient.subscribeChildChanges("/root", new IZkChildListener() {
583 |
584 | @Override
585 | public void handleChildChange(String parentPath, List currentChildren) throws Exception {
586 | children.set(currentChildren);
587 | }
588 | });
589 | gateway.stop();//
590 | //
591 | // the connected client created a new child node
592 | connectedClient.createPersistent("/root/node1");
593 | //
594 | // wait for 3x sessionTImeout, the session should have expired
595 | Thread.sleep(3 * sessionTimeout);
596 | //
597 | // now start the gateway
598 | gateway.start();
599 | //
600 | Boolean hasOneChild = TestUtil.waitUntil(true, new Callable() {
601 | @Override
602 | public Boolean call() throws Exception {
603 | return children.get() != null && children.get().size() == 1;
604 | }
605 | }, TimeUnit.SECONDS, TIMEOUT);
606 | //
607 | assertTrue(hasOneChild);
608 | assertEquals("node1", children.get().get(0));
609 | assertEquals("node1", disconnectedClient.getChildren("/root").get(0));
610 | //
611 | disconnectedClient.close();
612 | gateway.stop();
613 | }
614 |
615 | }
616 |
--------------------------------------------------------------------------------
/src/test/java/com/github/zkclient/ZkClientUtilsTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package com.github.zkclient;
5 |
6 | import static org.junit.Assert.assertEquals;
7 |
8 | import org.junit.Test;
9 |
10 | /**
11 | *
12 | * @author adyliu(imxylz@gmail.com)
13 | * @since 2012-12-3
14 | */
15 | public class ZkClientUtilsTest {
16 |
17 | /**
18 | * Test method for
19 | * {@link com.github.zkclient.ZkClientUtils#leadingZeros(long, int)}.
20 | */
21 | @Test
22 | public void testLeadingZeros() {
23 | assertEquals("99", ZkClientUtils.leadingZeros(99, 1));
24 | assertEquals("99", ZkClientUtils.leadingZeros(99, 2));
25 | assertEquals("099", ZkClientUtils.leadingZeros(99, 3));
26 | assertEquals("0099", ZkClientUtils.leadingZeros(99, 4));
27 | assertEquals("00099", ZkClientUtils.leadingZeros(99, 5));
28 | assertEquals("0100", ZkClientUtils.leadingZeros(100, 4));
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/test/java/com/github/zkclient/ZkServerDemo.java:
--------------------------------------------------------------------------------
1 | package com.github.zkclient;
2 |
3 | import java.io.File;
4 | import java.util.Arrays;
5 |
6 | public class ZkServerDemo {
7 | public static void main(String[] args) throws Exception{
8 | File dataDir = new File("/tmp/zkdemo");
9 | dataDir.mkdirs();
10 | ZkServer server = new ZkServer(dataDir.getAbsolutePath(), dataDir.getAbsolutePath());
11 | server.start();
12 |
13 | ZkClient client = server.getZkClient();
14 | client.createPersistent("/a", true);
15 | byte[] dat = client.readData("/a");
16 | System.out.println(Arrays.toString(dat));
17 | client.writeData("/a", "OK".getBytes());
18 | System.out.println("agian="+Arrays.toString(dat));
19 | //server.shutdown();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, console
2 | log4j.logger.org.apache.zookeeper=WARN
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 |
--------------------------------------------------------------------------------