treeItem = iterator.next();
129 | if (treeItem.getValue()
130 | .getName()
131 | .equals(nodeName)) {
132 | ((ZkNodeTreeItem) treeItem).closeChildren();
133 | findItem = treeItem;
134 | }
135 | }
136 | if (findItem != null) {
137 |
138 | String path = findItem.getValue()
139 | .getPath();
140 |
141 | zkClientWrap.unsubscribeDataChanges(path);
142 | zkClientWrap.unsubscribeChildChanges(path);
143 |
144 | sources.remove(findItem);
145 | }
146 | }
147 |
148 | }
--------------------------------------------------------------------------------
/src/main/java/com/xin/view/conf/ProgressDialog.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2014, 2015 ControlsFX
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | * * Redistributions of source code must retain the above copyright
8 | * notice, this list of conditions and the following disclaimer.
9 | * * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * * Neither the name of ControlsFX, any associated website, nor the
13 | * names of its contributors may be used to endorse or promote products
14 | * derived from this software without specific prior written permission.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 | package com.xin.view.conf;
28 |
29 | import com.xin.ZkConfService.ZkConf;
30 | import com.xin.view.ZkConnectionTask;
31 | import com.xin.view.ZkExceptionDialog;
32 | import javafx.beans.property.SimpleObjectProperty;
33 | import javafx.beans.value.ChangeListener;
34 | import javafx.beans.value.ObservableValue;
35 | import javafx.concurrent.Task;
36 | import javafx.concurrent.Worker;
37 | import javafx.geometry.Insets;
38 | import javafx.geometry.Pos;
39 | import javafx.scene.control.Button;
40 | import javafx.scene.control.Dialog;
41 | import javafx.scene.control.DialogPane;
42 | import javafx.scene.control.Label;
43 | import javafx.scene.control.ProgressBar;
44 | import javafx.scene.layout.Region;
45 | import javafx.scene.layout.VBox;
46 | import javafx.stage.Window;
47 | import lombok.Getter;
48 | import lombok.extern.slf4j.Slf4j;
49 | import org.I0Itec.zkclient.MyZkClient;
50 |
51 | import java.util.function.Consumer;
52 |
53 | @Slf4j
54 | public class ProgressDialog extends Dialog {
55 |
56 | @Getter
57 | private final ZkConf zkConf;
58 | @Getter
59 | private Task worker;
60 |
61 | public ProgressDialog(String text, ZkConf zkConf, Consumer successRun) {
62 | this.zkConf = zkConf;
63 | final DialogPane dialogPane = getDialogPane();
64 |
65 | final Label space = new Label("");
66 | final Label progressMessag2e = new Label(text);
67 | space.setPadding(new Insets(0, 0, 1, 0));
68 |
69 | final WorkerProgressPane content = new WorkerProgressPane(this, successRun);
70 | worker = new ZkConnectionTask(zkConf);
71 | Thread th = new Thread(worker);
72 | th.start();
73 |
74 | content.setWorker(worker);
75 |
76 | VBox vbox = new VBox(10, progressMessag2e, space, content);
77 | vbox.setMaxWidth(Double.MAX_VALUE);
78 | vbox.setPrefSize(300, 80);
79 | /**
80 | * The content Text cannot be set before the constructor and since we
81 | * set a Content Node, the contentText will not be shown. If we want to
82 | * let the user display a content text, we must recreate it.
83 | */
84 | Button close = new Button("close");
85 | close.setPrefWidth(150);
86 | close.setOnMouseClicked(event -> {
87 | closeDialog();
88 | worker.cancel();
89 | });
90 | vbox.setAlignment(Pos.BASELINE_CENTER);
91 | vbox.getChildren()
92 | .add(close);
93 | dialogPane.setContent(vbox);
94 | Window window = getDialogPane().getScene()
95 | .getWindow();
96 | window.setOnCloseRequest(event -> {
97 | closeDialog();
98 | worker.cancel();
99 | });
100 | }
101 |
102 | public void closeDialog() {
103 | setResult(true);
104 | close();
105 | }
106 |
107 | /**************************************************************************
108 | *
109 | * Support classes
110 | *
111 | **************************************************************************/
112 |
113 | /**
114 | * The WorkerProgressPane takes a {@link Dialog} and a {@link Worker}
115 | * and links them together so the dialog is shown or hidden depending
116 | * on the state of the worker. The WorkerProgressPane also includes
117 | * a progress bar that is automatically bound to the progress property
118 | * of the worker. The way in which the WorkerProgressPane shows and
119 | * hides its worker's dialog is consistent with the expected behavior
120 | * for {@link #showWorkerProgress(Worker)}.
121 | */
122 | private static class WorkerProgressPane extends Region {
123 | private final Consumer successRun;
124 | private final ProgressDialog dialog;
125 | private final ProgressBar progressBar;
126 | private Worker> worker;
127 |
128 | // If the progress indicator changes, then we need to re-initialize
129 | // If the worker changes, we need to re-initialize
130 | private ChangeListener stateListener = new ChangeListener() {
131 | @Override
132 | public void changed(ObservableValue extends Worker.State> observable, Worker.State old, Worker.State value) {
133 | ZkConnectionTask zkConnectionTask = (ZkConnectionTask) ((SimpleObjectProperty) observable).getBean();
134 |
135 | switch (value) {
136 | case CANCELLED:
137 | end();
138 | return;
139 | case FAILED:
140 | end();
141 | new ZkExceptionDialog("连接失败!\n ", zkConnectionTask.getException()).showUi();
142 | log.warn("连接异常", zkConnectionTask.getException());
143 | return;
144 | case SUCCEEDED:
145 | end();
146 | successRun.accept(zkConnectionTask.getZkClient());
147 | break;
148 | case SCHEDULED:
149 | break;
150 | default: //no-op
151 | }
152 | }
153 | };
154 |
155 | public WorkerProgressPane(ProgressDialog dialog, Consumer successRun) {
156 | this.successRun = successRun;
157 | this.dialog = dialog;
158 |
159 | this.progressBar = new ProgressBar();
160 | progressBar.setMaxWidth(Double.MAX_VALUE);
161 | getChildren().add(progressBar);
162 |
163 | if (worker != null) {
164 | progressBar.progressProperty()
165 | .bind(worker.progressProperty());
166 | }
167 | }
168 |
169 | public final void setWorker(final Worker> newWorker) {
170 | if (newWorker != worker) {
171 | if (worker != null) {
172 | worker.stateProperty()
173 | .removeListener(stateListener);
174 | end();
175 | }
176 |
177 | worker = newWorker;
178 |
179 | if (newWorker != null) {
180 | newWorker.stateProperty()
181 | .addListener(stateListener);
182 | if (newWorker.getState() == Worker.State.RUNNING || newWorker.getState() == Worker.State.SCHEDULED) {
183 | // It is already running
184 | }
185 | }
186 | }
187 | }
188 |
189 | @Override
190 | protected void layoutChildren() {
191 | if (progressBar != null) {
192 | Insets insets = getInsets();
193 | double w = getWidth() - insets.getLeft() - insets.getRight();
194 | double h = getHeight() - insets.getTop() - insets.getBottom();
195 |
196 | double prefH = progressBar.prefHeight(-1);
197 | double x = insets.getLeft() + (w - w) / 2.0;
198 | double y = insets.getTop() + (h - prefH) / 2.0;
199 |
200 | progressBar.resizeRelocate(x, y, w, prefH);
201 | }
202 | }
203 |
204 | private void end() {
205 | progressBar.progressProperty()
206 | .unbind();
207 | dialog.closeDialog();
208 |
209 | }
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/src/main/java/com/xin/view/conf/SearchFilterObservalbeList.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
3 | * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4 | *
5 | *
6 | *
7 | *
8 | *
9 | *
10 | *
11 | *
12 | *
13 | *
14 | *
15 | *
16 | *
17 | *
18 | *
19 | *
20 | *
21 | *
22 | *
23 | *
24 | */
25 |
26 | package com.xin.view.conf;
27 |
28 | import com.sun.javafx.collections.NonIterableChange.GenericAddRemoveChange;
29 | import com.sun.javafx.collections.SortHelper;
30 | import javafx.beans.NamedArg;
31 | import javafx.beans.property.ObjectProperty;
32 | import javafx.beans.property.ObjectPropertyBase;
33 | import javafx.collections.ListChangeListener.Change;
34 | import javafx.collections.ObservableList;
35 | import javafx.collections.transformation.TransformationList;
36 |
37 | import java.util.ArrayList;
38 | import java.util.Arrays;
39 | import java.util.Iterator;
40 | import java.util.List;
41 | import java.util.ListIterator;
42 | import java.util.function.Predicate;
43 |
44 | /**
45 | * Wraps an ObservableList and filters it's content using the provided Predicate.
46 | * All changes in the ObservableList are propagated immediately
47 | * to the FilteredList.
48 | *
49 | * @see TransformationList
50 | * @since JavaFX 8.0
51 | */
52 | public final class SearchFilterObservalbeList extends TransformationList {
53 |
54 | private static final Predicate ALWAYS_TRUE = t -> true;
55 | private int[] filtered;
56 | private int size;
57 | private SortHelper helper;
58 | /**
59 | * The predicate that will match the elements that will be in this FilteredList.
60 | * Elements not matching the predicate will be filtered-out.
61 | * Null predicate means "always true" predicate, all elements will be matched.
62 | */
63 | private ObjectProperty> predicate;
64 |
65 | /**
66 | * Constructs a new FilteredList wrapper around the source list.
67 | * The provided predicate will match the elements in the source list that will be visible.
68 | * If the predicate is null, all elements will be matched and the list is equal to the source list.
69 | *
70 | * @param source the source list
71 | * @param predicate the predicate to match the elements or null to match all elements.
72 | */
73 | public SearchFilterObservalbeList(@NamedArg("source") ObservableList source, @NamedArg("predicate") Predicate super E> predicate) {
74 | super(source);
75 | filtered = new int[source.size() * 3 / 2 + 1];
76 | if (predicate != null) {
77 | setPredicate(predicate);
78 | } else {
79 | for (size = 0; size < source.size(); size++) {
80 | filtered[size] = size;
81 | }
82 | }
83 | }
84 |
85 | /**
86 | * Constructs a new FilteredList wrapper around the source list.
87 | * This list has an "always true" predicate, containing all the elements
88 | * of the source list.
89 | *
90 | * This constructor might be useful if you want to bind {@link #predicateProperty()}
91 | * of this list.
92 | *
93 | * @param source the source list
94 | */
95 | public SearchFilterObservalbeList(@NamedArg("source") ObservableList source) {
96 | this(source, null);
97 | }
98 |
99 | public final ObjectProperty> predicateProperty() {
100 | if (predicate == null) {
101 | predicate = new ObjectPropertyBase>() {
102 | @Override
103 | public Object getBean() {
104 | return SearchFilterObservalbeList.this;
105 | }
106 |
107 | @Override
108 | public String getName() {
109 | return "predicate";
110 | }
111 |
112 | @Override
113 | protected void invalidated() {
114 | refilter();
115 | }
116 |
117 | };
118 | }
119 | return predicate;
120 | }
121 |
122 | public final Predicate super E> getPredicate() {
123 | return predicate == null ? null : predicate.get();
124 | }
125 |
126 | public final void setPredicate(Predicate super E> predicate) {
127 | predicateProperty().set(predicate);
128 | }
129 |
130 | /**
131 | * Returns the number of elements in this list.
132 | *
133 | * @return the number of elements in this list
134 | */
135 | @Override
136 | public int size() {
137 | return size;
138 | }
139 |
140 | /**
141 | * Returns the element at the specified position in this list.
142 | *
143 | * @param index index of the element to return
144 | * @return the element at the specified position in this list
145 | * @throws IndexOutOfBoundsException {@inheritDoc}
146 | */
147 | @Override
148 | public E get(int index) {
149 | if (index >= size) {
150 | throw new IndexOutOfBoundsException();
151 | }
152 | return getSource().get(filtered[index]);
153 | }
154 |
155 | @Override
156 | public void add(int index, E element) {
157 | ObservableList source = (ObservableList) getSource();
158 | source.add(index, element);
159 | }
160 |
161 | @Override
162 | public E remove(int index) {
163 | ObservableList source = (ObservableList) getSource();
164 | return source.remove(index);
165 | }
166 |
167 | @SuppressWarnings("unchecked")
168 | public void refilter() {
169 | ensureSize(getSource().size());
170 | List removed = null;
171 | if (hasListeners()) {
172 | removed = new ArrayList<>(this);
173 | }
174 | size = 0;
175 | int i = 0;
176 | Predicate super E> pred = getPredicateImpl();
177 | for (Iterator extends E> it = getSource().iterator(); it.hasNext(); ) {
178 | final E next = it.next();
179 | if (pred.test(next)) {
180 | filtered[size++] = i;
181 | }
182 | ++i;
183 | }
184 | if (hasListeners()) {
185 | fireChange(new GenericAddRemoveChange<>(0, size, removed, this));
186 | }
187 | }
188 |
189 | @Override
190 | protected void sourceChanged(Change extends E> c) {
191 | beginChange();
192 | while (c.next()) {
193 | if (c.wasPermutated()) {
194 | permutate(c);
195 | } else if (c.wasUpdated()) {
196 | update(c);
197 | } else {
198 | addRemove(c);
199 | }
200 | }
201 | endChange();
202 | }
203 |
204 | @Override
205 | public int getSourceIndex(int index) {
206 | if (index >= size) {
207 | throw new IndexOutOfBoundsException();
208 | }
209 | return filtered[index];
210 | }
211 |
212 | private Predicate super E> getPredicateImpl() {
213 | if (getPredicate() != null) {
214 | return getPredicate();
215 | }
216 | return ALWAYS_TRUE;
217 | }
218 |
219 | private SortHelper getSortHelper() {
220 | if (helper == null) {
221 | helper = new SortHelper();
222 | }
223 | return helper;
224 | }
225 |
226 | private int findPosition(int p) {
227 | if (filtered.length == 0) {
228 | return 0;
229 | }
230 | if (p == 0) {
231 | return 0;
232 | }
233 | int pos = Arrays.binarySearch(filtered, 0, size, p);
234 | if (pos < 0) {
235 | pos = ~pos;
236 | }
237 | return pos;
238 | }
239 |
240 | @SuppressWarnings("unchecked")
241 | private void ensureSize(int size) {
242 | if (filtered.length < size) {
243 | int[] replacement = new int[size * 3 / 2 + 1];
244 | System.arraycopy(filtered, 0, replacement, 0, this.size);
245 | filtered = replacement;
246 | }
247 | }
248 |
249 | private void updateIndexes(int from, int delta) {
250 | for (int i = from; i < size; ++i) {
251 | filtered[i] += delta;
252 | }
253 | }
254 |
255 | private void permutate(Change extends E> c) {
256 | int from = findPosition(c.getFrom());
257 | int to = findPosition(c.getTo());
258 |
259 | if (to > from) {
260 | for (int i = from; i < to; ++i) {
261 | filtered[i] = c.getPermutation(filtered[i]);
262 | }
263 |
264 | int[] perm = getSortHelper().sort(filtered, from, to);
265 | nextPermutation(from, to, perm);
266 | }
267 | }
268 |
269 | private void addRemove(Change extends E> c) {
270 | Predicate super E> pred = getPredicateImpl();
271 | ensureSize(getSource().size());
272 | final int from = findPosition(c.getFrom());
273 | final int to = findPosition(c.getFrom() + c.getRemovedSize());
274 |
275 | // Mark the nodes that are going to be removed
276 | for (int i = from; i < to; ++i) {
277 | nextRemove(from, c.getRemoved()
278 | .get(filtered[i] - c.getFrom()));
279 | }
280 |
281 | // Update indexes of the sublist following the last element that was removed
282 | updateIndexes(to, c.getAddedSize() - c.getRemovedSize());
283 |
284 | // Replace as many removed elements as possible
285 | int fpos = from;
286 | int pos = c.getFrom();
287 |
288 | ListIterator extends E> it = getSource().listIterator(pos);
289 | for (; fpos < to && it.nextIndex() < c.getTo(); ) {
290 | if (pred.test(it.next())) {
291 | filtered[fpos] = it.previousIndex();
292 | nextAdd(fpos, fpos + 1);
293 | ++fpos;
294 | }
295 | }
296 |
297 | if (fpos < to) {
298 | // If there were more removed elements than added
299 | System.arraycopy(filtered, to, filtered, fpos, size - to);
300 | size -= to - fpos;
301 | } else {
302 | // Add the remaining elements
303 | while (it.nextIndex() < c.getTo()) {
304 | if (pred.test(it.next())) {
305 | System.arraycopy(filtered, fpos, filtered, fpos + 1, size - fpos);
306 | filtered[fpos] = it.previousIndex();
307 | nextAdd(fpos, fpos + 1);
308 | ++fpos;
309 | ++size;
310 | }
311 | ++pos;
312 | }
313 | }
314 | }
315 |
316 | private void update(Change extends E> c) {
317 | Predicate super E> pred = getPredicateImpl();
318 | ensureSize(getSource().size());
319 | int sourceFrom = c.getFrom();
320 | int sourceTo = c.getTo();
321 | int filterFrom = findPosition(sourceFrom);
322 | int filterTo = findPosition(sourceTo);
323 | ListIterator extends E> it = getSource().listIterator(sourceFrom);
324 | int pos = filterFrom;
325 | while (pos < filterTo || sourceFrom < sourceTo) {
326 | E el = it.next();
327 | if (pos < size && filtered[pos] == sourceFrom) {
328 | if (!pred.test(el)) {
329 | nextRemove(pos, el);
330 | System.arraycopy(filtered, pos + 1, filtered, pos, size - pos - 1);
331 | --size;
332 | --filterTo;
333 | } else {
334 | nextUpdate(pos);
335 | ++pos;
336 | }
337 | } else {
338 | if (pred.test(el)) {
339 | nextAdd(pos, pos + 1);
340 | System.arraycopy(filtered, pos, filtered, pos + 1, size - pos);
341 | filtered[pos] = sourceFrom;
342 | ++size;
343 | ++pos;
344 | ++filterTo;
345 | }
346 | }
347 | sourceFrom++;
348 | }
349 | }
350 |
351 | }
352 |
--------------------------------------------------------------------------------
/src/main/java/com/xin/view/conf/ZkConfListView.java:
--------------------------------------------------------------------------------
1 | package com.xin.view.conf;
2 |
3 | import com.xin.ZkClientWrap;
4 | import com.xin.ZkConfService;
5 | import com.xin.ZkConfService.ZkConf;
6 | import com.xin.view.tab.ZkTab;
7 | import javafx.event.EventHandler;
8 | import javafx.scene.control.*;
9 | import javafx.scene.input.MouseEvent;
10 | import javafx.util.Callback;
11 | import org.I0Itec.zkclient.MyZkClient;
12 |
13 | import java.util.function.Consumer;
14 |
15 | import static javafx.scene.input.MouseButton.PRIMARY;
16 |
17 | /**
18 | * test
19 | *
20 | * @author 497668869@qq.com
21 | * @since 1.0
22 | */
23 | public class ZkConfListView extends ListView {
24 |
25 | private Runnable connectTrigger;
26 |
27 | public ZkConfListView() {
28 |
29 | setCellFactory(new Callback, ListCell>() {
30 | @Override
31 | public ListCell call(ListView param) {
32 |
33 | EventHandler mouseEventEventHandler = event -> {
34 | getSelectionModel()
35 | .clearSelection();
36 | event.consume();
37 | };
38 |
39 | return new ListCell() {
40 | @Override
41 | protected void updateItem(ZkConf item, boolean empty) {
42 | super.updateItem(item, empty);
43 | if (!empty && item != null) {
44 | setContextMenu(getRightContextMenu());
45 | setText(item.toString());
46 | removeEventFilter(MouseEvent.MOUSE_CLICKED, mouseEventEventHandler);
47 | } else {
48 | setText("");
49 | setContextMenu(getCreateContextMenu());
50 | }
51 | }
52 | };
53 | }
54 | });
55 | }
56 |
57 | public void installConnectTrigger(TabPane connectTabPane) {
58 | this.connectTrigger = () -> {
59 | final ZkConf selectedItem = getSelectionModel().getSelectedItem();
60 | ProgressDialog progressDialog = new ProgressDialog(selectedItem + " 连接中...", selectedItem,
61 | new Consumer() {
62 | @Override
63 | public void accept(MyZkClient zkClient) {
64 | ZkTab tab = new ZkTab(selectedItem);
65 | connectTabPane.getScene()
66 | .getStylesheets()
67 | .add(getClass().getResource("/css/style.css")
68 | .toExternalForm());
69 | tab.init(new ZkClientWrap(zkClient, selectedItem.copy()));
70 | tab.setClosable(true);
71 | connectTabPane.setTabClosingPolicy(
72 | TabPane.TabClosingPolicy.SELECTED_TAB);
73 | connectTabPane.getTabs()
74 | .add(tab);
75 | connectTabPane.getSelectionModel()
76 | .select(tab);
77 | }
78 | });
79 | progressDialog.showAndWait();
80 | };
81 |
82 | setOnMouseClicked(mouseEvent -> {
83 | if (!PRIMARY.equals(mouseEvent.getButton()) || mouseEvent.getClickCount() != 2) {
84 | return;
85 | }
86 | if (getSelectionModel().getSelectedItem() == null) {
87 | return;
88 | }
89 | connectTrigger.run();
90 | });
91 | }
92 |
93 | private ContextMenu getCreateContextMenu() {
94 | MenuItem menuItem1 = new MenuItem("新增连接");
95 | menuItem1.setOnAction(event -> {
96 | ZkConfService.createSaveUi(null, this);
97 | });
98 |
99 | ContextMenu cm = new ContextMenu();
100 | cm.getItems()
101 | .add(menuItem1);
102 | return cm;
103 | }
104 |
105 | private ContextMenu getRightContextMenu() {
106 | MenuItem menuItem1 = new MenuItem("修改");
107 | menuItem1.setOnAction(event -> {
108 | ZkConf selectedItem = getSelectionModel()
109 | .getSelectedItem();
110 | ZkConfService.createSaveUi(selectedItem, this);
111 | });
112 |
113 | MenuItem menuItem2 = new MenuItem("删除");
114 | menuItem2.setOnAction(event -> {
115 | ZkConf selectedItem = getSelectionModel()
116 | .getSelectedItem();
117 | ZkConfService.getService()
118 | .removeZkConf(selectedItem, this);
119 | });
120 | ContextMenu cm = new ContextMenu();
121 | cm.getItems()
122 | .add(menuItem1);
123 | cm.getItems()
124 | .add(menuItem2);
125 | return cm;
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/main/java/com/xin/view/tab/ZkTab.java:
--------------------------------------------------------------------------------
1 | package com.xin.view.tab;
2 |
3 | import com.xin.ZkClientWrap;
4 | import com.xin.ZkConfService.ZkConf;
5 | import com.xin.view.NodeInfoEditProxy;
6 | import com.xin.view.zktreeview.SearchTextField;
7 | import com.xin.view.zktreeview.ZkTreeView;
8 | import javafx.fxml.FXMLLoader;
9 | import javafx.geometry.Insets;
10 | import javafx.scene.Node;
11 | import javafx.scene.Parent;
12 | import javafx.scene.control.*;
13 | import javafx.scene.layout.StackPane;
14 | import lombok.Getter;
15 | import lombok.extern.slf4j.Slf4j;
16 | import org.I0Itec.zkclient.IZkStateListener;
17 | import org.apache.zookeeper.Watcher;
18 | import org.controlsfx.control.MaskerPane;
19 |
20 | import java.io.IOException;
21 | import java.util.Arrays;
22 |
23 | /**
24 | * @author 497668869@qq.com
25 | * @since 1.0
26 | */
27 | @Slf4j
28 | @Getter
29 | public class ZkTab extends Tab {
30 | public static final String SPLIT_PANE = "#splitPane";
31 | private final ZkConf zkConf;
32 | private MaskerPane loadingMaskerPane = new MaskerPane();
33 | @Getter
34 | private ZkClientWrap zkClientWrap;
35 | private ZkTreeView treeView;
36 | private SearchTextField searchZkNodeTextField;
37 |
38 | private NodeInfoEditProxy nodeInfoEditProxy;
39 |
40 | public ZkTab(ZkConf zkConf) {
41 | super(zkConf.toString());
42 | this.zkConf = zkConf;
43 | }
44 |
45 | public void initField(Node contentNode, ZkClientWrap zkClientWrap) {
46 | Node node = ((SplitPane) contentNode.lookup(SPLIT_PANE)).getItems()
47 | .get(0);
48 | treeView = (ZkTreeView) node.lookup("#zkTreeView");
49 | searchZkNodeTextField = (SearchTextField) node.lookup("#searchZkNodeTextField");
50 |
51 | Node node1 = ((SplitPane) contentNode.lookup(SPLIT_PANE)).getItems()
52 | .get(1);
53 | TextArea zkNodeDataTextArea = (TextArea) node1.lookup("#zkNodeDataTextArea");
54 |
55 | TextField zkPathTextField = (TextField) node1.lookup("#zkPathTextField");
56 | TextArea zkNodeStatTextArea = (TextArea) node1.lookup("#zkNodeStatTextArea");
57 | Button reloadNodeValueButton = (Button) node1.lookup("#reloadNodeValueButton");
58 | Button saveNodeValueButton = (Button) node1.lookup("#saveNodeValueButton");
59 |
60 | Button commandStatButton = (Button) node1.lookup("#commandStat");
61 | Button commandRuokButton = (Button) node1.lookup("#commandRuok");
62 | // Button commandDumpButton = (Button) node1.lookup("#commandDump");
63 | Button commandSrvrButton = (Button) node1.lookup("#commandSrvr");
64 | Button commandConfButton = (Button) node1.lookup("#commandConf");
65 | Button commandEnviButton = (Button) node1.lookup("#commandEnvi");
66 | Button commandReqsButton = (Button) node1.lookup("#commandReqs");
67 | Button commandConsButton = (Button) node1.lookup("#commandCons");
68 | Button commandWchcButton = (Button) node1.lookup("#commandWchc");
69 | Button commandWchpButton = (Button) node1.lookup("#commandWchp");
70 | loadingMaskerPane.setVisible(false);
71 | loadingMaskerPane.setText(zkConf + " 连接异常, 重连中...");
72 | nodeInfoEditProxy = new NodeInfoEditProxy(zkClientWrap,
73 | zkNodeDataTextArea,
74 | zkPathTextField,
75 | zkNodeStatTextArea,
76 | reloadNodeValueButton,
77 | saveNodeValueButton,
78 | Arrays.asList(commandStatButton,
79 | commandRuokButton,
80 | // commandDumpButton,
81 | commandSrvrButton,
82 | commandConfButton,
83 | commandEnviButton,
84 | commandReqsButton,
85 | commandConsButton,
86 | commandWchcButton,
87 | commandWchpButton));
88 | nodeInfoEditProxy.init();
89 | }
90 |
91 | public void init(ZkClientWrap zkClientWrap) {
92 |
93 | try {
94 | Parent parent = buildUi(zkClientWrap);
95 |
96 | initField(parent, zkClientWrap);
97 |
98 | installZkStateChange(zkClientWrap);
99 |
100 | setOnCloseRequest(event -> zkClientWrap.close());
101 |
102 | treeView.init(this.zkClientWrap, searchZkNodeTextField, nodeInfoEditProxy);
103 |
104 | } catch (IOException e) {
105 | log.error("加载ui资源失败 /connectTab.fxml", e);
106 | return;
107 | }
108 | }
109 |
110 | private Parent buildUi(ZkClientWrap zkClientWrap) throws IOException {
111 | Parent parent;
112 | parent = FXMLLoader.load(getClass().getResource("/fxml/connectTab.fxml"));
113 |
114 | StackPane stackPane = new StackPane();
115 | stackPane.setPadding(new Insets(10, 0, 0, 0));
116 | stackPane.getChildren()
117 | .add(parent);
118 | stackPane.getChildren()
119 | .add(loadingMaskerPane);
120 |
121 | this.zkClientWrap = zkClientWrap;
122 | setContent(stackPane);
123 | return parent;
124 | }
125 |
126 | private void installZkStateChange(ZkClientWrap zkClientWrap) {
127 | zkClientWrap.subscribeStateChanges(new IZkStateListener() {
128 | @Override
129 | public void handleStateChanged(Watcher.Event.KeeperState state) throws Exception {
130 | if (state == Watcher.Event.KeeperState.SyncConnected) {
131 | //当我重新启动后start,监听触发
132 | log.info("重连成功 " + zkConf);
133 | loadingMaskerPane.setVisible(false);
134 | } else if (state == Watcher.Event.KeeperState.Disconnected) {
135 | loadingMaskerPane.setVisible(true);
136 | }
137 | }
138 |
139 | @Override
140 | public void handleNewSession() throws Exception {
141 | loadingMaskerPane.setVisible(false);
142 | }
143 |
144 | @Override
145 | public void handleSessionEstablishmentError(Throwable error) throws Exception {
146 | log.error("zk异常" + error);
147 | }
148 | });
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/src/main/java/com/xin/view/zktreeview/ArrowChangeListener.java:
--------------------------------------------------------------------------------
1 | package com.xin.view.zktreeview;
2 |
3 | import com.xin.ZkClientWrap;
4 | import com.xin.view.ZkNodeTreeItem;
5 | import javafx.application.Platform;
6 | import javafx.beans.value.ChangeListener;
7 | import javafx.beans.value.ObservableValue;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.I0Itec.zkclient.IZkChildListener;
10 |
11 | import java.util.List;
12 |
13 | /**
14 | * @author 497668869@qq.com
15 | * @since 1.0
16 | */
17 | @Slf4j
18 | public class ArrowChangeListener implements ChangeListener, IZkChildListener {
19 |
20 | private final ZkClientWrap zkClientWrap;
21 | private final ZkNodeTreeItem zkNodeTreeItem;
22 |
23 | public ArrowChangeListener(ZkClientWrap zkClientWrap, ZkNodeTreeItem zkNodeTreeItem) {
24 | this.zkClientWrap = zkClientWrap;
25 | this.zkNodeTreeItem = zkNodeTreeItem;
26 | }
27 |
28 | private void fire() {
29 | zkClientWrap.subscribeChildChanges(zkNodeTreeItem.getValue()
30 | .getPath(), this);
31 | List currentChilds = zkClientWrap.getChildren(zkNodeTreeItem.getValue()
32 | .getPath());
33 | zkNodeTreeItem.refreshByParent(currentChilds);
34 | }
35 |
36 | @Override
37 | public void changed(ObservableValue extends Boolean> observable, Boolean oldValue, Boolean newValue) {
38 | if (newValue) {
39 | fire();
40 | } else {
41 | zkClientWrap.unsubscribeChildChanges(zkNodeTreeItem.getValue()
42 | .getPath(), this);
43 | zkNodeTreeItem.closeChildren();
44 | }
45 | }
46 |
47 |
48 | @Override
49 | public void handleChildChange(String parentPath, List currentChilds) {
50 | //这个没有子节点, 可能是删除自己了
51 | if (currentChilds == null) {
52 | return;
53 | }
54 | Platform.runLater(() -> {
55 | zkNodeTreeItem.refreshByParent(currentChilds);
56 | });
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/xin/view/zktreeview/ChangeSelectDataChangeListener.java:
--------------------------------------------------------------------------------
1 | package com.xin.view.zktreeview;
2 |
3 | import com.xin.ZkClientWrap;
4 | import com.xin.ZkNode;
5 | import com.xin.view.NodeInfoEditProxy;
6 | import javafx.beans.value.ChangeListener;
7 | import javafx.beans.value.ObservableValue;
8 | import javafx.scene.control.TreeItem;
9 | import org.I0Itec.zkclient.IZkDataListener;
10 |
11 | /**
12 | * 监听zk树节点的焦点变化, 如果选择了其他节点需要出发显示右边界面的情况
13 | *
14 | * @author 497668869@qq.com
15 | * @since 1.0
16 | */
17 | public class ChangeSelectDataChangeListener implements ChangeListener> {
18 |
19 | private final ZkClientWrap zkClientWrap;
20 | private final NodeInfoEditProxy nodeInfoEditProxy;
21 |
22 | private IZkDataListener listener = new IZkDataListener() {
23 | @Override
24 | public void handleDataChange(String dataPath, Object data) {
25 | nodeInfoEditProxy.updateDate(dataPath);
26 | }
27 |
28 | @Override
29 | public void handleDataDeleted(String dataPath) {
30 | nodeInfoEditProxy.selectNoNode();
31 | }
32 | };
33 |
34 | ChangeSelectDataChangeListener(ZkClientWrap zkClientWrap, NodeInfoEditProxy nodeInfoEditProxy) {
35 | this.zkClientWrap = zkClientWrap;
36 | this.nodeInfoEditProxy = nodeInfoEditProxy;
37 | }
38 |
39 | @Override
40 | public void changed(ObservableValue extends TreeItem> observable, TreeItem oldValue, TreeItem newValue) {
41 | nodeInfoEditProxy.setCurrentTreeItem(newValue);
42 | if (oldValue != null) {
43 | zkClientWrap.unsubscribeDataChanges(oldValue.getValue()
44 | .getPath(), listener);
45 | }
46 | nodeInfoEditProxy.disabledComponent(newValue == null);
47 | if (newValue != null) {
48 | zkClientWrap.subscribeDataChanges(newValue.getValue()
49 | .getPath(), listener);
50 |
51 | nodeInfoEditProxy.updateDate(newValue.getValue()
52 | .getPath());
53 | }
54 |
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/xin/view/zktreeview/SearchTextField.java:
--------------------------------------------------------------------------------
1 | package com.xin.view.zktreeview;
2 |
3 | import javafx.animation.FadeTransition;
4 | import javafx.beans.InvalidationListener;
5 | import javafx.beans.Observable;
6 | import javafx.beans.property.ObjectProperty;
7 | import javafx.scene.Cursor;
8 | import javafx.scene.Node;
9 | import javafx.scene.control.TextField;
10 | import javafx.scene.input.KeyCode;
11 | import javafx.scene.layout.Region;
12 | import javafx.scene.layout.StackPane;
13 | import javafx.util.Duration;
14 | import org.controlsfx.control.textfield.CustomTextField;
15 | import org.controlsfx.validation.ValidationSupport;
16 | import org.controlsfx.validation.Validator;
17 | import org.controlsfx.validation.decoration.StyleClassValidationDecoration;
18 |
19 | /**
20 | * @author 497668869@qq.com
21 | * @since 1.0
22 | */
23 | public class SearchTextField extends CustomTextField {
24 |
25 | ValidationSupport validationSupport = new ValidationSupport();
26 |
27 | {
28 | validationSupport.setValidationDecorator(new StyleClassValidationDecoration());
29 | }
30 |
31 | public SearchTextField() {
32 | setupClearButtonField(this, this.rightProperty());
33 | setOnKeyPressed(event -> {
34 | if (event.getCode().equals(KeyCode.ESCAPE)) {
35 | setText("");
36 | }
37 | });
38 | }
39 |
40 | public void validate(Validator stringValidator) {
41 | validationSupport.registerValidator(this, stringValidator);
42 | }
43 |
44 | private static void setupClearButtonField(final TextField inputField, ObjectProperty rightProperty) {
45 | inputField.getStyleClass().add("clearable-field");
46 | Region clearButton = new Region();
47 | clearButton.getStyleClass().addAll(new String[]{"graphic"});
48 | StackPane clearButtonPane = new StackPane(new Node[]{clearButton});
49 | clearButtonPane.getStyleClass().addAll(new String[]{"clear-button"});
50 | clearButtonPane.setOpacity(0.0D);
51 | clearButtonPane.setCursor(Cursor.DEFAULT);
52 | clearButtonPane.setOnMouseReleased((e) -> {
53 | inputField.clear();
54 | });
55 | clearButtonPane.managedProperty().bind(inputField.editableProperty());
56 | clearButtonPane.visibleProperty().bind(inputField.editableProperty());
57 | rightProperty.set(clearButtonPane);
58 | final FadeTransition fader = new FadeTransition(Duration.millis(200), clearButtonPane);
59 | fader.setCycleCount(1);
60 | inputField.textProperty().addListener(new InvalidationListener() {
61 | public void invalidated(Observable arg0) {
62 | String text = inputField.getText();
63 | boolean isTextEmpty = text == null || text.isEmpty();
64 | boolean isButtonVisible = fader.getNode().getOpacity() > 0.0D;
65 | if (isTextEmpty && isButtonVisible) {
66 | this.setButtonVisible(false);
67 | } else if (!isTextEmpty && !isButtonVisible) {
68 | this.setButtonVisible(true);
69 | }
70 |
71 | }
72 |
73 | private void setButtonVisible(boolean visible) {
74 | fader.setFromValue(visible ? 0.0D : 1.0D);
75 | fader.setToValue(visible ? 1.0D : 0.0D);
76 | fader.play();
77 | }
78 | });
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/com/xin/view/zktreeview/TreeCellSkin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
3 | * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4 | *
5 | *
6 | *
7 | *
8 | *
9 | *
10 | *
11 | *
12 | *
13 | *
14 | *
15 | *
16 | *
17 | *
18 | *
19 | *
20 | *
21 | *
22 | *
23 | *
24 | */
25 |
26 | package com.xin.view.zktreeview;
27 |
28 | import com.sun.javafx.css.converters.SizeConverter;
29 | import com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler;
30 | import com.sun.javafx.scene.control.behavior.TreeCellBehavior;
31 | import com.sun.javafx.scene.control.skin.CellSkinBase;
32 | import javafx.beans.property.DoubleProperty;
33 | import javafx.beans.value.WritableValue;
34 | import javafx.css.CssMetaData;
35 | import javafx.css.Styleable;
36 | import javafx.css.StyleableDoubleProperty;
37 | import javafx.css.StyleableProperty;
38 | import javafx.geometry.HPos;
39 | import javafx.geometry.VPos;
40 | import javafx.scene.Node;
41 | import javafx.scene.control.TreeCell;
42 | import javafx.scene.control.TreeItem;
43 | import javafx.scene.control.TreeView;
44 | import javafx.scene.input.MouseButton;
45 |
46 | import java.util.ArrayList;
47 | import java.util.Collections;
48 | import java.util.List;
49 | import java.util.Map;
50 | import java.util.WeakHashMap;
51 |
52 | public class TreeCellSkin extends CellSkinBase, TreeCellBehavior> {
53 |
54 | /*
55 | * This is rather hacky - but it is a quick workaround to resolve the
56 | * issue that we don't know maximum width of a disclosure node for a given
57 | * TreeView. If we don't know the maximum width, we have no way to ensure
58 | * consistent indentation for a given TreeView.
59 | *
60 | * To work around this, we create a single WeakHashMap to store a max
61 | * disclosureNode width per TreeView. We use WeakHashMap to help prevent
62 | * any memory leaks.
63 | *
64 | * RT-19656 identifies a related issue, which is that we may not provide
65 | * indentation to any TreeItems because we have not yet encountered a cell
66 | * which has a disclosureNode. Once we scroll and encounter one, indentation
67 | * happens in a displeasing way.
68 | */
69 | private static final Map, Double> maxDisclosureWidthMap = new WeakHashMap, Double>();
70 |
71 | /**
72 | * The amount of space to multiply by the treeItem.level to get the left
73 | * margin for this tree cell. This is settable from CSS
74 | */
75 | private DoubleProperty indent = null;
76 | private boolean disclosureNodeDirty = true;
77 | private TreeItem> treeItem;
78 | private double fixedCellSize;
79 | private boolean fixedCellSizeEnabled;
80 | private MultiplePropertyChangeListenerHandler treeItemListener = new MultiplePropertyChangeListenerHandler(p -> {
81 | if ("EXPANDED".equals(p)) {
82 | updateDisclosureNodeRotation(true);
83 | }
84 | return null;
85 | });
86 |
87 | public TreeCellSkin(TreeCell control) {
88 | super(control, new TreeCellBehavior(control) {
89 | @Override
90 | protected void handleClicks(MouseButton button, int clickCount, boolean isAlreadySelected) {
91 | }
92 | });
93 |
94 | this.fixedCellSize = control.getTreeView()
95 | .getFixedCellSize();
96 | this.fixedCellSizeEnabled = fixedCellSize > 0;
97 |
98 | updateTreeItem();
99 | updateDisclosureNodeRotation(false);
100 |
101 | registerChangeListener(control.treeItemProperty(), "TREE_ITEM");
102 | registerChangeListener(control.textProperty(), "TEXT");
103 | registerChangeListener(control.getTreeView()
104 | .fixedCellSizeProperty(), "FIXED_CELL_SIZE");
105 | }
106 |
107 | /**
108 | * @return The CssMetaData associated with this class, which may include the
109 | * CssMetaData of its super classes.
110 | */
111 | public static List> getClassCssMetaData() {
112 | return StyleableProperties.STYLEABLES;
113 | }
114 |
115 | public final double getIndent() {
116 | return indent == null ? 10.0 : indent.get();
117 | }
118 |
119 | public final void setIndent(double value) {
120 | indentProperty().set(value);
121 | }
122 |
123 | public final DoubleProperty indentProperty() {
124 | if (indent == null) {
125 | indent = new StyleableDoubleProperty(10.0) {
126 | @Override
127 | public Object getBean() {
128 | return TreeCellSkin.this;
129 | }
130 |
131 | @Override
132 | public String getName() {
133 | return "indent";
134 | }
135 |
136 | @Override
137 | public CssMetaData, Number> getCssMetaData() {
138 | return StyleableProperties.INDENT;
139 | }
140 | };
141 | }
142 | return indent;
143 | }
144 |
145 | /**
146 | * {@inheritDoc}
147 | */
148 | @Override
149 | public List> getCssMetaData() {
150 | return getClassCssMetaData();
151 | }
152 |
153 | @Override
154 | protected void handleControlPropertyChanged(String p) {
155 | super.handleControlPropertyChanged(p);
156 | if ("TREE_ITEM".equals(p)) {
157 | updateTreeItem();
158 | disclosureNodeDirty = true;
159 | getSkinnable().requestLayout();
160 | } else if ("TEXT".equals(p)) {
161 | getSkinnable().requestLayout();
162 | } else if ("FIXED_CELL_SIZE".equals(p)) {
163 | this.fixedCellSize = getSkinnable().getTreeView()
164 | .getFixedCellSize();
165 | this.fixedCellSizeEnabled = fixedCellSize > 0;
166 | }
167 | }
168 |
169 | @Override
170 | protected void updateChildren() {
171 | super.updateChildren();
172 | updateDisclosureNode();
173 | }
174 |
175 | @Override
176 | protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
177 | if (fixedCellSizeEnabled) {
178 | return fixedCellSize;
179 | }
180 |
181 | double pref = super.computeMinHeight(width, topInset, rightInset, bottomInset, leftInset);
182 | Node d = getSkinnable().getDisclosureNode();
183 | return (d == null) ? pref : Math.max(d.minHeight(-1), pref);
184 | }
185 |
186 | @Override
187 | protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
188 | double labelWidth = super.computePrefWidth(height, topInset, rightInset, bottomInset, leftInset);
189 |
190 | double pw = snappedLeftInset() + snappedRightInset();
191 |
192 | TreeView tree = getSkinnable().getTreeView();
193 | if (tree == null) {
194 | return pw;
195 | }
196 |
197 | if (treeItem == null) {
198 | return pw;
199 | }
200 |
201 | pw = labelWidth;
202 |
203 | // determine the amount of indentation
204 | int level = tree.getTreeItemLevel(treeItem);
205 | if (!tree.isShowRoot()) {
206 | level--;
207 | }
208 | pw += getIndent() * level;
209 |
210 | // include the disclosure node width
211 | Node disclosureNode = getSkinnable().getDisclosureNode();
212 | double disclosureNodePrefWidth = disclosureNode == null ? 0 : disclosureNode.prefWidth(-1);
213 | final double defaultDisclosureWidth = maxDisclosureWidthMap.containsKey(tree) ?
214 | maxDisclosureWidthMap.get(tree) : 0;
215 | pw += Math.max(defaultDisclosureWidth, disclosureNodePrefWidth);
216 |
217 | return pw;
218 | }
219 |
220 | @Override
221 | protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
222 | if (fixedCellSizeEnabled) {
223 | return fixedCellSize;
224 | }
225 |
226 | final TreeCell cell = getSkinnable();
227 |
228 | final double pref = super.computePrefHeight(width, topInset, rightInset, bottomInset, leftInset);
229 | final Node d = cell.getDisclosureNode();
230 | final double prefHeight = (d == null) ? pref : Math.max(d.prefHeight(-1), pref);
231 |
232 | // RT-30212: TreeCell does not honor minSize of cells.
233 | // snapSize for RT-36460
234 | return snapSize(Math.max(cell.getMinHeight(), prefHeight));
235 | }
236 |
237 | @Override
238 | protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
239 | if (fixedCellSizeEnabled) {
240 | return fixedCellSize;
241 | }
242 |
243 | return super.computeMaxHeight(width, topInset, rightInset, bottomInset, leftInset);
244 | }
245 |
246 | @Override
247 | protected void layoutChildren(double x, final double y,
248 | double w, final double h) {
249 | // RT-25876: can not null-check here as this prevents empty rows from
250 | // being cleaned out.
251 | // if (treeItem == null) return;
252 |
253 | TreeView tree = getSkinnable().getTreeView();
254 | if (tree == null) {
255 | return;
256 | }
257 |
258 | if (disclosureNodeDirty) {
259 | updateDisclosureNode();
260 | disclosureNodeDirty = false;
261 | }
262 |
263 | Node disclosureNode = getSkinnable().getDisclosureNode();
264 |
265 | int level = tree.getTreeItemLevel(treeItem);
266 | if (!tree.isShowRoot()) {
267 | level--;
268 | }
269 | double leftMargin = getIndent() * level;
270 |
271 | x += leftMargin;
272 |
273 | // position the disclosure node so that it is at the proper indent
274 | boolean disclosureVisible = disclosureNode != null && treeItem != null;
275 |
276 | final double defaultDisclosureWidth = maxDisclosureWidthMap.containsKey(tree) ?
277 | maxDisclosureWidthMap.get(tree) : 18; // RT-19656: default width of default disclosure node
278 | double disclosureWidth = defaultDisclosureWidth;
279 |
280 | if (true) {
281 | if (disclosureNode == null || disclosureNode.getScene() == null) {
282 | updateChildren();
283 | }
284 |
285 | if (disclosureNode != null) {
286 | disclosureWidth = disclosureNode.prefWidth(h);
287 | if (disclosureWidth > defaultDisclosureWidth) {
288 | maxDisclosureWidthMap.put(tree, disclosureWidth);
289 | }
290 |
291 | double ph = disclosureNode.prefHeight(disclosureWidth);
292 |
293 | disclosureNode.resize(disclosureWidth, ph);
294 | positionInArea(disclosureNode, x, y,
295 | disclosureWidth, ph, /*baseline ignored*/0,
296 | HPos.CENTER, VPos.CENTER);
297 | }
298 | }
299 |
300 | // determine starting point of the graphic or cell node, and the
301 | // remaining width available to them
302 | final int padding = treeItem != null && treeItem.getGraphic() == null ? 0 : 3;
303 | x += disclosureWidth + padding;
304 | w -= (leftMargin + disclosureWidth + padding);
305 |
306 | // Rather ugly fix for RT-38519, where graphics are disappearing in
307 | // certain circumstances
308 | Node graphic = getSkinnable().getGraphic();
309 | if (graphic != null && !getChildren().contains(graphic)) {
310 | getChildren().add(graphic);
311 | }
312 |
313 | layoutLabelInArea(x, y, w, h);
314 | }
315 |
316 | private void updateDisclosureNodeRotation(boolean animate) {
317 | // no-op, this is now handled in CSS (although we no longer animate)
318 | // if (treeItem == null || treeItem.isLeaf()) return;
319 | //
320 | // Node disclosureNode = getSkinnable().getDisclosureNode();
321 | // if (disclosureNode == null) return;
322 | //
323 | // final boolean isExpanded = treeItem.isExpanded();
324 | // int fromAngle = isExpanded ? 0 : 90;
325 | // int toAngle = isExpanded ? 90 : 0;
326 | //
327 | // if (animate) {
328 | // RotateTransition rt = new RotateTransition(Duration.millis(200), disclosureNode);
329 | // rt.setFromAngle(fromAngle);
330 | // rt.setToAngle(toAngle);
331 | // rt.play();
332 | // } else {
333 | // disclosureNode.setRotate(toAngle);
334 | // }
335 | }
336 |
337 | /***************************************************************************
338 | * *
339 | * Stylesheet Handling *
340 | * *
341 | **************************************************************************/
342 |
343 | private void updateTreeItem() {
344 | if (treeItem != null) {
345 | treeItemListener.unregisterChangeListener(treeItem.expandedProperty());
346 | }
347 | treeItem = getSkinnable().getTreeItem();
348 | if (treeItem != null) {
349 | treeItemListener.registerChangeListener(treeItem.expandedProperty(), "EXPANDED");
350 | }
351 |
352 | updateDisclosureNodeRotation(false);
353 | }
354 |
355 | private void updateDisclosureNode() {
356 | if (getSkinnable().isEmpty()) {
357 | return;
358 | }
359 |
360 | Node disclosureNode = getSkinnable().getDisclosureNode();
361 | if (disclosureNode == null) {
362 | return;
363 | }
364 |
365 | boolean disclosureVisible = treeItem != null;
366 | disclosureNode.setVisible(disclosureVisible);
367 |
368 | if (!disclosureVisible) {
369 | getChildren().remove(disclosureNode);
370 | } else if (disclosureNode.getParent() == null) {
371 | getChildren().add(disclosureNode);
372 | disclosureNode.toFront();
373 | } else {
374 | disclosureNode.toBack();
375 | }
376 |
377 | // RT-26625: [TreeView, TreeTableView] can lose arrows while scrolling
378 | // RT-28668: Ensemble tree arrow disappears
379 | if (disclosureNode.getScene() != null) {
380 | disclosureNode.applyCss();
381 | }
382 | }
383 |
384 | /**
385 | * @treatAsPrivate
386 | */
387 | private static class StyleableProperties {
388 |
389 | private static final CssMetaData, Number> INDENT =
390 | new CssMetaData, Number>("-fx-indent",
391 | SizeConverter.getInstance(), 10.0) {
392 |
393 | @Override
394 | public boolean isSettable(TreeCell> n) {
395 | DoubleProperty p = ((TreeCellSkin>) n.getSkin()).indentProperty();
396 | return p == null || !p.isBound();
397 | }
398 |
399 | @Override
400 | public StyleableProperty getStyleableProperty(TreeCell> n) {
401 | final TreeCellSkin> skin = (TreeCellSkin>) n.getSkin();
402 | return (StyleableProperty) (WritableValue) skin.indentProperty();
403 | }
404 | };
405 |
406 | private static final List> STYLEABLES;
407 |
408 | static {
409 | final List> styleables =
410 | new ArrayList>(CellSkinBase.getClassCssMetaData());
411 | styleables.add(INDENT);
412 | STYLEABLES = Collections.unmodifiableList(styleables);
413 | }
414 | }
415 | }
416 |
--------------------------------------------------------------------------------
/src/main/java/com/xin/view/zktreeview/ZkNodeTreeCell.java:
--------------------------------------------------------------------------------
1 | package com.xin.view.zktreeview;
2 |
3 | import com.xin.ZkClientWrap;
4 | import com.xin.ZkNode;
5 | import com.xin.controller.NodeAddController;
6 | import javafx.event.ActionEvent;
7 | import javafx.event.EventDispatcher;
8 | import javafx.event.EventHandler;
9 | import javafx.fxml.FXMLLoader;
10 | import javafx.scene.Parent;
11 | import javafx.scene.Scene;
12 | import javafx.scene.control.*;
13 | import javafx.scene.input.MouseButton;
14 | import javafx.scene.input.MouseEvent;
15 | import javafx.scene.paint.Color;
16 | import javafx.stage.Modality;
17 | import javafx.stage.Stage;
18 | import lombok.extern.slf4j.Slf4j;
19 |
20 | import java.io.IOException;
21 | import java.util.Optional;
22 |
23 | import static javafx.scene.input.MouseEvent.MOUSE_PRESSED;
24 |
25 | /**
26 | * @author 497668869@qq.com
27 | * @since 1.0
28 | */
29 | @Slf4j
30 | public class ZkNodeTreeCell extends TreeCell {
31 | private final ZkTreeView zkTreeView;
32 | private final ZkClientWrap zkClientWrap;
33 | EventHandler mouseEventEventHandler = event -> {
34 | getSelectionModel().clearSelection();
35 | event.consume();
36 | };
37 | private EventHandler deleteNodeAction = getDeleteNodeAction();
38 | private EventHandler addNodeAction = getAddNodeAction();
39 | private EventHandler expandNodeAction = getExpandNodeAction();
40 | private EventHandler unExpandNodeAction = getUnExpandNodeAction();
41 |
42 | public ZkNodeTreeCell(ZkTreeView zkTreeView, ZkClientWrap zkClientWrap) {
43 | this.zkTreeView = zkTreeView;
44 | this.zkClientWrap = zkClientWrap;
45 | }
46 |
47 | public boolean deleteZkNode(TreeItem zkNodeTreeItem) {
48 | log.info("准备删除节点 " + zkNodeTreeItem.getValue()
49 | .getPath());
50 | try {
51 | return zkClientWrap.deleteRecursive(zkNodeTreeItem.getValue()
52 | .getPath());
53 | } catch (Exception e) {
54 | log.error("删除节点失败 ", e);
55 | }
56 |
57 | return false;
58 | }
59 |
60 | @Override
61 | protected void updateItem(ZkNode item, boolean empty) {
62 | super.updateItem(item, empty);
63 |
64 | if (empty || getIndex() < 0) {
65 | setText(null);
66 | setGraphic(null);
67 | addEventFilter(MouseEvent.MOUSE_CLICKED, mouseEventEventHandler);
68 | } else {
69 |
70 | setContentDisplay(ContentDisplay.TEXT_ONLY);
71 | setTextFill(Color.BLACK);
72 | setText(item.getName());
73 | setGraphic(null);
74 |
75 | installContextMenu();
76 |
77 | removeEventFilter(MouseEvent.MOUSE_CLICKED, mouseEventEventHandler);
78 | }
79 |
80 |
81 | setOnMouseClicked(event -> {
82 | if (event.getClickCount() == 2) {
83 | triggertExpand();
84 | }
85 | });
86 | // treeItemDoubleClick();
87 | }
88 |
89 | @Override
90 | protected Skin> createDefaultSkin() {
91 | return new TreeCellSkin<>(this);
92 | }
93 |
94 | private void triggertExpand() {
95 | TreeItem selectedItem = getSelectionModel().getSelectedItem();
96 | if (selectedItem != null) {
97 | selectedItem.setExpanded(!selectedItem.isExpanded());
98 | }
99 | }
100 |
101 | private void treeItemDoubleClick() {
102 | EventDispatcher eventDispatcher = getEventDispatcher();
103 | setEventDispatcher((event, tail) -> {
104 | if (event instanceof MouseEvent) {
105 | if (((MouseEvent) event).getButton() == MouseButton.PRIMARY
106 | && event.getEventType()
107 | .equals(MOUSE_PRESSED)
108 | && ((MouseEvent) event).getClickCount() == 2) {
109 |
110 | return event;
111 | }
112 | }
113 | return eventDispatcher.dispatchEvent(event, tail);
114 | });
115 | }
116 |
117 | private SelectionModel> getSelectionModel() {
118 | return zkTreeView.getSelectionModel();
119 | }
120 |
121 | private void installContextMenu() {
122 | ContextMenu contextMenu = new ContextMenu();
123 | MenuItem addNode = new MenuItem("新增节点");
124 | addNode.setOnAction(addNodeAction);
125 | contextMenu.getItems()
126 | .add(addNode);
127 |
128 | MenuItem deleteNode = new MenuItem("删除节点");
129 | deleteNode.setOnAction(deleteNodeAction);
130 | contextMenu.getItems()
131 | .add(deleteNode);
132 |
133 | MenuItem expandNode = new MenuItem("展开所有节点");
134 | expandNode.setOnAction(expandNodeAction);
135 | contextMenu.getItems()
136 | .add(expandNode);
137 |
138 | MenuItem unExpandNode = new MenuItem("收缩所有节点");
139 | unExpandNode.setOnAction(unExpandNodeAction);
140 | contextMenu.getItems()
141 | .add(unExpandNode);
142 | setContextMenu(contextMenu);
143 |
144 | }
145 |
146 | private EventHandler getUnExpandNodeAction() {
147 | return event -> {
148 | ZkNode value = getSelectionModel().getSelectedItem()
149 | .getValue();
150 | unExpandAllChildren(value);
151 | };
152 | }
153 |
154 | private EventHandler getExpandNodeAction() {
155 | return event -> {
156 | ZkNode value = getSelectionModel().getSelectedItem()
157 | .getValue();
158 | expandAllChildren(value);
159 | };
160 |
161 | }
162 |
163 | private void expandAllChildren(ZkNode zkNode) {
164 | zkNode.getTreeItem()
165 | .setExpanded(true);
166 | if (zkNode.getChildren() == null) {
167 | return;
168 | }
169 | for (ZkNode child : zkNode.getChildren()) {
170 | expandAllChildren(child);
171 | }
172 | }
173 |
174 | private void unExpandAllChildren(ZkNode zkNode) {
175 | zkNode.getTreeItem()
176 | .setExpanded(false);
177 | if (zkNode.getChildren() == null) {
178 | return;
179 | }
180 | for (ZkNode child : zkNode.getChildren()) {
181 | unExpandAllChildren(child);
182 | }
183 | }
184 |
185 | private EventHandler getDeleteNodeAction() {
186 | return event -> {
187 | Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
188 | alert.setTitle("删除节点提示");
189 | alert.setHeaderText(null);
190 | alert.setContentText("准备删除节点 path: " + getSelectionModel().getSelectedItem()
191 | .getValue()
192 | .getPath());
193 | Optional result = alert.showAndWait();
194 | if (result.isPresent() && result.get() == ButtonType.OK) {
195 | if (!deleteZkNode(getSelectionModel().getSelectedItem())) {
196 | Alert errorAlert = new Alert(Alert.AlertType.ERROR);
197 | errorAlert.setTitle("节点删除失败 path: " + getSelectionModel().getSelectedItem()
198 | .getValue()
199 | .getPath());
200 | errorAlert.setHeaderText(null);
201 | errorAlert.setContentText("准备删除节点 ");
202 | errorAlert.showAndWait();
203 | }
204 | }
205 | };
206 | }
207 |
208 | private EventHandler getAddNodeAction() {
209 | return new EventHandler() {
210 | @Override
211 | public void handle(ActionEvent event) {
212 | try {
213 | Parent parent = FXMLLoader.load(getClass().getResource("/fxml/nodeAdd.fxml"));
214 | Label parentPathLabel = (Label) parent.lookup("#parentPathLabel");
215 | TreeItem selectedItem = getSelectionModel()
216 | .getSelectedItem();
217 | if ("/".equals(selectedItem.getValue()
218 | .getPath())) {
219 | parentPathLabel.setText(selectedItem.getValue()
220 | .getPath());
221 | } else {
222 | parentPathLabel.setText(selectedItem.getValue()
223 | .getPath() + "/");
224 | }
225 | Stage stage = new Stage();
226 | stage.initModality(Modality.APPLICATION_MODAL);
227 | stage.setTitle("zk节点新增");
228 | Scene scene = new Scene(parent);
229 | stage.setScene(scene);
230 | stage.showAndWait();
231 |
232 | NodeAddController.NodeAddConf nodeAddConf = (NodeAddController.NodeAddConf) scene.getUserData();
233 | if (nodeAddConf != null) {
234 | log.info("准备创建zk节点 " + nodeAddConf);
235 | zkClientWrap.create(nodeAddConf.getPath(), nodeAddConf.getValue(), nodeAddConf.getZkNodeType());
236 | }
237 |
238 | } catch (IOException e) {
239 | log.error("生成nodeAdd控件失败", e);
240 | }
241 | }
242 | };
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/src/main/java/com/xin/view/zktreeview/ZkTreeView.java:
--------------------------------------------------------------------------------
1 | package com.xin.view.zktreeview;
2 |
3 | import com.xin.ZkClientWrap;
4 | import com.xin.ZkNode;
5 | import com.xin.util.FuzzyMatchUtils;
6 | import com.xin.util.StringUtil;
7 | import com.xin.view.NodeInfoEditProxy;
8 | import com.xin.view.ZkNodeTreeItem;
9 | import javafx.event.EventHandler;
10 | import javafx.scene.control.TreeItem;
11 | import javafx.scene.control.TreeView;
12 | import javafx.scene.input.KeyCode;
13 | import javafx.scene.input.KeyEvent;
14 | import lombok.extern.slf4j.Slf4j;
15 |
16 | /**
17 | * @author 497668869@qq.com
18 | * @since 1.0
19 | */
20 | @Slf4j
21 | public class ZkTreeView extends TreeView {
22 |
23 | private ZkClientWrap zkClientWrap;
24 | private ChangeSelectDataChangeListener selectToDataChangeListener;
25 | private SearchTextField searchZkNodeTextField;
26 |
27 | public void init(ZkClientWrap zkClient, SearchTextField searchZkNodeTextField, NodeInfoEditProxy nodeInfoEditProxy) {
28 | this.zkClientWrap = zkClient;
29 | this.searchZkNodeTextField = searchZkNodeTextField;
30 | ZkNodeTreeItem rootZkNodeTreeItem = initRootItem();
31 |
32 | setCellFactory(param -> new ZkNodeTreeCell(this, zkClientWrap));
33 | setOnKeyPressed(event -> {
34 | if (event.getCode() == KeyCode.ENTER) {
35 | TreeItem selectedItem = getSelectionModel().getSelectedItem();
36 | if (selectedItem != null) {
37 | selectedItem.setExpanded(!selectedItem.isExpanded());
38 | }
39 | }
40 | });
41 | selectToDataChangeListener = new ChangeSelectDataChangeListener(zkClient, nodeInfoEditProxy);
42 |
43 | getSelectionModel().selectedItemProperty()
44 | .addListener(selectToDataChangeListener);
45 |
46 | searchZkNodeTextField.textProperty()
47 | .addListener((observable, oldValue, newValue) -> {
48 | filterBySearchValue(rootZkNodeTreeItem, newValue);
49 | updateShowTreeItems(rootZkNodeTreeItem);
50 |
51 | });
52 |
53 | pressKeyToSearchInputText(searchZkNodeTextField);
54 |
55 | refresh();
56 | }
57 |
58 | private void updateShowTreeItems(ZkNodeTreeItem rootZkNodeTreeItem) {
59 | rootZkNodeTreeItem.updateShowTreeItems();
60 | for (TreeItem source : rootZkNodeTreeItem.getSources()) {
61 | ((ZkNodeTreeItem) source).updateShowTreeItems();
62 | }
63 | }
64 |
65 | private boolean filterBySearchValue(ZkNodeTreeItem rootZkNodeTreeItem,
66 | String newValue) {
67 | if (StringUtil.isEmpty(newValue)) {
68 | rootZkNodeTreeItem.setShow(true);
69 | } else {
70 | rootZkNodeTreeItem.setShow(FuzzyMatchUtils.match(rootZkNodeTreeItem.getValue()
71 | .getName(), newValue));
72 | }
73 |
74 | for (TreeItem child : rootZkNodeTreeItem.getSources()) {
75 | ZkNodeTreeItem zkNodeTreeItem = (ZkNodeTreeItem) child;
76 | if (filterBySearchValue(zkNodeTreeItem, newValue)) {
77 | rootZkNodeTreeItem.setShow(true);
78 | }
79 | }
80 | return rootZkNodeTreeItem.isShow();
81 |
82 | }
83 |
84 | /**
85 | * 随意在TreeView输入都可以在搜索框识别得到
86 | */
87 | private void pressKeyToSearchInputText(SearchTextField searchZkNodeTextField) {
88 | EventHandler keyEventHandler = event -> {
89 | searchZkNodeTextField.selectEnd();
90 | searchZkNodeTextField.fireEvent(
91 | new KeyEvent(searchZkNodeTextField, searchZkNodeTextField, event.getEventType(), event.getCharacter(), event.getText(),
92 | event.getCode(), event.isShiftDown(), event.isControlDown(), event.isAltDown(), event.isMetaDown()));
93 |
94 | };
95 | setOnKeyTyped(keyEventHandler);
96 |
97 | setOnKeyPressed(keyEventHandler);
98 | setOnKeyReleased(keyEventHandler);
99 | }
100 |
101 | // private void getSubTreeNodes(String currPath, List subs, ZkNodeInfo zkNodeInfo) {
102 | // List subList = new ArrayList<>();
103 | // subs.forEach(node -> {
104 | // String nodePath = currPath + "/" + node;
105 | // try {
106 | // ZkNodeInfo info = new ZkNodeInfo().setName(node)
107 | // .setPath(nodePath)
108 | // .setData(zkClientWrap.readData(nodePath, new Stat()));
109 | // subList.add(info);
110 | // zkNodeInfo.setChildren(subList);
111 | // getSubTreeNodes(nodePath, zkClientWrap.getChildren(nodePath), info);
112 | // } catch (Exception e) {
113 | // log.info("获取节点[{}]的子节点失败,可能已经发生了变更", nodePath);
114 | // }
115 | // });
116 | // }
117 |
118 | /**
119 | * 跟节点初始化, 添加箭头监听, 展开第二层
120 | */
121 | private ZkNodeTreeItem initRootItem() {
122 | ZkNode root = new ZkNode("/dubbo", "/dubbo");
123 | ZkNodeTreeItem rootZkNodeTreeItem = new ZkNodeTreeItem(zkClientWrap, root, this);
124 | setRoot(rootZkNodeTreeItem);
125 | root.setTreeItem(rootZkNodeTreeItem);
126 | rootZkNodeTreeItem.setExpanded(true);
127 | return rootZkNodeTreeItem;
128 | }
129 |
130 | }
131 |
--------------------------------------------------------------------------------
/src/main/java/org/I0Itec/zkclient/MyZkClient.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.ZkEventThread.ZkEvent;
19 | import org.I0Itec.zkclient.exception.ZkAuthFailedException;
20 | import org.I0Itec.zkclient.exception.ZkBadVersionException;
21 | import org.I0Itec.zkclient.exception.ZkException;
22 | import org.I0Itec.zkclient.exception.ZkInterruptedException;
23 | import org.I0Itec.zkclient.exception.ZkNoNodeException;
24 | import org.I0Itec.zkclient.exception.ZkNodeExistsException;
25 | import org.I0Itec.zkclient.exception.ZkTimeoutException;
26 | import org.I0Itec.zkclient.serialize.SerializableSerializer;
27 | import org.I0Itec.zkclient.serialize.ZkSerializer;
28 | import org.apache.zookeeper.CreateMode;
29 | import org.apache.zookeeper.KeeperException;
30 | import org.apache.zookeeper.KeeperException.ConnectionLossException;
31 | import org.apache.zookeeper.KeeperException.SessionExpiredException;
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.data.ACL;
40 | import org.apache.zookeeper.data.Stat;
41 | import org.slf4j.Logger;
42 | import org.slf4j.LoggerFactory;
43 |
44 | import javax.security.auth.login.Configuration;
45 | import java.io.File;
46 | import java.io.IOException;
47 | import java.io.OutputStream;
48 | import java.util.Date;
49 | import java.util.List;
50 | import java.util.Map;
51 | import java.util.Map.Entry;
52 | import java.util.Set;
53 | import java.util.concurrent.Callable;
54 | import java.util.concurrent.ConcurrentHashMap;
55 | import java.util.concurrent.CopyOnWriteArraySet;
56 | import java.util.concurrent.TimeUnit;
57 |
58 | /**
59 | * Abstracts the interaction with zookeeper and allows permanent (not just one time) watches on nodes in ZooKeeper
60 | */
61 | public class MyZkClient implements Watcher {
62 |
63 | protected static final String JAVA_LOGIN_CONFIG_PARAM = "java.security.auth.login.config";
64 | protected static final String ZK_SASL_CLIENT = "zookeeper.sasl.client";
65 | protected static final String ZK_LOGIN_CONTEXT_NAME_KEY = "zookeeper.sasl.clientconfig";
66 | private final static Logger LOG = LoggerFactory.getLogger(MyZkClient.class);
67 | protected final IZkConnection _connection;
68 | protected final long _operationRetryTimeoutInMillis;
69 | private final Map> _childListener = new ConcurrentHashMap>();
70 | private final ConcurrentHashMap> _dataListener = new ConcurrentHashMap>();
71 | private final Set _stateListener = new CopyOnWriteArraySet();
72 | private final ZkLock _zkEventLock = new ZkLock();
73 | private KeeperState _currentState;
74 | private boolean _shutdownTriggered;
75 | private ZkEventThread _eventThread;
76 | // TODO PVo remove this later
77 | private Thread _zookeeperEventThread;
78 | private ZkSerializer _zkSerializer;
79 | private volatile boolean _closed;
80 | private boolean _isZkSaslEnabled;
81 |
82 | public MyZkClient(String serverstring) {
83 | this(serverstring, Integer.MAX_VALUE);
84 | }
85 |
86 | public MyZkClient(String zkServers, int connectionTimeout) {
87 | this(new ZkConnection(zkServers), connectionTimeout);
88 | }
89 |
90 | public MyZkClient(String zkServers, int sessionTimeout, int connectionTimeout) {
91 | this(new ZkConnection(zkServers, sessionTimeout), connectionTimeout);
92 | }
93 |
94 | public MyZkClient(String zkServers, int sessionTimeout, int connectionTimeout, ZkSerializer zkSerializer) {
95 | this(new ZkConnection(zkServers, sessionTimeout), connectionTimeout, zkSerializer);
96 | }
97 |
98 | /**
99 | * @param zkServers The Zookeeper servers
100 | * @param sessionTimeout The session timeout in milli seconds
101 | * @param connectionTimeout The connection timeout in milli seconds
102 | * @param zkSerializer The Zookeeper data serializer
103 | * @param operationRetryTimeout Most operations done through this {@link MyZkClient} are retried in cases like
104 | * connection loss with the Zookeeper servers. During such failures, this
105 | * operationRetryTimeout
decides the maximum amount of time, in milli seconds, each
106 | * operation is retried. A value lesser than 0 is considered as
107 | * "retry forever until a connection has been reestablished".
108 | */
109 | public MyZkClient(final String zkServers, final int sessionTimeout, final int connectionTimeout, final ZkSerializer zkSerializer,
110 | final long operationRetryTimeout) {
111 | this(new ZkConnection(zkServers, sessionTimeout), connectionTimeout, zkSerializer, operationRetryTimeout);
112 | }
113 |
114 | public MyZkClient(IZkConnection connection) {
115 | this(connection, Integer.MAX_VALUE);
116 | }
117 |
118 | public MyZkClient(IZkConnection connection, int connectionTimeout) {
119 | this(connection, connectionTimeout, new SerializableSerializer());
120 | }
121 |
122 | public MyZkClient(IZkConnection zkConnection, int connectionTimeout, ZkSerializer zkSerializer) {
123 | this(zkConnection, connectionTimeout, zkSerializer, -1);
124 | }
125 |
126 | /**
127 | * @param zkConnection The Zookeeper servers
128 | * @param connectionTimeout The connection timeout in milli seconds
129 | * @param zkSerializer The Zookeeper data serializer
130 | * @param operationRetryTimeout Most operations done through this {@link MyZkClient} are retried in cases like
131 | * connection loss with the Zookeeper servers. During such failures, this
132 | * operationRetryTimeout
decides the maximum amount of time, in milli seconds, each
133 | * operation is retried. A value lesser than 0 is considered as
134 | * "retry forever until a connection has been reestablished".
135 | */
136 | public MyZkClient(final IZkConnection zkConnection, final int connectionTimeout, final ZkSerializer zkSerializer,
137 | final long operationRetryTimeout) {
138 | if (zkConnection == null) {
139 | throw new NullPointerException("Zookeeper connection is null!");
140 | }
141 | _connection = zkConnection;
142 | _zkSerializer = zkSerializer;
143 | _operationRetryTimeoutInMillis = operationRetryTimeout;
144 | _isZkSaslEnabled = isZkSaslEnabled();
145 | connect(connectionTimeout, this);
146 | }
147 |
148 | public void setZkSerializer(ZkSerializer zkSerializer) {
149 | _zkSerializer = zkSerializer;
150 | }
151 |
152 | public List subscribeChildChanges(String path, IZkChildListener listener) {
153 | synchronized (_childListener) {
154 | Set listeners = _childListener.get(path);
155 | if (listeners == null) {
156 | listeners = new CopyOnWriteArraySet();
157 | _childListener.put(path, listeners);
158 | }
159 | listeners.add(listener);
160 | }
161 | return watchForChilds(path);
162 | }
163 |
164 | public void unsubscribeChildChanges(String path, IZkChildListener childListener) {
165 | synchronized (_childListener) {
166 | final Set listeners = _childListener.get(path);
167 | if (listeners != null) {
168 | listeners.remove(childListener);
169 | }
170 | }
171 | }
172 |
173 | public void subscribeDataChanges(String path, IZkDataListener listener) {
174 | Set listeners;
175 | synchronized (_dataListener) {
176 | listeners = _dataListener.get(path);
177 | if (listeners == null) {
178 | listeners = new CopyOnWriteArraySet();
179 | _dataListener.put(path, listeners);
180 | }
181 | listeners.add(listener);
182 | }
183 | watchForData(path);
184 | LOG.debug("Subscribed data changes for " + path);
185 | }
186 |
187 | public void unsubscribeDataChanges(String path, IZkDataListener dataListener) {
188 | synchronized (_dataListener) {
189 | final Set listeners = _dataListener.get(path);
190 | if (listeners != null) {
191 | listeners.remove(dataListener);
192 | }
193 | if (listeners == null || listeners.isEmpty()) {
194 | _dataListener.remove(path);
195 | }
196 | }
197 | }
198 |
199 | public void subscribeStateChanges(final IZkStateListener listener) {
200 | synchronized (_stateListener) {
201 | _stateListener.add(listener);
202 | }
203 | }
204 |
205 | public void unsubscribeStateChanges(IZkStateListener stateListener) {
206 | synchronized (_stateListener) {
207 | _stateListener.remove(stateListener);
208 | }
209 | }
210 |
211 | public void unsubscribeAll() {
212 | synchronized (_childListener) {
213 | _childListener.clear();
214 | }
215 | synchronized (_dataListener) {
216 | _dataListener.clear();
217 | }
218 | synchronized (_stateListener) {
219 | _stateListener.clear();
220 | }
221 | }
222 |
223 | //
224 |
225 | /**
226 | * Create a persistent node.
227 | *
228 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
229 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
230 | * @throws ZkException if any ZooKeeper exception occurred
231 | * @throws RuntimeException if any other exception occurs
232 | */
233 | public void createPersistent(String path) throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
234 | createPersistent(path, false);
235 | }
236 |
237 | /**
238 | * Create a persistent node and set its ACLs.
239 | *
240 | * @param createParents if true all parent dirs are created as well and no {@link ZkNodeExistsException} is thrown in case the
241 | * path already exists
242 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
243 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
244 | * @throws ZkException if any ZooKeeper exception occurred
245 | * @throws RuntimeException if any other exception occurs
246 | */
247 | public void createPersistent(String path, boolean createParents) throws ZkInterruptedException, IllegalArgumentException, ZkException,
248 | RuntimeException {
249 | createPersistent(path, createParents, ZooDefs.Ids.OPEN_ACL_UNSAFE);
250 | }
251 |
252 | /**
253 | * Create a persistent node and set its ACLs.
254 | *
255 | * @param acl List of ACL permissions to assign to the node
256 | * @param createParents if true all parent dirs are created as well and no {@link ZkNodeExistsException} is thrown in case the
257 | * path already exists
258 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
259 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
260 | * @throws ZkException if any ZooKeeper exception occurred
261 | * @throws RuntimeException if any other exception occurs
262 | */
263 | public void createPersistent(String path, boolean createParents, List acl) throws ZkInterruptedException, IllegalArgumentException,
264 | ZkException, RuntimeException {
265 | try {
266 | create(path, null, acl, CreateMode.PERSISTENT);
267 | } catch (ZkNodeExistsException e) {
268 | if (!createParents) {
269 | throw e;
270 | }
271 | } catch (ZkNoNodeException e) {
272 | if (!createParents) {
273 | throw e;
274 | }
275 | String parentDir = path.substring(0, path.lastIndexOf('/'));
276 | createPersistent(parentDir, createParents, acl);
277 | createPersistent(path, createParents, acl);
278 | }
279 | }
280 |
281 | /**
282 | * Sets the acl on path
283 | *
284 | * @param acl List of ACL permissions to assign to the path.
285 | * @throws ZkException if any ZooKeeper exception occurred
286 | * @throws RuntimeException if any other exception occurs
287 | */
288 | public void setAcl(final String path, final List acl) throws ZkException {
289 | if (path == null) {
290 | throw new NullPointerException("Missing value for path");
291 | }
292 |
293 | if (acl == null || acl.size() == 0) {
294 | throw new NullPointerException("Missing value for ACL");
295 | }
296 |
297 | if (!exists(path)) {
298 | throw new RuntimeException("trying to set acls on non existing node " + path);
299 | }
300 |
301 | retryUntilConnected(new Callable() {
302 | @Override
303 | public Void call() throws Exception {
304 | Stat stat = new Stat();
305 | _connection.readData(path, stat, false);
306 | _connection.setAcl(path, acl, stat.getAversion());
307 | return null;
308 | }
309 | });
310 | }
311 |
312 | /**
313 | * Gets the acl on path
314 | *
315 | * @return an entry instance with key = list of acls on node and value = stats.
316 | * @throws ZkException if any ZooKeeper exception occurred
317 | * @throws RuntimeException if any other exception occurs
318 | */
319 | public Map.Entry, Stat> getAcl(final String path) throws ZkException {
320 | if (path == null) {
321 | throw new NullPointerException("Missing value for path");
322 | }
323 |
324 | if (!exists(path)) {
325 | throw new RuntimeException("trying to get acls on non existing node " + path);
326 | }
327 |
328 | return retryUntilConnected(new Callable, Stat>>() {
329 | @Override
330 | public Map.Entry, Stat> call() throws Exception {
331 | return _connection.getAcl(path);
332 | }
333 | });
334 | }
335 |
336 | /**
337 | * Create a persistent node.
338 | *
339 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
340 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
341 | * @throws ZkException if any ZooKeeper exception occurred
342 | * @throws RuntimeException if any other exception occurs
343 | */
344 | public void createPersistent(String path, Object data) throws ZkInterruptedException, IllegalArgumentException, ZkException,
345 | RuntimeException {
346 | create(path, data, CreateMode.PERSISTENT);
347 | }
348 |
349 | /**
350 | * Create a persistent node.
351 | *
352 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
353 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
354 | * @throws ZkException if any ZooKeeper exception occurred
355 | * @throws RuntimeException if any other exception occurs
356 | */
357 | public void createPersistent(String path, Object data, List acl) {
358 | create(path, data, acl, CreateMode.PERSISTENT);
359 | }
360 |
361 | /**
362 | * Create a persistent, sequental node.
363 | *
364 | * @return create node's path
365 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
366 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
367 | * @throws ZkException if any ZooKeeper exception occurred
368 | * @throws RuntimeException if any other exception occurs
369 | */
370 | public String createPersistentSequential(String path, Object data) throws ZkInterruptedException, IllegalArgumentException, ZkException,
371 | RuntimeException {
372 | return create(path, data, CreateMode.PERSISTENT_SEQUENTIAL);
373 | }
374 |
375 | /**
376 | * Create a persistent, sequential node and set its ACL.
377 | *
378 | * @return create node's path
379 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
380 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
381 | * @throws ZkException if any ZooKeeper exception occurred
382 | * @throws RuntimeException if any other exception occurs
383 | */
384 | public String createPersistentSequential(String path, Object data, List acl) throws ZkInterruptedException,
385 | IllegalArgumentException, ZkException,
386 | RuntimeException {
387 | return create(path, data, acl, CreateMode.PERSISTENT_SEQUENTIAL);
388 | }
389 |
390 | /**
391 | * Create an ephemeral node.
392 | *
393 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
394 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
395 | * @throws ZkException if any ZooKeeper exception occurred
396 | * @throws RuntimeException if any other exception occurs
397 | */
398 | public void createEphemeral(final String path) throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
399 | create(path, null, CreateMode.EPHEMERAL);
400 | }
401 |
402 | /**
403 | * Create an ephemeral node and set its ACL.
404 | *
405 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
406 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
407 | * @throws ZkException if any ZooKeeper exception occurred
408 | * @throws RuntimeException if any other exception occurs
409 | */
410 | public void createEphemeral(final String path, final List acl) throws ZkInterruptedException, IllegalArgumentException,
411 | ZkException, RuntimeException {
412 | create(path, null, acl, CreateMode.EPHEMERAL);
413 | }
414 |
415 | /**
416 | * Create a node.
417 | *
418 | * @return create node's path
419 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
420 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
421 | * @throws ZkException if any ZooKeeper exception occurred
422 | * @throws RuntimeException if any other exception occurs
423 | */
424 | public String create(final String path, Object data, final CreateMode mode) throws ZkInterruptedException, IllegalArgumentException,
425 | ZkException, RuntimeException {
426 | return create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, mode);
427 | }
428 |
429 | /**
430 | * Create a node with ACL.
431 | *
432 | * @return create node's path
433 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
434 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
435 | * @throws ZkException if any ZooKeeper exception occurred
436 | * @throws RuntimeException if any other exception occurs
437 | */
438 | public String create(final String path, Object data, final List acl, final CreateMode mode) {
439 | if (path == null) {
440 | throw new NullPointerException("Missing value for path");
441 | }
442 | if (acl == null || acl.size() == 0) {
443 | throw new NullPointerException("Missing value for ACL");
444 | }
445 | final byte[] bytes = data == null ? null : serialize(data);
446 |
447 | return retryUntilConnected(new Callable() {
448 | @Override
449 | public String call() throws Exception {
450 | return _connection.create(path, bytes, acl, mode);
451 | }
452 | });
453 |
454 | }
455 |
456 | /**
457 | * Create an ephemeral node.
458 | *
459 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
460 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
461 | * @throws ZkException if any ZooKeeper exception occurred
462 | * @throws RuntimeException if any other exception occurs
463 | */
464 | public void createEphemeral(final String path, final Object data) throws ZkInterruptedException, IllegalArgumentException, ZkException,
465 | RuntimeException {
466 | create(path, data, CreateMode.EPHEMERAL);
467 | }
468 |
469 | /**
470 | * Create an ephemeral node.
471 | *
472 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
473 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
474 | * @throws ZkException if any ZooKeeper exception occurred
475 | * @throws RuntimeException if any other exception occurs
476 | */
477 | public void createEphemeral(final String path, final Object data, final List acl) throws ZkInterruptedException,
478 | IllegalArgumentException, ZkException,
479 | RuntimeException {
480 | create(path, data, acl, CreateMode.EPHEMERAL);
481 | }
482 |
483 | /**
484 | * Create an ephemeral, sequential node.
485 | *
486 | * @return created path
487 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
488 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
489 | * @throws ZkException if any ZooKeeper exception occurred
490 | * @throws RuntimeException if any other exception occurs
491 | */
492 | public String createEphemeralSequential(final String path, final Object data) throws ZkInterruptedException, IllegalArgumentException,
493 | ZkException, RuntimeException {
494 | return create(path, data, CreateMode.EPHEMERAL_SEQUENTIAL);
495 | }
496 |
497 | /**
498 | * Create an ephemeral, sequential node with ACL.
499 | *
500 | * @return created path
501 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
502 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
503 | * @throws ZkException if any ZooKeeper exception occurred
504 | * @throws RuntimeException if any other exception occurs
505 | */
506 | public String createEphemeralSequential(final String path, final Object data, final List acl) throws ZkInterruptedException,
507 | IllegalArgumentException,
508 | ZkException,
509 | RuntimeException {
510 | return create(path, data, acl, CreateMode.EPHEMERAL_SEQUENTIAL);
511 | }
512 |
513 | @Override
514 | public void process(WatchedEvent event) {
515 | LOG.debug("Received event: " + event);
516 | _zookeeperEventThread = Thread.currentThread();
517 |
518 | boolean stateChanged = event.getPath() == null;
519 | boolean znodeChanged = event.getPath() != null;
520 | boolean dataChanged = event.getType() == EventType.NodeDataChanged || event.getType() == EventType.NodeDeleted || event.getType() == EventType.NodeCreated
521 | || event.getType() == EventType.NodeChildrenChanged;
522 |
523 | getEventLock().lock();
524 | try {
525 |
526 | // We might have to install child change event listener if a new node was created
527 | if (getShutdownTrigger()) {
528 | LOG.debug("ignoring event '{" + event.getType() + " | " + event.getPath() + "}' since shutdown triggered");
529 | return;
530 | }
531 | if (stateChanged) {
532 | processStateChanged(event);
533 | }
534 | if (dataChanged) {
535 | processDataOrChildChange(event);
536 | }
537 | } finally {
538 | if (stateChanged) {
539 | getEventLock().getStateChangedCondition()
540 | .signalAll();
541 |
542 | // If the session expired we have to signal all conditions, because watches might have been removed and
543 | // there is no guarantee that those
544 | // conditions will be signaled at all after an Expired event
545 | // TODO PVo write a test for this
546 | if (event.getState() == KeeperState.Expired) {
547 | getEventLock().getZNodeEventCondition()
548 | .signalAll();
549 | getEventLock().getDataChangedCondition()
550 | .signalAll();
551 | // We also have to notify all listeners that something might have changed
552 | fireAllEvents();
553 | }
554 | }
555 | if (znodeChanged) {
556 | getEventLock().getZNodeEventCondition()
557 | .signalAll();
558 | }
559 | if (dataChanged) {
560 | getEventLock().getDataChangedCondition()
561 | .signalAll();
562 | }
563 | getEventLock().unlock();
564 | LOG.debug("Leaving process event");
565 | }
566 | }
567 |
568 | public void unsubscribeChildChanges(String path) {
569 | synchronized (_childListener) {
570 | final Set listeners = _childListener.get(path);
571 | if (listeners != null) {
572 | listeners.clear();
573 | }
574 | }
575 |
576 | }
577 |
578 | public void unsubscribeDataChanges(String path) {
579 | Set iZkDataListeners = _dataListener.get(path);
580 | if (iZkDataListeners != null) {
581 | iZkDataListeners
582 | .clear();
583 | }
584 | }
585 |
586 | public List getChildren(String path) {
587 | return getChildren(path, hasListeners(path));
588 | }
589 |
590 | /**
591 | * Counts number of children for the given path.
592 | *
593 | * @return number of children or 0 if path does not exist.
594 | */
595 | public int countChildren(String path) {
596 | try {
597 | return getChildren(path).size();
598 | } catch (ZkNoNodeException e) {
599 | return 0;
600 | }
601 | }
602 |
603 | public boolean exists(final String path) {
604 | return exists(path, hasListeners(path));
605 | }
606 |
607 | public boolean deleteRecursive(String path) {
608 | List children;
609 | try {
610 | children = getChildren(path, false);
611 | } catch (ZkNoNodeException e) {
612 | return true;
613 | }
614 |
615 | for (String subPath : children) {
616 | if (!deleteRecursive(path + "/" + subPath)) {
617 | return false;
618 | }
619 | }
620 |
621 | return delete(path);
622 | }
623 |
624 | public boolean waitUntilExists(String path, TimeUnit timeUnit, long time) throws ZkInterruptedException {
625 | Date timeout = new Date(System.currentTimeMillis() + timeUnit.toMillis(time));
626 | LOG.debug("Waiting until znode '" + path + "' becomes available.");
627 | if (exists(path)) {
628 | return true;
629 | }
630 | acquireEventLock();
631 | try {
632 | while (!exists(path, true)) {
633 | boolean gotSignal = getEventLock().getZNodeEventCondition()
634 | .awaitUntil(timeout);
635 | if (!gotSignal) {
636 | return false;
637 | }
638 | }
639 | return true;
640 | } catch (InterruptedException e) {
641 | throw new ZkInterruptedException(e);
642 | } finally {
643 | getEventLock().unlock();
644 | }
645 | }
646 |
647 | public Set getDataListener(String path) {
648 | return _dataListener.get(path);
649 | }
650 |
651 | public void showFolders(OutputStream output) {
652 | try {
653 | output.write(org.I0Itec.MyZkClient.MyZkPathUtil.toString(this)
654 | .getBytes());
655 | } catch (final IOException e) {
656 | e.printStackTrace();
657 | }
658 | }
659 |
660 | public void waitUntilConnected() throws ZkInterruptedException {
661 | waitUntilConnected(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
662 | }
663 |
664 | public boolean waitUntilConnected(long time, TimeUnit timeUnit) throws ZkInterruptedException {
665 | if (_isZkSaslEnabled) {
666 | return waitForKeeperState(KeeperState.SaslAuthenticated, time, timeUnit);
667 | } else {
668 | return waitForKeeperState(KeeperState.SyncConnected, time, timeUnit);
669 | }
670 | }
671 |
672 | public boolean waitForKeeperState(KeeperState keeperState, long time, TimeUnit timeUnit) throws ZkInterruptedException {
673 | if (_zookeeperEventThread != null && Thread.currentThread() == _zookeeperEventThread) {
674 | throw new IllegalArgumentException("Must not be done in the zookeeper event thread.");
675 | }
676 | Date timeout = new Date(System.currentTimeMillis() + timeUnit.toMillis(time));
677 |
678 | LOG.info("Waiting for keeper state " + keeperState);
679 | acquireEventLock();
680 | try {
681 | boolean stillWaiting = true;
682 | while (_currentState != keeperState) {
683 | if (!stillWaiting) {
684 | return false;
685 | }
686 | stillWaiting = getEventLock().getStateChangedCondition()
687 | .awaitUntil(timeout);
688 | // Throw an exception in the case authorization fails
689 | if (_currentState == KeeperState.AuthFailed && _isZkSaslEnabled) {
690 | throw new ZkAuthFailedException("Authentication failure");
691 | }
692 | }
693 | LOG.debug("State is " + _currentState);
694 | return true;
695 | } catch (InterruptedException e) {
696 | throw new ZkInterruptedException(e);
697 | } finally {
698 | getEventLock().unlock();
699 | }
700 | }
701 |
702 | /**
703 | * @return result of Callable
704 | * @throws ZkInterruptedException if operation was interrupted, or a required reconnection got interrupted
705 | * @throws IllegalArgumentException if called from anything except the ZooKeeper event thread
706 | * @throws ZkException if any ZooKeeper exception occurred
707 | * @throws RuntimeException if any other exception occurs from invoking the Callable
708 | */
709 | public T retryUntilConnected(Callable callable) throws ZkInterruptedException, IllegalArgumentException, ZkException,
710 | RuntimeException {
711 | if (_zookeeperEventThread != null && Thread.currentThread() == _zookeeperEventThread) {
712 | throw new IllegalArgumentException("Must not be done in the zookeeper event thread.");
713 | }
714 | final long operationStartTime = System.currentTimeMillis();
715 | while (true) {
716 | if (_closed) {
717 | throw new IllegalStateException("ZkClient already closed!");
718 | }
719 | try {
720 | return callable.call();
721 | } catch (ConnectionLossException e) {
722 | // we give the event thread some time to update the status to 'Disconnected'
723 | Thread.yield();
724 | waitForRetry();
725 | } catch (SessionExpiredException e) {
726 | // we give the event thread some time to update the status to 'Expired'
727 | Thread.yield();
728 | waitForRetry();
729 | } catch (KeeperException e) {
730 | throw ZkException.create(e);
731 | } catch (InterruptedException e) {
732 | throw new ZkInterruptedException(e);
733 | } catch (Exception e) {
734 | throw ExceptionUtil.convertToRuntimeException(e);
735 | }
736 | // before attempting a retry, check whether retry timeout has elapsed
737 | if (_operationRetryTimeoutInMillis > -1 && (System.currentTimeMillis() - operationStartTime) >= _operationRetryTimeoutInMillis) {
738 | throw new ZkTimeoutException(
739 | "Operation cannot be retried because of retry timeout (" + _operationRetryTimeoutInMillis + " milli seconds)");
740 | }
741 | }
742 | }
743 |
744 | public void setCurrentState(KeeperState currentState) {
745 | getEventLock().lock();
746 | try {
747 | _currentState = currentState;
748 | } finally {
749 | getEventLock().unlock();
750 | }
751 | }
752 |
753 | /**
754 | * Returns a mutex all zookeeper events are synchronized aginst. So in case you need to do something without getting
755 | * any zookeeper event interruption synchronize against this mutex. Also all threads waiting on this mutex object
756 | * will be notified on an event.
757 | *
758 | * @return the mutex.
759 | */
760 | public ZkLock getEventLock() {
761 | return _zkEventLock;
762 | }
763 |
764 | public boolean delete(final String path) {
765 | return delete(path, -1);
766 | }
767 |
768 | public boolean delete(final String path, final int version) {
769 | try {
770 | retryUntilConnected(new Callable