blob: dce978edc25f0ae4b4e929d629c6f290b80ad8ff [file] [log] [blame]
Madan Jampani25461112015-02-17 14:17:29 -08001/*
2 * Copyright 2015 Open Networking Laboratory
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
Madan Jampani09342702015-02-05 23:32:40 -080017package org.onosproject.store.consistent.impl;
18
19import static com.google.common.base.Preconditions.checkArgument;
20import static com.google.common.base.Preconditions.checkNotNull;
21import static org.slf4j.LoggerFactory.getLogger;
22
23import java.io.File;
24import java.io.IOException;
25import java.util.HashMap;
26import java.util.HashSet;
27import java.util.Iterator;
28import java.util.Map;
29import java.util.Map.Entry;
30import java.util.Set;
31
32import org.onosproject.cluster.DefaultControllerNode;
33import org.onosproject.cluster.NodeId;
34import org.onlab.packet.IpAddress;
35import org.slf4j.Logger;
36
37import com.fasterxml.jackson.core.JsonEncoding;
38import com.fasterxml.jackson.core.JsonFactory;
39import com.fasterxml.jackson.databind.JsonNode;
40import com.fasterxml.jackson.databind.ObjectMapper;
41import com.fasterxml.jackson.databind.node.ArrayNode;
42import com.fasterxml.jackson.databind.node.ObjectNode;
43import com.google.common.collect.Maps;
44
45/**
46 * Allows for reading and writing partitioned database definition as a JSON file.
47 */
48public class DatabaseDefinitionStore {
49
50 private final Logger log = getLogger(getClass());
51
52 private final File definitionfile;
53
54 /**
55 * Creates a reader/writer of the database definition file.
56 *
57 * @param filePath location of the definition file
58 */
59 public DatabaseDefinitionStore(String filePath) {
60 definitionfile = new File(filePath);
61 }
62
63 /**
64 * Creates a reader/writer of the database definition file.
65 *
66 * @param filePath location of the definition file
67 */
68 public DatabaseDefinitionStore(File filePath) {
69 definitionfile = checkNotNull(filePath);
70 }
71
72 /**
73 * Returns the Map from database partition name to set of initial active member nodes.
74 *
75 * @return Map from partition name to set of active member nodes
76 * @throws IOException when I/O exception of some sort has occurred.
77 */
78 public Map<String, Set<DefaultControllerNode>> read() throws IOException {
79
80 final Map<String, Set<DefaultControllerNode>> partitions = Maps.newHashMap();
81
82 final ObjectMapper mapper = new ObjectMapper();
83 final ObjectNode tabletNodes = (ObjectNode) mapper.readTree(definitionfile);
84 final Iterator<Entry<String, JsonNode>> fields = tabletNodes.fields();
85 while (fields.hasNext()) {
86 final Entry<String, JsonNode> next = fields.next();
87 final Set<DefaultControllerNode> nodes = new HashSet<>();
88 final Iterator<JsonNode> elements = next.getValue().elements();
89 while (elements.hasNext()) {
90 ObjectNode nodeDef = (ObjectNode) elements.next();
91 nodes.add(new DefaultControllerNode(new NodeId(nodeDef.get("id").asText()),
92 IpAddress.valueOf(nodeDef.get("ip").asText()),
93 nodeDef.get("tcpPort").asInt(DatabaseManager.COPYCAT_TCP_PORT)));
94 }
95
96 partitions.put(next.getKey(), nodes);
97 }
98 return partitions;
99 }
100
101 /**
102 * Updates the Map from database partition name to set of member nodes.
103 *
104 * @param partitionName name of the database partition to update
105 * @param nodes set of initial member nodes
106 * @throws IOException when I/O exception of some sort has occurred.
107 */
108 public void write(String partitionName, Set<DefaultControllerNode> nodes) throws IOException {
109 checkNotNull(partitionName);
110 checkArgument(partitionName.isEmpty(), "Partition name cannot be empty");
111
112 // load current
113 Map<String, Set<DefaultControllerNode>> config;
114 try {
115 config = read();
116 } catch (IOException e) {
117 log.info("Reading partition config failed, assuming empty definition.");
118 config = new HashMap<>();
119 }
120 // update with specified
121 config.put(partitionName, nodes);
122
123 // write back to file
124 final ObjectMapper mapper = new ObjectMapper();
125 final ObjectNode partitionNodes = mapper.createObjectNode();
126 for (Entry<String, Set<DefaultControllerNode>> tablet : config.entrySet()) {
127 ArrayNode nodeDefs = mapper.createArrayNode();
128 partitionNodes.set(tablet.getKey(), nodeDefs);
129
130 for (DefaultControllerNode node : tablet.getValue()) {
131 ObjectNode nodeDef = mapper.createObjectNode();
132 nodeDef.put("id", node.id().toString())
133 .put("ip", node.ip().toString())
134 .put("tcpPort", node.tcpPort());
135 nodeDefs.add(nodeDef);
136 }
137 }
138 mapper.writeTree(new JsonFactory().createGenerator(definitionfile, JsonEncoding.UTF8),
139 partitionNodes);
140 }
141}