Merge "Hide credentials from logs"
[netconf.git] / restconf / restconf-nb-bierman02 / src / main / java / org / opendaylight / netconf / sal / restconf / impl / ControllerContext.java
index 988384c24e5c781628de53af49d3ea73f234b640..39a61379eb4daaa4a139c18afd317172e6fedb09 100644 (file)
@@ -7,13 +7,13 @@
  */
 package org.opendaylight.netconf.sal.restconf.impl;
 
-import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.io.Closeable;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URLDecoder;
@@ -28,14 +28,20 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Singleton;
 import javax.ws.rs.core.Response.Status;
+import org.apache.aries.blueprint.annotation.service.Reference;
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation;
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
-import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
-import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMMountPointService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
 import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider;
 import org.opendaylight.netconf.sal.rest.api.Draft02;
 import org.opendaylight.netconf.sal.rest.api.Draft02.RestConfModule;
@@ -45,6 +51,7 @@ import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
 import org.opendaylight.restconf.common.util.RestUtil;
 import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.Revision;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -74,15 +81,13 @@ import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class ControllerContext implements SchemaContextListener {
+@Singleton
+public final class ControllerContext implements SchemaContextListener, Closeable {
     // FIXME: this should be in md-sal somewhere
     public static final String MOUNT = "yang-ext:mount";
 
     private static final Logger LOG = LoggerFactory.getLogger(ControllerContext.class);
 
-    // FIXME: this should be the current instance which is mutated
-    private static final ControllerContext INSTANCE = new ControllerContext();
-
     private static final String NULL_VALUE = "null";
 
     private static final String MOUNT_MODULE = "yang-ext";
@@ -95,36 +100,42 @@ public class ControllerContext implements SchemaContextListener {
 
     private final AtomicReference<Map<QName, RpcDefinition>> qnameToRpc = new AtomicReference<>(Collections.emptyMap());
 
-    // FIXME; these three should be final
+    private final DOMMountPointService mountService;
+    private final DOMYangTextSourceProvider yangTextSourceProvider;
+    private final ListenerRegistration<SchemaContextListener> listenerRegistration;
     private volatile SchemaContext globalSchema;
-    private volatile DOMMountPointService mountService;
-    private volatile DOMYangTextSourceProvider yangTextSourceProvider;
-    private DataNormalizer dataNormalizer;
-
-
-    public void setGlobalSchema(final SchemaContext globalSchema) {
-        this.globalSchema = globalSchema;
-        this.dataNormalizer = new DataNormalizer(globalSchema);
-    }
+    private volatile DataNormalizer dataNormalizer;
 
-    public void setMountService(final DOMMountPointService mountService) {
+    @Inject
+    public ControllerContext(final @Reference DOMSchemaService schemaService,
+            final @Reference DOMMountPointService mountService, final @Reference DOMSchemaService domSchemaService) {
         this.mountService = mountService;
-    }
+        this.yangTextSourceProvider = domSchemaService.getExtensions().getInstance(DOMYangTextSourceProvider.class);
 
-    public DOMYangTextSourceProvider getYangTextSourceProvider() {
-        return yangTextSourceProvider;
+        onGlobalContextUpdated(schemaService.getGlobalContext());
+        listenerRegistration = schemaService.registerSchemaContextListener(this);
     }
 
-    public void setYangTextSourceProvider(DOMYangTextSourceProvider yangTextSourceProvider) {
-        this.yangTextSourceProvider = yangTextSourceProvider;
+    /**
+     * Factory method.
+     *
+     * @deprecated Just use the
+     *             {@link #ControllerContext(DOMSchemaService, DOMMountPointService, DOMSchemaService)}
+     *             constructor instead.
+     */
+    @Deprecated
+    public static ControllerContext newInstance(final DOMSchemaService schemaService,
+            final DOMMountPointService mountService, final DOMSchemaService domSchemaService) {
+        return new ControllerContext(schemaService, mountService, domSchemaService);
     }
 
-    ControllerContext() {
-
+    private void setGlobalSchema(final SchemaContext globalSchema) {
+        this.globalSchema = globalSchema;
+        this.dataNormalizer = new DataNormalizer(globalSchema);
     }
 
-    public static ControllerContext getInstance() {
-        return INSTANCE;
+    public DOMYangTextSourceProvider getYangTextSourceProvider() {
+        return yangTextSourceProvider;
     }
 
     private void checkPreconditions() {
@@ -133,6 +144,12 @@ public class ControllerContext implements SchemaContextListener {
         }
     }
 
+    @Override
+    @PreDestroy
+    public void close() {
+        listenerRegistration.close();
+    }
+
     public void setSchemas(final SchemaContext schemas) {
         onGlobalContextUpdated(schemas);
     }
@@ -502,7 +519,7 @@ public class ControllerContext implements SchemaContextListener {
             return childByQName((Module) container, name);
         } else {
             throw new IllegalArgumentException("Unhandled parameter types: "
-                    + Arrays.<Object>asList(container, name).toString());
+                    + Arrays.asList(container, name).toString());
         }
     }
 
@@ -522,9 +539,9 @@ public class ControllerContext implements SchemaContextListener {
         return ret;
     }
 
-    private static String toUriString(final Object object, final LeafSchemaNode leafNode, final DOMMountPoint mount)
+    private String toUriString(final Object object, final LeafSchemaNode leafNode, final DOMMountPoint mount)
             throws UnsupportedEncodingException {
-        final Codec<Object, Object> codec = RestCodec.from(leafNode.getType(), mount);
+        final Codec<Object, Object> codec = RestCodec.from(leafNode.getType(), mount, this);
         // FIXME: UrlEncoder looks up a well-known charset, we need something that will use it directly
         return object == null ? "" : URLEncoder.encode(codec.serialize(object).toString(), URI_ENCODING_CHARSET.name());
     }
@@ -533,7 +550,7 @@ public class ControllerContext implements SchemaContextListener {
     private InstanceIdentifierContext<?> collectPathArguments(final InstanceIdentifierBuilder builder,
             final List<String> strings, final DataNodeContainer parentNode, final DOMMountPoint mountPoint,
             final boolean returnJustMountPoint) {
-        Preconditions.<List<String>>checkNotNull(strings);
+        Preconditions.checkNotNull(strings);
 
         if (parentNode == null) {
             return null;
@@ -545,6 +562,12 @@ public class ControllerContext implements SchemaContextListener {
         }
 
         final String head = strings.iterator().next();
+
+        if (head.isEmpty()) {
+            final List<String> remaining = strings.subList(1, strings.size());
+            return collectPathArguments(builder, remaining, parentNode, mountPoint, returnJustMountPoint);
+        }
+
         final String nodeName = toNodeName(head);
         final String moduleName = toModuleName(head);
 
@@ -626,11 +649,10 @@ public class ControllerContext implements SchemaContextListener {
             if (targetNode == null && parentNode instanceof Module) {
                 final RpcDefinition rpc;
                 if (mountPoint == null) {
-                    rpc = ControllerContext.getInstance().getRpcDefinition(head, module.getRevision());
+                    rpc = getRpcDefinition(head, module.getRevision());
                 } else {
                     final String rpcName = toNodeName(head);
-                    ControllerContext.getInstance();
-                    rpc = ControllerContext.getRpcDefinition(module, rpcName);
+                    rpc = getRpcDefinition(module, rpcName);
                 }
                 if (rpc != null) {
                     return new InstanceIdentifierContext<>(builder.build(), rpc, mountPoint,
@@ -782,7 +804,7 @@ public class ControllerContext implements SchemaContextListener {
         if (baseType instanceof LeafrefTypeDefinition) {
             typedef = SchemaContextUtil.getBaseTypeForLeafRef((LeafrefTypeDefinition) baseType, schemaContext, node);
         }
-        final Codec<Object, Object> codec = RestCodec.from(typedef, mountPoint);
+        final Codec<Object, Object> codec = RestCodec.from(typedef, mountPoint, this);
         Object decoded = codec.deserialize(urlDecoded);
         String additionalInfo = "";
         if (decoded == null) {
@@ -1000,5 +1022,4 @@ public class ControllerContext implements SchemaContextListener {
     public DataNormalizationOperation<?> getRootOperation() {
         return this.dataNormalizer.getRootOperation();
     }
-
 }