View Javadoc

1   package org.apache.helix;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.TreeMap;
29  
30  import org.apache.helix.model.ConfigScope;
31  import org.apache.helix.model.HelixConfigScope;
32  import org.apache.helix.model.HelixConfigScope.ConfigScopeProperty;
33  import org.apache.helix.manager.zk.ZKUtil;
34  import org.apache.helix.manager.zk.ZkClient;
35  import org.apache.helix.util.StringTemplate;
36  import org.apache.log4j.Logger;
37  
38  
39  public class ConfigAccessor
40  {
41    private static Logger               LOG      = Logger.getLogger(ConfigAccessor.class);
42  
43    private static final StringTemplate template = new StringTemplate();
44    static
45    {
46      // @formatter:off
47      template.addEntry(ConfigScopeProperty.CLUSTER, 1, "/{clusterName}/CONFIGS/CLUSTER");
48      template.addEntry(ConfigScopeProperty.CLUSTER,
49                        2,
50                        "/{clusterName}/CONFIGS/CLUSTER/{clusterName}|SIMPLEKEYS");
51      template.addEntry(ConfigScopeProperty.PARTICIPANT,
52                        1,
53                        "/{clusterName}/CONFIGS/PARTICIPANT");
54      template.addEntry(ConfigScopeProperty.PARTICIPANT,
55                        2,
56                        "/{clusterName}/CONFIGS/PARTICIPANT/{participantName}|SIMPLEKEYS");
57      template.addEntry(ConfigScopeProperty.RESOURCE, 1, "/{clusterName}/CONFIGS/RESOURCE");
58      template.addEntry(ConfigScopeProperty.RESOURCE,
59                        2,
60                        "/{clusterName}/CONFIGS/RESOURCE/{resourceName}|SIMPLEKEYS");
61      template.addEntry(ConfigScopeProperty.PARTITION,
62                        2,
63                        "/{clusterName}/CONFIGS/RESOURCE/{resourceName}|MAPKEYS");
64      template.addEntry(ConfigScopeProperty.PARTITION,
65                        3,
66                        "/{clusterName}/CONFIGS/RESOURCE/{resourceName}|MAPMAPKEYS|{partitionName}");
67      // @formatter:on
68    }
69  
70    private final ZkClient              zkClient;
71  
72    public ConfigAccessor(ZkClient zkClient)
73    {
74      this.zkClient = zkClient;
75    }
76  
77    /**
78     * get config
79     * @deprecated replaced by {@link #get(HelixConfigScope, String)}
80     * 
81     * @param scope
82     * @param key
83     * @return value or null if doesn't exist
84     */
85    @Deprecated
86    public String get(ConfigScope scope, String key)
87    {
88      Map<String, String> map = get(scope, Arrays.asList(key));
89      return map.get(key);
90    }
91    
92    /**
93     * get configs
94     * @deprecated replaced by {@link #get(HelixConfigScope, List<String>)}
95     * 
96     * @param scope
97     * @param keys
98     * @return
99     */
100   @Deprecated
101   public Map<String, String> get(ConfigScope scope, List<String> keys)
102   {
103     if (scope == null || scope.getScope() == null)
104     {
105       LOG.error("Scope can't be null");
106       return null;
107     }
108 
109     // String value = null;
110     Map<String, String> map = new HashMap<String, String>();
111     String clusterName = scope.getClusterName();
112     if (!ZKUtil.isClusterSetup(clusterName, zkClient))
113     {
114       throw new HelixException("cluster " + clusterName + " is not setup yet");
115     }
116 
117     String scopeStr = scope.getScopeStr();
118     String[] splits = scopeStr.split("\\|");
119 
120     ZNRecord record = zkClient.readData(splits[0], true);
121 
122     if (record != null)
123     {
124       if (splits.length == 1)
125       {
126         for (String key : keys) {
127           if (record.getSimpleFields().containsKey(key)) {
128             map.put(key, record.getSimpleField(key));
129           }
130         }
131       }
132       else if (splits.length == 2)
133       {
134         if (record.getMapField(splits[1]) != null)
135         {
136           for (String key : keys) {
137             if (record.getMapField(splits[1]).containsKey(key)) {
138               map.put(key, record.getMapField(splits[1]).get(key));
139             }
140           }
141         }
142       }
143     }
144     return map;
145 
146   }
147   
148   /**
149    * get config
150    * 
151    * @param scope
152    * @param key
153    * @return
154    */
155   public String get(HelixConfigScope scope, String key) {
156     Map<String, String> map = get(scope, Arrays.asList(key));
157     if (map != null) {
158       return map.get(key);
159     }
160     return null;
161   }
162   
163   /**
164    * get configs
165    * 
166    * @param scope
167    * @param keys
168    * @return
169    */
170   public Map<String, String> get(HelixConfigScope scope, List<String> keys) {
171     if (scope == null || scope.getType()== null || !scope.isFullKey()) {
172       LOG.error("fail to get configs. invalid config scope. scope: " + scope + ", keys: " + keys);
173       return null;
174     }
175 
176     String clusterName = scope.getClusterName();
177     if (!ZKUtil.isClusterSetup(clusterName, zkClient)) {
178       throw new HelixException("fail to get configs. cluster " + clusterName + " is not setup yet");
179     }
180 
181     Map<String, String> map = new HashMap<String, String>();
182 
183     ZNRecord record = zkClient.readData(scope.getZkPath(), true);
184     if (record == null) {
185       LOG.warn("No config found at " + scope.getZkPath());
186       return null;
187     }
188     
189     String mapKey = scope.getMapKey();
190     if (mapKey == null) {
191       for (String key : keys) {
192         if (record.getSimpleFields().containsKey(key)) {
193           map.put(key, record.getSimpleField(key));
194         }
195       }
196     } else {
197       Map<String, String> configMap = record.getMapField(mapKey);
198       if (configMap == null) {
199         LOG.warn("No map-field found in " + record + " using mapKey: " + mapKey);
200         return null;
201       }
202       
203       for (String key : keys) {
204         if (record.getMapField(mapKey).containsKey(key)) {
205           map.put(key, record.getMapField(mapKey).get(key));
206         }
207       }
208     }
209 
210     return map;  
211   }
212   
213   /**
214    * Set config, create if not exist
215    * @deprecated replaced by {@link #set(HelixConfigScope, String, String)}
216    * 
217    * @param scope
218    * @param key
219    * @param value
220    */
221   @Deprecated
222   public void set(ConfigScope scope, String key, String value) {
223     Map<String, String> map = new HashMap<String, String>();
224     map.put(key, value);
225     set(scope, map);
226   }
227   
228   /**
229    * Set configs, create if not exist
230    * @deprecated replaced by {@link #set(HelixConfigScope, Map<String, String>)}
231    *
232    * @param scope
233    * @param keyValueMap
234    */
235   @Deprecated
236   public void set(ConfigScope scope, Map<String, String> keyValueMap)
237   {
238     if (scope == null || scope.getScope() == null)
239     {
240       LOG.error("Scope can't be null");
241       return;
242     }
243 
244     String clusterName = scope.getClusterName();
245     if (!ZKUtil.isClusterSetup(clusterName, zkClient))
246     {
247       throw new HelixException("cluster: " + clusterName + " is NOT setup.");
248     }
249 
250     if (scope.getScope() == ConfigScopeProperty.PARTICIPANT) {
251        String scopeStr = scope.getScopeStr();
252        String instanceName = scopeStr.substring(scopeStr.lastIndexOf('/') + 1);
253        if (!ZKUtil.isInstanceSetup(zkClient, scope.getClusterName(), instanceName, InstanceType.PARTICIPANT)) {
254            throw new HelixException("instance: " + instanceName + " is NOT setup in cluster: " + clusterName);
255        }
256     }
257 
258     // use "|" to delimit resource and partition. e.g. /MyCluster/CONFIGS/PARTICIPANT/MyDB|MyDB_0
259     String scopeStr = scope.getScopeStr();
260     String[] splits = scopeStr.split("\\|");
261 
262     String id = splits[0].substring(splits[0].lastIndexOf('/') + 1);
263     ZNRecord update = new ZNRecord(id);
264     if (splits.length == 1)
265     {
266       for (String key: keyValueMap.keySet()) {
267         String value = keyValueMap.get(key);
268         update.setSimpleField(key, value);
269       }
270     }
271     else if (splits.length == 2)
272     {
273       if (update.getMapField(splits[1]) == null)
274       {
275         update.setMapField(splits[1], new TreeMap<String, String>());
276       }
277       for (String key: keyValueMap.keySet()) {
278         String value = keyValueMap.get(key);
279         update.getMapField(splits[1]).put(key, value);
280       }
281     }
282     ZKUtil.createOrUpdate(zkClient, splits[0], update, true, true);
283     return;
284   }
285 
286   /**
287    * set config. create if not exist
288    * 
289    * @param scope
290    * @param key
291    * @param value
292    */
293   public void set(HelixConfigScope scope, String key, String value) {
294     Map<String, String> map = new TreeMap<String, String>();
295     map.put(key, value);
296     set(scope, map);
297   }
298 
299   /**
300    * set configs. create if not exist
301    * 
302    * @param scope
303    * @param keyValueMap
304    */
305   public void set(HelixConfigScope scope, Map<String, String> keyValueMap)
306   {
307     if (scope == null || scope.getType() == null || !scope.isFullKey()) {
308       LOG.error("fail to set config. invalid config scope. scope: " + scope);
309       return;
310     }
311 
312     String clusterName = scope.getClusterName();
313     if (!ZKUtil.isClusterSetup(clusterName, zkClient)) {
314       throw new HelixException("fail to set config. cluster: " + clusterName + " is NOT setup.");
315     }
316 
317     if (scope.getType() == ConfigScopeProperty.PARTICIPANT) {
318        if (!ZKUtil.isInstanceSetup(zkClient, scope.getClusterName(), scope.getParticipantName(), 
319                InstanceType.PARTICIPANT)) {
320            throw new HelixException("fail to set config. instance: " + scope.getClusterName() 
321                + " is NOT setup in cluster: " + clusterName);
322        }
323     }
324 
325     String zkPath = scope.getZkPath();
326     String mapKey = scope.getMapKey();
327     String id = zkPath.substring(zkPath.lastIndexOf('/') + 1);
328     ZNRecord update = new ZNRecord(id);
329     if (mapKey == null) {
330       update.getSimpleFields().putAll(keyValueMap);
331     } else {
332         update.setMapField(mapKey, keyValueMap);
333     }
334     ZKUtil.createOrUpdate(zkClient, zkPath, update, true, true);
335     return;
336   }
337   
338   /**
339    * Remove config
340    * @deprecated replaced by {@link #remove(HelixConfigScope, String)}
341    * 
342    * @param scope
343    * @param key
344    */
345   @Deprecated
346   public void remove(ConfigScope scope, String key) {
347     remove(scope, Arrays.asList(key));
348   }
349   
350   /**
351    * remove configs
352    * @deprecated replaced by {@link #remove(HelixConfigScope, List<String>)}
353    * 
354    * @param scope
355    * @param keys
356    */
357   @Deprecated
358   public void remove(ConfigScope scope, List<String> keys)
359   {
360     if (scope == null || scope.getScope() == null)
361     {
362       LOG.error("Scope can't be null");
363       return;
364     }
365 
366     String clusterName = scope.getClusterName();
367     if (!ZKUtil.isClusterSetup(clusterName, zkClient))
368     {
369       throw new HelixException("cluster " + clusterName + " is not setup yet");
370     }
371 
372     String scopeStr = scope.getScopeStr();
373     String[] splits = scopeStr.split("\\|");
374 
375     String id = splits[0].substring(splits[0].lastIndexOf('/') + 1);
376     ZNRecord update = new ZNRecord(id);
377     if (splits.length == 1)
378     {
379       // subtract doesn't care about value, use empty string
380       for (String key : keys) {
381         update.setSimpleField(key, "");
382       }
383     }
384     else if (splits.length == 2)
385     {
386       if (update.getMapField(splits[1]) == null)
387       {
388         update.setMapField(splits[1], new TreeMap<String, String>());
389       }
390       // subtract doesn't care about value, use empty string
391       for (String key : keys) {
392         update.getMapField(splits[1]).put(key, "");
393       }
394     }
395 
396     ZKUtil.subtract(zkClient, splits[0], update);
397     return;
398   }
399 
400   /**
401    * rmeove config
402    * 
403    * @param scope
404    * @param key
405    */
406   public void remove(HelixConfigScope scope, String key) {
407     remove(scope, Arrays.asList(key));
408   }
409 
410   /**
411    * remove configs
412    * 
413    * @param scope
414    * @param keys
415    */
416   public void remove(HelixConfigScope scope, List<String> keys)
417   {
418     if (scope == null || scope.getType() == null || !scope.isFullKey()) {
419       LOG.error("fail to remove. invalid scope: " + scope + ", keys: " + keys);
420       return;
421     }
422 
423     String clusterName = scope.getClusterName();
424     if (!ZKUtil.isClusterSetup(clusterName, zkClient)) {
425       throw new HelixException("fail to remove. cluster " + clusterName + " is not setup yet");
426     }
427 
428     String zkPath = scope.getZkPath();
429     String mapKey = scope.getMapKey();
430     String id = zkPath.substring(zkPath.lastIndexOf('/') + 1);
431     ZNRecord update = new ZNRecord(id);
432     if (mapKey == null) {
433       // subtract doesn't care about value, use empty string
434       for (String key : keys) {
435         update.setSimpleField(key, "");
436       }
437     } else {
438       update.setMapField(mapKey, new TreeMap<String, String>());
439       // subtract doesn't care about value, use empty string
440       for (String key : keys) {
441         update.getMapField(mapKey).put(key, "");
442       }
443     }
444 
445     ZKUtil.subtract(zkClient, zkPath, update);
446     return;
447   }
448   
449   /**
450    * get config keys
451    * @deprecated replaced by {@link #getKeys(HelixConfigScope)}
452    * 
453    * @param type
454    * @param clusterName
455    * @param keys
456    * @return
457    */
458   @Deprecated
459   public List<String> getKeys(ConfigScopeProperty type,
460                               String clusterName,
461                               String... keys)
462   {
463     if (type == null || clusterName == null)
464     {
465       LOG.error("clusterName|scope can't be null");
466       return Collections.emptyList();
467     }
468 
469     try
470     {
471       if (!ZKUtil.isClusterSetup(clusterName, zkClient))
472       {
473         LOG.error("cluster " + clusterName + " is not setup yet");
474         return Collections.emptyList();
475       }
476 
477       String[] args = new String[1 + keys.length];
478       args[0] = clusterName;
479       System.arraycopy(keys, 0, args, 1, keys.length);
480       String scopeStr = template.instantiate(type, args);
481       String[] splits = scopeStr.split("\\|");
482       List<String> retKeys = null;
483       if (splits.length == 1)
484       {
485         retKeys = zkClient.getChildren(splits[0]);
486       }
487       else
488       {
489         ZNRecord record = zkClient.readData(splits[0]);
490 
491         if (splits[1].startsWith("SIMPLEKEYS"))
492         {
493           retKeys = new ArrayList<String>(record.getSimpleFields().keySet());
494 
495         }
496         else if (splits[1].startsWith("MAPKEYS"))
497         {
498           retKeys = new ArrayList<String>(record.getMapFields().keySet());
499         }
500         else if (splits[1].startsWith("MAPMAPKEYS"))
501         {
502           retKeys = new ArrayList<String>(record.getMapField(splits[2]).keySet());
503         }
504       }
505       if (retKeys == null)
506       {
507         LOG.error("Invalid scope: " + type + " or keys: " + Arrays.toString(args));
508         return Collections.emptyList();
509       }
510 
511       Collections.sort(retKeys);
512       return retKeys;
513     }
514     catch (Exception e)
515     {
516       return Collections.emptyList();
517     }
518 
519   }
520   
521   
522   /**
523    * get list of config keys for a scope
524    * 
525    * @param scope
526    * @return
527    */
528   public List<String> getKeys(HelixConfigScope scope) {
529     if (scope == null || scope.getType() == null) {
530       LOG.error("fail to getKeys. invalid config scope: " + scope);
531       return null;
532     }
533   
534     if (!ZKUtil.isClusterSetup(scope.getClusterName(), zkClient)){
535       LOG.error("fail to getKeys. cluster " + scope.getClusterName() + " is not setup yet");
536       return Collections.emptyList();
537     }
538   
539     String zkPath = scope.getZkPath();
540     String mapKey = scope.getMapKey();
541     List<String> retKeys = null;
542     
543     if (scope.isFullKey()) {
544       ZNRecord record = zkClient.readData(zkPath);
545       if (mapKey == null) {
546         retKeys = new ArrayList<String>(record.getSimpleFields().keySet());
547       } else {
548         retKeys = new ArrayList<String>(record.getMapField(mapKey).keySet());
549       }
550     } else {
551       if (scope.getType() == ConfigScopeProperty.PARTITION) {
552         ZNRecord record = zkClient.readData(zkPath);
553         retKeys = new ArrayList<String>(record.getMapFields().keySet());
554       } else {
555         retKeys = zkClient.getChildren(zkPath);
556       }
557     }
558       
559     if (retKeys != null) {
560       Collections.sort(retKeys);
561     }
562     return retKeys;
563   }
564 }