Optimize RESTCONF module/node parsing
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / main / java / org / opendaylight / controller / sal / restconf / impl / ControllerContext.java
index ebf0fd896a4089220e0125fa66753ca229ec9576..0a67c84d8b2b04c56a31fa2d7e9dd2e3e8821934 100644 (file)
@@ -17,6 +17,7 @@ import com.google.common.base.Strings;
 import com.google.common.collect.BiMap;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.HashBiMap;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 
 import java.io.UnsupportedEncodingException;
@@ -25,13 +26,14 @@ import java.net.URLDecoder;
 import java.net.URLEncoder;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicReference;
 
 import javax.ws.rs.core.Response.Status;
 
@@ -84,13 +86,12 @@ public class ControllerContext implements SchemaContextListener {
 
     private static final Splitter SLASH_SPLITTER = Splitter.on('/');
 
-    private static final Splitter COLON_SPLITTER = Splitter.on(':');
-
     private final BiMap<URI, String> uriToModuleName = HashBiMap.<URI, String> create();
 
     private final Map<String, URI> moduleNameToUri = uriToModuleName.inverse();
 
-    private final Map<QName, RpcDefinition> qnameToRpc = new ConcurrentHashMap<>();
+    private final AtomicReference<Map<QName, RpcDefinition>> qnameToRpc =
+            new AtomicReference<>(Collections.<QName, RpcDefinition>emptyMap());
 
     private volatile SchemaContext globalSchema;
     private volatile MountService mountService;
@@ -793,24 +794,31 @@ public class ControllerContext implements SchemaContextListener {
     }
 
     private static String toModuleName(final String str) {
-        Preconditions.<String> checkNotNull(str);
-        if (str.indexOf(':') != -1) {
-            final Iterable<String> args = COLON_SPLITTER.split(str);
-            if (Iterables.size(args) == 2) {
-                return args.iterator().next();
-            }
+        final int idx = str.indexOf(':');
+        if (idx == -1) {
+            return null;
         }
-        return null;
+
+        // Make sure there is only one occurrence
+        if (str.indexOf(':', idx + 1) != -1) {
+            return null;
+        }
+
+        return str.substring(0, idx);
     }
 
     private static String toNodeName(final String str) {
-        if (str.indexOf(':') != -1) {
-            final Iterable<String> args = COLON_SPLITTER.split(str);
-            if (Iterables.size(args) == 2) {
-                return Iterables.get(args, 1);
-            }
+        final int idx = str.indexOf(':');
+        if (idx == -1) {
+            return str;
         }
-        return str;
+
+        // Make sure there is only one occurrence
+        if (str.indexOf(':', idx + 1) != -1) {
+            return str;
+        }
+
+        return str.substring(idx + 1);
     }
 
     private QName toQName(final String name) {
@@ -846,26 +854,28 @@ public class ControllerContext implements SchemaContextListener {
         return namespace.isPresent() ? QName.create(namespace.get(), node) : null;
     }
 
-    private boolean isListOrContainer(final DataSchemaNode node) {
+    private static boolean isListOrContainer(final DataSchemaNode node) {
         return node instanceof ListSchemaNode || node instanceof ContainerSchemaNode;
     }
 
     public RpcDefinition getRpcDefinition(final String name) {
         final QName validName = this.toQName(name);
-        return validName == null ? null : this.qnameToRpc.get(validName);
+        return validName == null ? null : this.qnameToRpc.get().get(validName);
     }
 
     @Override
     public void onGlobalContextUpdated(final SchemaContext context) {
         if (context != null) {
-            this.qnameToRpc.clear();
-            this.setGlobalSchema(context);
-            Set<RpcDefinition> _operations = context.getOperations();
-            for (final RpcDefinition operation : _operations) {
-                {
-                    this.qnameToRpc.put(operation.getQName(), operation);
-                }
+            final Collection<RpcDefinition> defs = context.getOperations();
+            final Map<QName, RpcDefinition> newMap = new HashMap<>(defs.size());
+
+            for (final RpcDefinition operation : defs) {
+                newMap.put(operation.getQName(), operation);
             }
+
+            // FIXME: still not completely atomic
+            this.qnameToRpc.set(ImmutableMap.copyOf(newMap));
+            this.setGlobalSchema(context);
         }
     }