summaryrefslogtreecommitdiffstats
path: root/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplication.java
blob: 084f26bd3682a35b5bfd2db09fe7f4a5f476e803 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.zookeeper;

import com.yahoo.io.reader.NamedReader;
import com.yahoo.path.Path;

import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Responsible for providing data from an application subtree in zookeeper.
 * (i.e. /config/v2/tenants/x/session/<session id for an application>/).
 *
 * @author Tony Vaagenes
 */
public class ZKApplication {

    private final ConfigCurator zk;
    private final Path appPath;

    ZKApplication(ConfigCurator zk, Path appPath) {
        this.zk = zk;
        this.appPath = appPath;
    }

    /**
     * Returns a list of the files (as readers) in the given path. The readers <b>must</b>
     * be closed by the caller.
     *
     * @param path           a path relative to the session
     *                       (i.e. /config/v2/tenants/x/sessions/&lt;session id&gt;/).
     * @param fileNameSuffix the suffix of files to return, or null to return all
     * @param recursive      if true, all files from all subdirectories of this will also be returned
     * @return the files in the given path, or an empty list if the directory does not exist or is empty.
     *         The list gets owned by the caller and can be modified freely.
     */
    List<NamedReader> getAllDataFromDirectory(String path, String fileNameSuffix, boolean recursive) {
        return getAllDataFromDirectory(path, "", fileNameSuffix, recursive);
    }

    /**
     * As above, except
     *
     * @param namePrefix the prefix to prepend to the returned reader names
     */
    private List<NamedReader> getAllDataFromDirectory(String path, String namePrefix, String fileNameSuffix, boolean recursive) {
        String fullPath = getFullPath(path);
        List<NamedReader> result = new ArrayList<>();
        List<String> children = getChildren(path);

        try {
            for (String child : children) {
                if (fileNameSuffix == null || child.endsWith(fileNameSuffix)) {
                    result.add(new NamedReader(namePrefix + child, reader(zk.getData(fullPath, child))));
                }
                if (recursive)
                    result.addAll(getAllDataFromDirectory(path + "/" + child,
                                                          namePrefix + child + "/", fileNameSuffix, recursive));
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException("Could not retrieve all data from '" + fullPath + "' in zookeeper", e);
        }
    }

    /**
     * Retrieves a node relative to the node of the live application
     *
     * @param path a path relative to the currently active application
     * @param node a path relative to the path above
     * @return a Reader that can be used to get the data
     */
    Reader getDataReader(String path, String node) {
        return reader(getData(path, node));
    }

    public String getData(String path, String node) {
        if ( ! exists(path, node)) throw new IllegalArgumentException("No node for " + getFullPath(path) + "/" + node + " exists");

        try {
            return zk.getData(getFullPath(path), node);
        } catch (Exception e) {
            throw new IllegalArgumentException("Could not retrieve node '" +
                                               getFullPath(path) + "/" + node + "' in zookeeper", e);
        }
    }

    public String getData(String path) {
        if ( ! exists(path)) throw new IllegalArgumentException("No node for " + getFullPath(path) + " exists");

        try {
            return zk.getData(getFullPath(path));
        } catch (RuntimeException e) {
            throw new IllegalArgumentException("Could not retrieve path '" + getFullPath(path) + "' in zookeeper", e);
        }
    }

    public byte[] getBytes(String path) {
        try {
            return zk.getBytes(getFullPath(path));
        } catch (RuntimeException e) {
            throw new IllegalArgumentException("Could not retrieve path '" + getFullPath(path) + "' in zookeeper", e);
        }
    }

    void putData(String path, String data) {
        try {
            zk.putData(getFullPath(path), data);
        } catch (RuntimeException e) {
            throw new IllegalArgumentException("Could not put data to node '" + getFullPath(path) + "' in zookeeper", e);
        }
    }

    /**
     * Checks if the given node exists under path under this live app
     *
     * @param path a zookeeper path
     * @param node a zookeeper node
     * @return true if the node exists in the path, false otherwise
     */
    public boolean exists(String path, String node) {
        return zk.exists(getFullPath(path), node);
    }

    /**
     * Checks if the given node exists under path under this live app
     *
     * @param path a zookeeper path
     * @return true if the node exists in the path, false otherwise
     */
    public boolean exists(String path) {
        return zk.exists(getFullPath(path));
    }

    private String getFullPath(String path) {
        Path fullPath = appPath;
        if (path != null) {
            fullPath = appPath.append(path);
        }
        return fullPath.getAbsolute();
    }

    /**
     * Recursively delete given path
     *
     * @param path path to delete
     */
    void deleteRecurse(String path) {
        zk.deleteRecurse(getFullPath(path));
    }

    /**
     * Returns the full list of children (file names) in the given path.
     *
     * @param path a path relative to the currently active application
     * @return a list of file names, which is empty (never null) if the path does not exist
     */
    public List<String> getChildren(String path) {
        String fullPath = getFullPath(path);
        if (! zk.exists(fullPath)) return Collections.emptyList();
        return zk.getChildren(fullPath);
    }

    private static Reader reader(String string) {
        return new StringReader(string);
    }

    public void create(String path) {
        if (path != null && !path.startsWith("/")) path = "/" + path;
        try {
            zk.createNode(getFullPath(path));
        } catch (RuntimeException e) {
            throw new IllegalArgumentException(e);
        }
    }

    Reader getDataReader(String path) {
        String data = getData(path);
        if (data == null)
            throw new IllegalArgumentException("No node for " + getFullPath(path) + " exists");
        return reader(data);
    }

}