Merge pull request #7725 from dbalek/dbalek/lsp-push-diagnostics

LSP: Push diagnostics collected on project indexing.
diff --git a/enterprise/cloud.oracle/external/binaries-list b/enterprise/cloud.oracle/external/binaries-list
index cc48847..68d8b5d 100644
--- a/enterprise/cloud.oracle/external/binaries-list
+++ b/enterprise/cloud.oracle/external/binaries-list
@@ -33,6 +33,7 @@
 A7D98B96CEA17F78E4BB9270B4A60FEBFACF6C78 com.oracle.oci.sdk:oci-java-sdk-core:3.25.3
 2236737DDF39CA3A3BABDB58B41F50C47E861EA7 com.oracle.oci.sdk:oci-java-sdk-containerengine:3.25.3
 923F38FE7186DFCBF921F9B3626832FFFFB8F6E9 com.oracle.oci.sdk:oci-java-sdk-artifacts:3.25.3
+99AE5824FBBABF71475404EE19AA480973CBD790 com.oracle.oci.sdk:oci-java-sdk-monitoring:3.25.3
 
 E5F6CAE5CA7ECAAC1EC2827A9E2D65AE2869CADA org.apache.httpcomponents:httpclient:4.5.13
 853B96D3AFBB7BF8CC303FE27EE96836A10C1834 org.apache.httpcomponents:httpcore:4.4.13
diff --git a/enterprise/cloud.oracle/external/oci-java-sdk-3.25.3-license.txt b/enterprise/cloud.oracle/external/oci-java-sdk-3.25.3-license.txt
index 10b6404..cb25afd 100644
--- a/enterprise/cloud.oracle/external/oci-java-sdk-3.25.3-license.txt
+++ b/enterprise/cloud.oracle/external/oci-java-sdk-3.25.3-license.txt
@@ -3,7 +3,7 @@
 Origin: https://github.com/oracle/oci-java-sdk
 Version: 3.25.3
 License: UPL-Apache-2.0
-Files: oci-java-sdk-circuitbreaker-3.25.3.jar, oci-java-sdk-common-3.25.3.jar, oci-java-sdk-database-3.25.3.jar, oci-java-sdk-identity-3.25.3.jar, oci-java-sdk-workrequests-3.25.3.jar, oci-java-sdk-adm-3.25.3.jar, oci-java-sdk-devops-3.25.3.jar, oci-java-sdk-addons-apache-configurator-jersey-3.25.3.jar, oci-java-sdk-common-httpclient-3.25.3.jar, oci-java-sdk-common-httpclient-jersey-3.25.3.jar oci-java-sdk-keymanagement-3.25.3.jar oci-java-sdk-vault-3.25.3.jar oci-java-sdk-containerengine-3.25.3.jar oci-java-sdk-core-3.25.3.jar oci-java-sdk-objectstorage-3.25.3.jar oci-java-sdk-objectstorage-extensions-3.25.3.jar oci-java-sdk-objectstorage-generated-3.25.3.jar, oci-java-sdk-artifacts-3.25.3.jar
+Files: oci-java-sdk-circuitbreaker-3.25.3.jar, oci-java-sdk-common-3.25.3.jar, oci-java-sdk-database-3.25.3.jar, oci-java-sdk-identity-3.25.3.jar, oci-java-sdk-workrequests-3.25.3.jar, oci-java-sdk-adm-3.25.3.jar, oci-java-sdk-devops-3.25.3.jar, oci-java-sdk-addons-apache-configurator-jersey-3.25.3.jar, oci-java-sdk-common-httpclient-3.25.3.jar, oci-java-sdk-common-httpclient-jersey-3.25.3.jar oci-java-sdk-keymanagement-3.25.3.jar oci-java-sdk-vault-3.25.3.jar oci-java-sdk-containerengine-3.25.3.jar oci-java-sdk-core-3.25.3.jar oci-java-sdk-objectstorage-3.25.3.jar oci-java-sdk-objectstorage-extensions-3.25.3.jar oci-java-sdk-objectstorage-generated-3.25.3.jar, oci-java-sdk-artifacts-3.25.3.jar, oci-java-sdk-monitoring-3.25.3.jar
 
 Copyright (c) 2016, 2020, Oracle and/or its affiliates.  All rights reserved.
 
diff --git a/enterprise/cloud.oracle/nbproject/project.properties b/enterprise/cloud.oracle/nbproject/project.properties
index 293786f..32bb84d 100644
--- a/enterprise/cloud.oracle/nbproject/project.properties
+++ b/enterprise/cloud.oracle/nbproject/project.properties
@@ -34,6 +34,7 @@
 release.external/oci-java-sdk-core-3.25.3.jar=modules/ext/oci-java-sdk-core-3.25.3.jar
 release.external/oci-java-sdk-containerengine-3.25.3.jar=modules/ext/oci-java-sdk-containerengine-3.25.3.jar
 release.external/oci-java-sdk-artifacts-3.25.3.jar=modules/ext/oci-java-sdk-artifacts-3.25.3.jar
+release.external/oci-java-sdk-monitoring-3.25.3.jar=modules/ext/oci-java-sdk-monitoring-3.25.3.jar
 release.external/httpclient-4.5.13.jar=modules/ext/httpclient-4.5.13.jar
 release.external/httpcore-4.4.13.jar=modules/ext/httpcore-4.4.13.jar
 release.external/javassist-3.25.0-GA.jar=modules/ext/javassist-3.25.0-GA.jar
@@ -41,7 +42,7 @@
 release.external/resilience4j-core-1.7.1.jar=modules/ext/resilience4j-core-1.7.1.jar
 release.external/vavr-0.10.2.jar=modules/ext/vavr-0.10.2.jar
 release.external/vavr-match-0.10.2.jar=modules/ext/vavr-match-0.10.2.jar
-javac.source=1.8
+javac.release=11
 javac.compilerargs=-Xlint -Xlint:-serial
 requires.nb.javac=true
 spec.version.base.fatal.warning=false
diff --git a/enterprise/cloud.oracle/nbproject/project.xml b/enterprise/cloud.oracle/nbproject/project.xml
index 436a865..e36ecd4 100644
--- a/enterprise/cloud.oracle/nbproject/project.xml
+++ b/enterprise/cloud.oracle/nbproject/project.xml
@@ -378,6 +378,10 @@
                 <binary-origin>external/oci-java-sdk-artifacts-3.25.3.jar</binary-origin>
             </class-path-extension>
             <class-path-extension>
+                <runtime-relative-path>ext/oci-java-sdk-monitoring-3.25.3.jar</runtime-relative-path>
+                <binary-origin>external/oci-java-sdk-monitoring-3.25.3.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
                 <runtime-relative-path>ext/httpclient-4.5.13.jar</runtime-relative-path>
                 <binary-origin>external/httpclient-4.5.13.jar</binary-origin>
             </class-path-extension>
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/adm/ShowInBrowserAction.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/adm/ShowInBrowserAction.java
index 6dd876d..4c3ed84 100644
--- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/adm/ShowInBrowserAction.java
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/adm/ShowInBrowserAction.java
@@ -45,6 +45,7 @@
     @ActionReference(path = "Cloud/Oracle/KnowledgeBase/Actions", position = 260),
     @ActionReference(path = "Cloud/Oracle/Vulnerability/Actions", position = 260),
     @ActionReference(path = "Cloud/Oracle/VulnerabilityAudit/Actions", position = 260),
+    @ActionReference(path = "Cloud/Oracle/MetricsNamespace/Metrics/Actions", position = 260),
 })
 
 @NbBundle.Messages({
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/AddNewAssetCommand.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/AddNewAssetCommand.java
index 107b880..67ec5de 100644
--- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/AddNewAssetCommand.java
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/AddNewAssetCommand.java
@@ -59,9 +59,17 @@
             put("Databases", new String[]{"io.micronaut.oraclecloud", "micronaut-oraclecloud-atp"}); //NOI18N
             put("Bucket", new String[]{"io.micronaut.objectstorage", "micronaut-object-storage-oracle-cloud"}); //NOI18N
             put("Vault", new String[]{"io.micronaut.oraclecloud", "micronaut-oraclecloud-vault"}); //NOI18N
+            put("MetricsNamespace", new String[]{"io.micronaut.oraclecloud", "micronaut-oraclecloud-micrometer"}); //NOI18N
         }
     };
 
+    private static final Map<String, String[]> ANNOTATION_PROCESSOR_MAP = new HashMap() {
+        {
+            put("MetricsNamespace", new String[]{"io.micronaut.micrometer", "micronaut-micrometer-annotation"}); //NOI18N
+        }
+    };
+
+        
     @Override
     public Set<String> getCommands() {
         return Collections.unmodifiableSet(COMMANDS);
@@ -78,16 +86,15 @@
                         return new TenancyStep();
                     }).stepForClass(TenancyStep.class, (s) -> new CompartmentStep())
                     .stepForClass(CompartmentStep.class, (s) -> new SuggestedStep(null))
-                    .stepForClass(SuggestedStep.class, (s) ->  new ProjectStep())
+                    .stepForClass(SuggestedStep.class, (s) -> new ProjectStep())
                     .build();
-        
         Steps.getDefault()
                 .executeMultistep(new ItemTypeStep(), Lookups.fixed(nsProvider))
                 .thenAccept(values -> {
                     Project project = values.getValueForStep(ProjectStep.class);
                     CompletableFuture<? extends OCIItem> item = null;
                     String itemType = values.getValueForStep(ItemTypeStep.class);
-                    if ("Databases".equals(itemType)) { 
+                    if ("Databases".equals(itemType)) {
                         DatabaseItem i = values.getValueForStep(DatabaseConnectionStep.class);
                         if (i == null) {
                             item = new AddADBAction().addADB();
@@ -117,15 +124,20 @@
                     item.thenAccept(i -> {
                         CloudAssets.getDefault().addItem(i);
                         String[] art = DEP_MAP.get(i.getKey().getPath());
+                        String[] processor = ANNOTATION_PROCESSOR_MAP.get(i.getKey().getPath());
                         try {
-                            DependencyUtils.addDependency(project, art[0], art[1]);
-                            future.complete(null);
+                            if (art != null && art.length > 1) {
+                                DependencyUtils.addDependency(project, art[0], art[1]);
+                            }
+                            if (processor != null && processor.length > 1) {
+                                DependencyUtils.addAnnotationProcessor(project, processor[0], processor[1]);
+                            }
                         } catch (IllegalStateException e) {
                             future.completeExceptionally(e);
                         }
+                        future.complete(null);
                     });
                 });
         return future;
     }
-    
 }
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CloudAssets.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CloudAssets.java
index d7bee23..35782a3 100644
--- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CloudAssets.java
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CloudAssets.java
@@ -56,6 +56,7 @@
 import org.netbeans.modules.cloud.oracle.compute.ComputeInstanceItem;
 import org.netbeans.modules.cloud.oracle.database.DatabaseItem;
 import org.netbeans.modules.cloud.oracle.developer.ContainerRepositoryItem;
+import org.netbeans.modules.cloud.oracle.developer.MetricsNamespaceItem;
 import org.netbeans.modules.cloud.oracle.items.OCID;
 import org.netbeans.modules.cloud.oracle.items.OCIItem;
 import org.netbeans.modules.cloud.oracle.vault.VaultItem;
@@ -358,6 +359,9 @@
                                 case "ContainerRepository": //NOI18N
                                     loaded.add(gson.fromJson(element, ContainerRepositoryItem.class));
                                     break;
+                                case "MetricsNamespace": //NOI18N
+                                    loaded.add(gson.fromJson(element, MetricsNamespaceItem.class));
+                                    break;
                             }
                         }
                         reader.endArray();
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/ConfigFileGenerator.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/ConfigFileGenerator.java
new file mode 100644
index 0000000..d9d757f
--- /dev/null
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/ConfigFileGenerator.java
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cloud.oracle.assets;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.attribute.AclEntry;
+import java.nio.file.attribute.AclEntryPermission;
+import static java.nio.file.attribute.AclEntryPermission.APPEND_DATA;
+import static java.nio.file.attribute.AclEntryPermission.READ_ACL;
+import static java.nio.file.attribute.AclEntryPermission.READ_ATTRIBUTES;
+import static java.nio.file.attribute.AclEntryPermission.READ_DATA;
+import static java.nio.file.attribute.AclEntryPermission.READ_NAMED_ATTRS;
+import static java.nio.file.attribute.AclEntryPermission.SYNCHRONIZE;
+import static java.nio.file.attribute.AclEntryPermission.WRITE_ACL;
+import static java.nio.file.attribute.AclEntryPermission.WRITE_ATTRIBUTES;
+import static java.nio.file.attribute.AclEntryPermission.WRITE_DATA;
+import static java.nio.file.attribute.AclEntryPermission.WRITE_NAMED_ATTRS;
+import java.nio.file.attribute.AclFileAttributeView;
+import java.nio.file.attribute.DosFileAttributeView;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFilePermission;
+import static java.nio.file.attribute.PosixFilePermission.OWNER_READ;
+import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Properties;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.openide.modules.Places;
+
+/**
+ *
+ * @author Dusan Petrovic
+ */
+public class ConfigFileGenerator {
+    
+    private static final Logger LOG = Logger.getLogger(ConfigFileGenerator.class.getName());
+
+    private static final boolean POSIX = FileSystems.getDefault().supportedFileAttributeViews().contains("posix");  // NOI18N
+    private static final EnumSet<PosixFilePermission> readWritePosix = EnumSet.of(OWNER_READ, OWNER_WRITE);
+    private static final EnumSet<PosixFilePermission> readPosix = EnumSet.of(OWNER_READ);
+
+    private static final EnumSet<AclEntryPermission> readOnlyAcl = EnumSet.of(
+                READ_ACL,
+                READ_ATTRIBUTES,
+                READ_DATA,
+                READ_NAMED_ATTRS,
+                SYNCHRONIZE
+        );
+
+    private static final EnumSet<AclEntryPermission> readWriteAcl = EnumSet.of(
+                READ_DATA,
+                WRITE_DATA,
+                APPEND_DATA,
+                READ_NAMED_ATTRS,
+                WRITE_NAMED_ATTRS,
+                READ_ATTRIBUTES,
+                WRITE_ATTRIBUTES,
+                READ_ACL,
+                WRITE_ACL
+        );
+    
+    private final boolean readOnly;
+    private final String filePrefix;
+    private final String fileSufix;
+    private final String configPath;
+
+    public ConfigFileGenerator(String filePrefix, String fileSufix, String configPath, boolean readOnly) {
+        this.readOnly = readOnly;
+        this.configPath = configPath;
+        this.filePrefix = filePrefix;
+        this.fileSufix = fileSufix;
+    }
+    
+    public Path writePropertiesFile(Properties props) throws IOException {
+        Path temp = null;
+        try {
+            temp = generateConfigFile();
+            writePropertiesToFile(props, temp);
+        } catch (IOException ex) {
+            deleteTempFile(temp);
+            throw ex;
+        }
+        
+        return temp;
+    }
+    
+    private Path generateConfigFile() throws IOException {
+        Path dir = generateDirPath();
+        
+        if (!Files.isDirectory(dir, LinkOption.NOFOLLOW_LINKS)) {
+            Files.createDirectory(dir);
+        }
+        if (POSIX) {
+            return createFilePosix(dir);       
+        } 
+        
+        Path temp = Files.createTempFile(dir, this.filePrefix, this.fileSufix);
+        setFileOwnerAcl(temp, readWriteAcl);
+        return temp;
+    }
+    
+    private void writePropertiesToFile(Properties props, Path filePath) throws IOException {
+        try (Writer writer = new FileWriter(filePath.toFile(), Charset.defaultCharset());) {
+            props.store(writer, "");
+            if (POSIX) {
+                setFilePermissionPosix(filePath);
+            } else {
+                if (readOnly) {
+                    DosFileAttributeView attribs = Files.getFileAttributeView(filePath, DosFileAttributeView.class);
+                    attribs.setReadOnly(true);
+                    setFileOwnerAcl(filePath, readOnlyAcl);
+                } else {
+                    setFileOwnerAcl(filePath, readWriteAcl);
+                }
+            }
+            filePath.toFile().deleteOnExit();
+        }
+    }
+    
+    private void setFileOwnerAcl(Path filePath, Set<AclEntryPermission> permissions) throws IOException {
+        AclFileAttributeView acl = Files.getFileAttributeView(filePath, AclFileAttributeView.class);
+        AclEntry ownerEntry = findFileOwner(acl);
+        
+        if (ownerEntry == null) {
+            throw new IOException("Owner missing, file:" + filePath.toString()); // NOI18N
+        } 
+
+        AclEntry ownerAcl = AclEntry.newBuilder(ownerEntry).setPermissions(permissions).build();
+        acl.setAcl(Collections.singletonList(ownerAcl));
+    }
+
+    private AclEntry findFileOwner(AclFileAttributeView acl) throws IOException {
+        for(AclEntry e : acl.getAcl()) {
+            if (e.principal().equals(acl.getOwner())) {
+                return e;
+            }
+        }
+        return null;
+    }
+    
+    private void setFilePermissionPosix(Path temp) throws IOException {
+        PosixFileAttributeView attributes = Files.getFileAttributeView(temp, PosixFileAttributeView.class);
+        if (this.readOnly) {
+            attributes.setPermissions(readPosix);
+        } else {
+            attributes.setPermissions(readWritePosix);
+        }
+    }
+    
+    
+    private Path createFilePosix(Path dir) throws IOException {
+        FileAttribute<?> readWriteAttribs = PosixFilePermissions.asFileAttribute(readWritePosix);
+        return Files.createTempFile(dir,this.filePrefix, this.fileSufix, readWriteAttribs);
+    }
+    
+    private Path generateDirPath() {
+        File file = Places.getCacheSubdirectory(this.configPath);
+        file.deleteOnExit();
+        return file.toPath();
+    }
+    
+    private void deleteTempFile(Path temp) {
+        if (temp != null && Files.isRegularFile(temp, LinkOption.NOFOLLOW_LINKS)) {
+            try {
+                if (POSIX) {
+                    PosixFileAttributeView attribs = Files.getFileAttributeView(temp, PosixFileAttributeView.class);
+                    attribs.setPermissions(readWritePosix);
+                } else {
+                    DosFileAttributeView attribs = Files.getFileAttributeView(temp, DosFileAttributeView.class);
+                    attribs.setReadOnly(false);
+                }
+                Files.delete(temp);
+            } catch (IOException ex) {
+                LOG.log(Level.WARNING, "deleteTempFile", ex);
+            }
+        }
+    }
+}
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/ConfigFileProvider.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/ConfigFileProvider.java
new file mode 100644
index 0000000..f04e4ed
--- /dev/null
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/ConfigFileProvider.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cloud.oracle.assets;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import org.netbeans.spi.lsp.CommandProvider;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ *
+ * @author Dusan Petrovic
+ */
+@ServiceProvider(service = CommandProvider.class)
+public class ConfigFileProvider implements CommandProvider {
+    private static final String GET_CONFIG_FILE_PATH = "nbls.config.file.path"; //NOI18N
+
+    private final ConfigFileGenerator applicationPropertiesFileGenerator;
+    private final ConfigFileGenerator bootstrapPropertiesFileGenerator;
+
+    public ConfigFileProvider() {
+        this.applicationPropertiesFileGenerator = new ConfigFileGenerator("application-", ".properties", GET_CONFIG_FILE_PATH, false); // NOI18N
+        this.bootstrapPropertiesFileGenerator = new ConfigFileGenerator("bootstrap-", ".properties", GET_CONFIG_FILE_PATH, false); // NOI18N
+    }
+    
+    @Override
+    public Set<String> getCommands() {
+        return Collections.singleton(GET_CONFIG_FILE_PATH);
+    }
+
+    @Override
+    public CompletableFuture<Object> runCommand(String command, List<Object> arguments) {
+        CompletableFuture ret = new CompletableFuture();
+
+        Properties applicationProps = new Properties();
+        Properties bootstrapProps = new Properties();
+        PropertiesGenerator propGen = new PropertiesGenerator(false);
+        
+        applicationProps.putAll(propGen.getApplication());
+        bootstrapProps.putAll(propGen.getBootstrap());
+        
+        String applicationPropertiesPath = null;
+        String bootstrapPropertiesPath = null;  
+        try {
+            if (!bootstrapProps.isEmpty()) {
+                Path bootstrapProperties = bootstrapPropertiesFileGenerator.writePropertiesFile(bootstrapProps);
+                bootstrapPropertiesPath = bootstrapProperties.toAbsolutePath().toString();
+            }
+            
+            if (!applicationProps.isEmpty()) {
+                Path applicationProperties = applicationPropertiesFileGenerator.writePropertiesFile(applicationProps);
+                applicationPropertiesPath = applicationProperties.toAbsolutePath().toString();
+            }
+            ret.complete(new ConfigFilesResponse(applicationPropertiesPath, bootstrapPropertiesPath));
+        } catch (IOException ex) {
+            ret.completeExceptionally(ex);
+            return ret;
+        }
+        
+        return ret;
+    }
+    
+    private class ConfigFilesResponse {
+        
+        final String applicationProperties;
+        final String bootstrapProperties;
+
+        public ConfigFilesResponse(String applicationProperties, String bootstrapProperties) {
+            this.applicationProperties = applicationProperties;
+            this.bootstrapProperties = bootstrapProperties;
+        }
+    }
+}
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/DependenciesAnalyzer.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/DependenciesAnalyzer.java
index 3fd0013f..4df0d9a 100644
--- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/DependenciesAnalyzer.java
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/DependenciesAnalyzer.java
@@ -39,6 +39,7 @@
             put("micronaut-oraclecloud-atp", "Databases"); //NOI18N
             put("micronaut-object-storage-oracle-cloud", "Bucket"); //NOI18N
             put("micronaut-oraclecloud-vault", "Vault"); //NOI18N
+            put("micronaut-oraclecloud-micrometer", "MetricsNamespace"); //NOI18N        
         }
     };
 
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/DependencyUtils.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/DependencyUtils.java
index 5d55480..77e63b2 100644
--- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/DependencyUtils.java
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/DependencyUtils.java
@@ -26,7 +26,9 @@
 import org.netbeans.modules.project.dependency.ArtifactSpec;
 import org.netbeans.modules.project.dependency.Dependency;
 import org.netbeans.modules.project.dependency.DependencyChange;
+import org.netbeans.modules.project.dependency.DependencyChange.Options;
 import org.netbeans.modules.project.dependency.DependencyChangeException;
+import org.netbeans.modules.project.dependency.DependencyChangeRequest;
 import org.netbeans.modules.project.dependency.ProjectDependencies;
 import org.netbeans.modules.project.dependency.ProjectOperationException;
 import org.netbeans.modules.project.dependency.Scopes;
@@ -38,12 +40,49 @@
  * @author Jan Horvath
  */
 public class DependencyUtils {
-    
+
     public static void addDependency(Project project, String groupId, String artifactId) {
+        Project projectToModify = getProjectToModify(project, "oci");
+        
+        if (projectToModify != null) {
+            ArtifactSpec spec = ArtifactSpec.make(groupId, artifactId);
+            Dependency dep = Dependency.make(spec, Scopes.COMPILE);
+            DependencyChange change = DependencyChange.add(Collections.singletonList(dep), Options.skipConflicts);
+            try {
+                ModificationResult mod = ProjectDependencies.modifyDependencies(projectToModify, change);
+                mod.commit();
+            } catch (IOException | DependencyChangeException | ProjectOperationException ex) {
+                throw new IllegalStateException(ex);
+            }
+        }
+    }
+    
+    public static void addAnnotationProcessor(Project project, String groupId, String artifactId) {
+        Project projectToModify = getProjectToModify(project, "lib");
+        
+        if (projectToModify != null) {
+            ArtifactSpec spec = ArtifactSpec.make(groupId, artifactId);
+            Dependency dep = Dependency.make(spec, Scopes.PROCESS);
+            DependencyChange change = DependencyChange.builder(DependencyChange.Kind.ADD)
+                    .dependency(dep)
+                    .option(Options.skipConflicts)
+                    .create();
+
+            try {
+                ModificationResult mod = ProjectDependencies
+                        .modifyDependencies(projectToModify, new DependencyChangeRequest(Collections.singletonList(change)));
+                mod.commit();
+            } catch (IOException | DependencyChangeException | ProjectOperationException ex) {
+                throw new IllegalStateException(ex);
+            }
+        }
+    }
+    
+    private static Project getProjectToModify(Project project, String projectDirectory) {
         Project projectToModify = null;
         Set<Project> subProjects = ProjectUtils.getContainedProjects(project, false);
         for (Project subProject : subProjects) {
-            if ("oci".equals(subProject.getProjectDirectory().getName())) { //NOI18N
+            if (projectDirectory.equals(subProject.getProjectDirectory().getName())) { //NOI18N
                 projectToModify = subProject;
                 break;
             }
@@ -51,17 +90,7 @@
         if (projectToModify == null) {
             projectToModify = project;
         }
-        if (projectToModify != null) {
-            ArtifactSpec spec = ArtifactSpec.make(groupId, artifactId);
-            Dependency dep = Dependency.make(spec, Scopes.COMPILE);
-            DependencyChange change = DependencyChange.add(Collections.singletonList(dep), DependencyChange.Options.skipConflicts);
-            try {
-                ModificationResult mod = ProjectDependencies.modifyDependencies(projectToModify, change);
-                mod.commit();
-            } catch (IOException | DependencyChangeException | ProjectOperationException ex) {
-                throw new IllegalStateException(ex);
-            } 
-        }
+        
+        return projectToModify;
     }
-    
 }
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/OCIPropertiesProvider.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/OCIPropertiesProvider.java
index 89f469b..bdc85ab 100644
--- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/OCIPropertiesProvider.java
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/OCIPropertiesProvider.java
@@ -19,35 +19,15 @@
 package org.netbeans.modules.cloud.oracle.assets;
 
 
-import java.io.FileWriter;
 import java.io.IOException;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
 import java.nio.file.Path;
-import java.nio.file.attribute.AclEntry;
-import java.nio.file.attribute.AclEntryPermission;
-import static java.nio.file.attribute.AclEntryPermission.*;
-import java.nio.file.attribute.AclFileAttributeView;
-import java.nio.file.attribute.DosFileAttributeView;
-import java.nio.file.attribute.FileAttribute;
-import java.nio.file.attribute.PosixFileAttributeView;
-import java.nio.file.attribute.PosixFilePermission;
-import static java.nio.file.attribute.PosixFilePermission.*;
-import java.nio.file.attribute.PosixFilePermissions;
 import java.util.Collections;
-import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 import org.netbeans.api.db.explorer.ConnectionManager;
 import org.netbeans.api.db.explorer.DatabaseConnection;
 import org.netbeans.spi.lsp.CommandProvider;
@@ -59,22 +39,12 @@
  */
 @ServiceProvider(service = CommandProvider.class)
 public class OCIPropertiesProvider implements CommandProvider {
-    private static final Logger LOG = Logger.getLogger(OCIPropertiesProvider.class.getName());
     private static final String  GET_DB_CONNECTION = "nbls.db.connection"; //NOI18N
 
-    private static final boolean POSIX = FileSystems.getDefault().supportedFileAttributeViews().contains("posix");  // NOI18N
-    private static final EnumSet<PosixFilePermission> readWritePosix = EnumSet.of(OWNER_READ, OWNER_WRITE);
-    private static final EnumSet<AclEntryPermission> readOnlyAcl = EnumSet.of(READ_ACL, READ_ATTRIBUTES, WRITE_ATTRIBUTES, READ_DATA, READ_NAMED_ATTRS, DELETE, SYNCHRONIZE);
-
-    // temporary directory location
-    private static final Path tmpdir = Path.of(System.getProperty("java.io.tmpdir"));       // NOI18N
+    private final ConfigFileGenerator configFileGenerator;
 
     public OCIPropertiesProvider() {
-        try {
-            deleteOldFiles(generateDirPath());
-        } catch (IOException ex) {
-            LOG.log(Level.SEVERE, "deleteOldFiles", ex);
-        }
+        this.configFileGenerator = new ConfigFileGenerator("db-", ".properties", GET_DB_CONNECTION, true); // NOI18N
     }
 
     @Override
@@ -99,80 +69,15 @@
             }
         }
         if (!dbProps.isEmpty()) {
-            Path temp = null;
-            Path dir = generateDirPath();
-
             try {
-                if (!Files.isDirectory(dir, LinkOption.NOFOLLOW_LINKS)) {
-                    Files.createDirectory(dir);
-                }
-                if (POSIX) {
-                    FileAttribute<?> readWriteAttribs = PosixFilePermissions.asFileAttribute(readWritePosix);
-                    temp = Files.createTempFile(dir, "db-", ".properties", readWriteAttribs);       // NOI18N
-                } else {
-                    temp = Files.createTempFile(dir, "db-", ".properties");                         // NOI18N
-                    AclFileAttributeView acl = Files.getFileAttributeView(temp, AclFileAttributeView.class);
-                    AclEntry ownerEntry = null;
-                    for(AclEntry e : acl.getAcl()) {
-                        if (e.principal().equals(acl.getOwner())) {
-                            ownerEntry = e;
-                            break;
-                        }
-                    }
-                    if (ownerEntry != null) {
-                        acl.setAcl(Collections.singletonList(ownerEntry));
-                    } else {
-                        deleteTempFile(temp);
-                        ret.completeExceptionally(new IOException("Owner missing, file:"+temp.toString())); // NOI18N
-                        return ret;
-                    }
-                }
+                Path temp = configFileGenerator.writePropertiesFile(dbProps);
+                result.put("MICRONAUT_CONFIG_FILES", temp.toAbsolutePath().toString()); // NOI18N
+                ret.complete(result);
             } catch (IOException ex) {
-                deleteTempFile(temp);
-                ret.completeExceptionally(ex);
-                return ret;
-            }
-
-            try (Writer writer = new FileWriter(temp.toFile(), Charset.defaultCharset());) {
-                dbProps.store(writer, "");
-                if (POSIX) {
-                    PosixFileAttributeView attribs = Files.getFileAttributeView(temp, PosixFileAttributeView.class);
-                    attribs.setPermissions(EnumSet.of(OWNER_READ));
-                } else {
-                    DosFileAttributeView attribs = Files.getFileAttributeView(temp, DosFileAttributeView.class);
-                    attribs.setReadOnly(true);
-                    AclFileAttributeView acl = Files.getFileAttributeView(temp, AclFileAttributeView.class);
-                    AclEntry ownerEntry = null;
-                    if (acl.getAcl().size() != 1) {
-                        deleteTempFile(temp);
-                        ret.completeExceptionally(new IOException("Too many Acls, file:"+temp.toString()));     // NOI18N
-                        return ret;
-                    }
-                    for(AclEntry e : acl.getAcl()) {
-                        if (e.principal().equals(acl.getOwner())) {
-                            ownerEntry = e;
-                            break;
-                        }
-                    }
-                    if (ownerEntry != null) {
-                        AclEntry readOnly = AclEntry.newBuilder(ownerEntry).setPermissions(readOnlyAcl).build();
-                        acl.setAcl(Collections.singletonList(readOnly));
-                    } else {
-                        deleteTempFile(temp);
-                        ret.completeExceptionally(new IOException("Owner missing, file:"+temp.toString()));     // NOI18N
-                        return ret;
-                    }
-                }
-                temp.toFile().deleteOnExit();
-                result.put("MICRONAUT_CONFIG_FILES", temp.toAbsolutePath().toString());     // NOI18N
-            } catch (IOException ex) {
-                deleteTempFile(temp);
                 ret.completeExceptionally(ex);
                 return ret;
             }
         }
-
-        ret.complete(result);
         return ret;
     }
 
@@ -180,38 +85,4 @@
     public Set<String> getCommands() {
         return Collections.singleton(GET_DB_CONNECTION);
     }
-
-    private static Path generateDirPath() {
-        String s = GET_DB_CONNECTION + "_" + System.getProperty("user.name");       // NOI18N
-        Path name = tmpdir.getFileSystem().getPath(s);
-        return tmpdir.resolve(name);
-    }
-
-    private static void deleteOldFiles(Path dir) throws IOException {
-        if (Files.isDirectory(dir, LinkOption.NOFOLLOW_LINKS)) {
-            try (DirectoryStream<Path> stream  = Files.newDirectoryStream(dir)) {
-                for (Path f : stream) {
-                    deleteTempFile(f);
-                }
-            }
-        }
-    }
-
-    private static void deleteTempFile(Path temp) {
-        if (temp != null && Files.isRegularFile(temp, LinkOption.NOFOLLOW_LINKS)) {
-            try {
-                if (POSIX) {
-                    PosixFileAttributeView attribs = Files.getFileAttributeView(temp, PosixFileAttributeView.class);
-                    attribs.setPermissions(readWritePosix);
-                } else {
-                    DosFileAttributeView attribs = Files.getFileAttributeView(temp, DosFileAttributeView.class);
-                    attribs.setReadOnly(false);
-                }
-                Files.delete(temp);
-            } catch (IOException ex) {
-                LOG.log(Level.WARNING, "deleteTempFile", ex);
-            }
-        }
-    }
-    
 }
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/PropertiesGenerator.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/PropertiesGenerator.java
index d6b86ef..9adcad1 100644
--- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/PropertiesGenerator.java
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/PropertiesGenerator.java
@@ -28,6 +28,7 @@
 import org.netbeans.api.db.explorer.ConnectionManager;
 import org.netbeans.api.db.explorer.DatabaseConnection;
 import org.netbeans.modules.cloud.oracle.bucket.BucketItem;
+import org.netbeans.modules.cloud.oracle.developer.MetricsNamespaceItem;
 import org.netbeans.modules.cloud.oracle.items.OCIItem;
 import org.netbeans.modules.cloud.oracle.vault.VaultItem;
 
@@ -53,7 +54,18 @@
             "oci.config.instance-principal.enabled",
             "oci.vault.config.enabled",
             "oci.vault.vaults[0].ocid",
-            "oci.vault.vaults[0].compartment-ocid"
+            "oci.vault.vaults[0].compartment-ocid",
+            "micronaut.metrics.enabled",
+            "micronaut.metrics.binders.files.enabled",
+            "micronaut.metrics.binders.jdbc.enabled",
+            "micronaut.metrics.binders.jvm.enabled",
+            "micronaut.metrics.binders.logback.enabled",
+            "micronaut.metrics.binders.processor.enabled",
+            "micronaut.metrics.binders.uptime.enabled",
+            "micronaut.metrics.binders.web.enabled",
+            "micronaut.metrics.export.oraclecloud.enabled",
+            "micronaut.metrics.export.oraclecloud.namespace",
+            "micronaut.metrics.export.oraclecloud.compartmentId"
     );
 
     public PropertiesGenerator(boolean local) {
@@ -113,6 +125,20 @@
                             }
                         }
                     }
+                    break;
+                case "MetricsNamespace": //NOI18N                    
+                    application.put("micronaut.metrics.enabled", "true"); //NOI18N
+                    application.put("micronaut.metrics.binders.files.enabled", "true"); //NOI18N
+                    application.put("micronaut.metrics.binders.jdbc.enabled", "true"); //NOI18N
+                    application.put("micronaut.metrics.binders.jvm.enabled", "true"); //NOI18N
+                    application.put("micronaut.metrics.binders.logback.enabled", "true"); //NOI18N
+                    application.put("micronaut.metrics.binders.processor.enabled", "true"); //NOI18N
+                    application.put("micronaut.metrics.binders.uptime.enabled", "true"); //NOI18N
+                    application.put("micronaut.metrics.binders.web.enabled", "true"); //NOI18N
+                    application.put("micronaut.metrics.export.oraclecloud.enabled", "true"); //NOI18N
+                    application.put("micronaut.metrics.export.oraclecloud.namespace", ((MetricsNamespaceItem) item).getName()); //NOI18N
+                    application.put("micronaut.metrics.export.oraclecloud.compartmentId", ((MetricsNamespaceItem) item).getCompartmentId()); //NOI18N
+
             }
         }
         if (!local) {
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/SuggestedItem.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/SuggestedItem.java
index 3726f69..ed1092b 100644
--- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/SuggestedItem.java
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/SuggestedItem.java
@@ -34,7 +34,8 @@
     "SelectBucket=Select Object Storage Bucket",
     "SelectCluster=Select Oracle Container Engine for Kubernetes",
     "SelectCompute=Select Compute Instance",
-    "SelectContainerRepository=Select Container Repository"
+    "SelectContainerRepository=Select Container Repository",
+    "SelectMetricsNamespace=Select Metrics Namespace"
 })
 public final class SuggestedItem extends OCIItem {
 
@@ -69,6 +70,8 @@
                 return new SuggestedItem("ComputeInstance", Bundle.SelectCompute(), Collections.singleton("Cluster")); //NOI18N
             case "ContainerRepository": //NOI18N
                 return new SuggestedItem("ContainerRepository", Bundle.SelectContainerRepository(), Collections.singleton("ContainerRepository")); //NOI18N
+            case "MetricsNamespace": //NOI18N
+                return new SuggestedItem("MetricsNamespace", Bundle.SelectMetricsNamespace(), Collections.singleton("MetricsNamespace")); //NOI18N
             default:
                 throw new IllegalArgumentException("");
         }
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/MetricsItem.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/MetricsItem.java
new file mode 100644
index 0000000..04256ff
--- /dev/null
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/MetricsItem.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cloud.oracle.developer;
+
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
+import org.netbeans.modules.cloud.oracle.adm.URLProvider;
+import org.netbeans.modules.cloud.oracle.items.OCID;
+import org.netbeans.modules.cloud.oracle.items.OCIItem;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Dusan Petrovic
+ */
+public class MetricsItem extends OCIItem implements URLProvider {
+    
+    private static final String DEFAULT_AGGREGATION_FUNCTION = "mean()";
+    private static final String DEFAULT_INTERVAL = "1m";
+    private static final String BASE_URL = "https://cloud.oracle.com/monitoring/explore";
+    private static final String DEFAULT_ADVANCED_MODE = "false";
+    private static final String DEFAULT_AGGREGATE_METRICS = "false";
+    private static final String UTF_8 = "UTF-8";
+    
+    private String namespace;
+    private String region;
+    
+    public MetricsItem() {
+        super();
+    }
+
+    public MetricsItem(String compartmentId, String name, String namespace, String region) {
+        super(OCID.of("MetricsNamespace/Metrics"), compartmentId, name);
+        this.namespace = namespace;
+        this.region = region;
+    }
+    
+    public String getNamespace() {
+        return namespace;
+    }
+
+    @Override
+    public URL getURL() {        
+        try {
+            String url = addQueryTo(BASE_URL);
+            return URI.create(url).toURL();
+        } catch (MalformedURLException | UnsupportedEncodingException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+        return null;
+    }
+    
+    public String addQueryTo(String baseUrl) throws UnsupportedEncodingException {
+        Map<String, String> params = getQueryParams();
+        StringBuilder sb = new StringBuilder(baseUrl);
+        sb.append("?");
+        for (Map.Entry<String, String> entry : params.entrySet()) {
+            sb.append(URLEncoder.encode(entry.getKey(), UTF_8))
+              .append("=")
+              .append(URLEncoder.encode(entry.getValue(), UTF_8))
+              .append("&");
+        }
+
+        if (sb.length() > 0) {
+            sb.setLength(sb.length() - 1);
+        }
+
+        return sb.toString();
+    }
+
+    private Map<String, String> getQueryParams() {
+        return new HashMap<>() {{
+            put("panelConfigs[0][advanced]", DEFAULT_ADVANCED_MODE);
+            put("panelConfigs[0][content][aggregate]", DEFAULT_AGGREGATE_METRICS);
+            put("panelConfigs[0][content][compartmentId]", getCompartmentId());
+            put("panelConfigs[0][content][metricName]", getName());
+            put("panelConfigs[0][content][namespace]", getNamespace());
+            put("panelConfigs[0][content][interval]", DEFAULT_INTERVAL);
+            put("panelConfigs[0][content][statistic]", DEFAULT_AGGREGATION_FUNCTION);
+            put("region", region);
+        }};
+    }
+}
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/MetricsNamespaceItem.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/MetricsNamespaceItem.java
new file mode 100644
index 0000000..dfd0c43
--- /dev/null
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/MetricsNamespaceItem.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cloud.oracle.developer;
+
+import org.netbeans.modules.cloud.oracle.items.OCID;
+import org.netbeans.modules.cloud.oracle.items.OCIItem;
+
+/**
+ *
+ * @author Dusan Petrovic
+ */
+public class MetricsNamespaceItem extends OCIItem {
+
+    public MetricsNamespaceItem() {
+        super();
+    }
+    
+    public MetricsNamespaceItem(String compartmentId, String name) {
+        super(OCID.of("MetricsNamespace"), compartmentId, name);
+    }
+    
+}
\ No newline at end of file
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/MetricsNamespaceNode.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/MetricsNamespaceNode.java
new file mode 100644
index 0000000..cb0701c
--- /dev/null
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/MetricsNamespaceNode.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cloud.oracle.developer;
+
+import com.oracle.bmc.monitoring.MonitoringClient;
+import com.oracle.bmc.monitoring.model.ListMetricsDetails;
+import com.oracle.bmc.monitoring.requests.ListMetricsRequest;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.netbeans.modules.cloud.oracle.ChildrenProvider;
+import org.netbeans.modules.cloud.oracle.NodeProvider;
+import org.netbeans.modules.cloud.oracle.OCINode;
+import org.netbeans.modules.cloud.oracle.compartment.CompartmentItem;
+import org.openide.util.NbBundle;
+
+/**
+ *
+ * @author Dusan Petrovic
+ */
+@NbBundle.Messages({
+    "MetricsNamespaceDesc=Metrics namespace"
+})
+public class MetricsNamespaceNode extends OCINode {
+    
+    private static final String METRICS_NAMESPACE_ICON = "org/netbeans/modules/cloud/oracle/resources/metrics_namespace.svg"; // NOI18N
+
+    public MetricsNamespaceNode(MetricsNamespaceItem instance) {
+        super(instance);
+        setName(instance.getName());
+        setDisplayName(instance.getName());
+        setIconBaseWithExtension(METRICS_NAMESPACE_ICON);
+        setShortDescription(Bundle.MetricsNamespaceDesc());
+    }
+    
+    public static NodeProvider<MetricsNamespaceItem> createNode() {
+        return MetricsNamespaceNode::new;
+    }
+
+    /**
+     * Retrieves list of Metrics namespaces belonging to a given Compartment.
+     *
+     * @return Returns {@code ChildrenProvider} which fetches List of
+     * {@code BucketItem} for given {@code CompartmentItem}
+     */
+    public static ChildrenProvider.SessionAware<CompartmentItem, MetricsNamespaceItem> getMetricNamespaces() {
+        return (compartmentId, session) -> {
+            MonitoringClient client = session.newClient(MonitoringClient.class);
+            ListMetricsDetails listMetricsDetails = ListMetricsDetails.builder()
+                    .groupBy(List.of("namespace"))
+                    .build();
+            
+            ListMetricsRequest request = ListMetricsRequest.builder()
+                    .compartmentId(compartmentId.getKey().getValue())
+                    .listMetricsDetails(listMetricsDetails)
+                    .build();
+
+            return client.listMetrics(request)
+                    .getItems()
+                    .stream()
+                    .map(d -> new MetricsNamespaceItem(
+                            compartmentId.getKey().getValue(),
+                            d.getNamespace()
+                    ))
+                    .collect(Collectors.toList());
+        };
+    }
+}
+
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/MetricsNode.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/MetricsNode.java
new file mode 100644
index 0000000..cb4ed99
--- /dev/null
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/MetricsNode.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cloud.oracle.developer;
+
+import com.oracle.bmc.monitoring.MonitoringClient;
+import com.oracle.bmc.monitoring.model.ListMetricsDetails;
+import com.oracle.bmc.monitoring.requests.ListMetricsRequest;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.netbeans.modules.cloud.oracle.ChildrenProvider;
+import org.netbeans.modules.cloud.oracle.NodeProvider;
+import org.netbeans.modules.cloud.oracle.OCINode;
+import org.openide.nodes.Children;
+import org.openide.util.NbBundle;
+
+/**
+ *
+ * @author Dusan Petrovic
+ */
+@NbBundle.Messages({
+    "MetricsDesc=Namespace: {0}"
+})
+public class MetricsNode extends OCINode {
+    
+    private static final String METRICS_ICON = "org/netbeans/modules/cloud/oracle/resources/metrics.svg"; // NOI18N
+
+    public MetricsNode(MetricsItem instance) {
+        super(instance, Children.LEAF);
+        setName(instance.getName());
+        setDisplayName(instance.getName());
+        setIconBaseWithExtension(METRICS_ICON);
+        setShortDescription(Bundle.MetricsDesc(instance.getNamespace()));
+    }
+    
+    public static NodeProvider<MetricsItem> createNode() {
+        return MetricsNode::new;
+    }
+
+    /**
+     * Retrieves list of Metrics belonging to a given Compartment.
+     *
+     * @return Returns {@code ChildrenProvider} which fetches List of
+     * {@code MetricsItem} for given {@code MetricsNamespaceItem}
+     */
+    public static ChildrenProvider.SessionAware<MetricsNamespaceItem, MetricsItem> getMetrics() {
+        return (metricsNamespace, session) -> {
+            MonitoringClient client = session.newClient(MonitoringClient.class);
+            ListMetricsDetails listMetricsDetails = ListMetricsDetails.builder()
+                    .namespace(metricsNamespace.getName())
+                    .build();
+            
+            ListMetricsRequest request = ListMetricsRequest.builder()
+                    .compartmentId(metricsNamespace.getCompartmentId())
+                    .listMetricsDetails(listMetricsDetails)
+                    .build();
+
+            Set<String> uniqueMetrics = new HashSet<>();
+
+            return client.listMetrics(request)
+                    .getItems()
+                    .stream()
+                    .filter(m -> uniqueMetrics.add(m.getName()))
+                    .map(d -> new MetricsItem(
+                            d.getCompartmentId(),
+                            d.getName(),
+                            d.getNamespace(),
+                            session.getRegion().getRegionId()
+                    ))
+                    .collect(Collectors.toList());
+        };
+    }
+}
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/items/OCID.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/items/OCID.java
index 20324fc..0f5883e 100644
--- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/items/OCID.java
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/items/OCID.java
@@ -25,6 +25,8 @@
  * @author Jan Horvath
  */
 public final class OCID  {
+    private static final String NO_OCID = "NO_OCID";
+
     private final String value;
     private final String path;
     
@@ -39,7 +41,11 @@
     
     public final String getPath() {
         return path;
-    }   
+    }
+    
+    public static final OCID of(String path) {
+        return new OCID(NO_OCID, path);
+    }
 
     public static final OCID of(String value, String path) {
         return new OCID(value, path);
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/layer.xml b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/layer.xml
index 481c9f4..77e1862 100644
--- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/layer.xml
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/layer.xml
@@ -82,6 +82,9 @@
                     <file name="org-netbeans-modules-cloud-oracle-developer-ContainerRepositoryNode-getContainerRepositories.instance">
                         <attr methodvalue="org.netbeans.modules.cloud.oracle.developer.ContainerRepositoryNode.getContainerRepositories" name="instanceCreate"/>
                     </file>
+                    <file name="org-netbeans-modules-cloud-oracle-developer-MetricsNamespaceNode-getMetrics.instance">
+                        <attr methodvalue="org.netbeans.modules.cloud.oracle.developer.MetricsNamespaceNode.getMetricNamespaces" name="instanceCreate"/>
+                    </file>
                     <file name="org-netbeans-modules-cloud-oracle-compute-ClusterNode-getClusters.instance">
                         <attr methodvalue="org.netbeans.modules.cloud.oracle.compute.ClusterNode.getClusters" name="instanceCreate"/>
                     </file>
@@ -215,6 +218,23 @@
                     </file>
                 </folder>
             </folder>
+            <folder name="MetricsNamespace">
+                <folder name="Nodes">
+                    <file name="org-netbeans-modules-cloud-oracle-developer-MetricsNamespaceNode-createNode.instance">
+                        <attr methodvalue="org.netbeans.modules.cloud.oracle.developer.MetricsNamespaceNode.createNode" name="instanceCreate"/>
+                    </file>
+                    <file name="org-netbeans-modules-cloud-oracle-developer-MetricsNode-getMetrics.instance">
+                        <attr methodvalue="org.netbeans.modules.cloud.oracle.developer.MetricsNode.getMetrics" name="instanceCreate"/>
+                    </file>
+                </folder>
+                <folder name="Metrics">
+                    <folder name="Nodes">
+                        <file name="org-netbeans-modules-cloud-oracle-developer-MetricsNode-createNode.instance">
+                            <attr methodvalue="org.netbeans.modules.cloud.oracle.developer.MetricsNode.createNode" name="instanceCreate"/>
+                        </file>
+                    </folder>
+                </folder>
+            </folder>
             <folder name="ContainerTag">
                 <folder name="Nodes">
                     <file name="org-netbeans-modules-cloud-oracle-cdeveloper-ContainerTagNode-createNode.instance">
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/metrics.svg b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/metrics.svg
new file mode 100644
index 0000000..d570c0b
--- /dev/null
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/metrics.svg
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+
+<svg
+   version="1.1"
+   id="Vector_Icons"
+   x="0px"
+   y="0px"
+   width="16px"
+   height="16px"
+   viewBox="0 0 16 16"
+   style="enable-background:new 0 0 16 16;"
+   xml:space="preserve"
+   sodipodi:docname="metrics.svg"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs17027" /><sodipodi:namedview
+   id="namedview17025"
+   pagecolor="#ffffff"
+   bordercolor="#666666"
+   borderopacity="1.0"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   showgrid="false"
+   inkscape:zoom="29.651788"
+   inkscape:cx="7.8241487"
+   inkscape:cy="5.0924416"
+   inkscape:window-width="1576"
+   inkscape:window-height="1049"
+   inkscape:window-x="202"
+   inkscape:window-y="49"
+   inkscape:window-maximized="0"
+   inkscape:current-layer="Vector_Icons"
+   inkscape:showpageshadow="2"
+   inkscape:deskcolor="#d1d1d1" />
+<style
+   type="text/css"
+   id="style17020">
+	.st0{fill:#FFFFFF;}
+	.st1{opacity:0.25;}
+	.st2{fill:#FAFAFA;}
+	.st3{opacity:0.33;}
+	.st4{fill:none;stroke:#474747;stroke-miterlimit:10;}
+	.st5{opacity:0.42;}
+	.st6{fill:#CAE3FF;}
+	.st7{opacity:0.2;}
+	.st8{opacity:0.03;}
+	.st9{opacity:0.1;}
+	.st10{opacity:0.15;}
+	.st11{opacity:0.45;}
+	.st12{fill:#FFE1B0;}
+	.st13{fill:#B3DBFF;}
+	.st14{fill:#FBDC7C;}
+	.st15{fill:#FFDB43;}
+	.st16{fill:#E79B00;}
+	.st17{fill:#3883CE;}
+	.st18{fill:none;stroke:#003399;stroke-width:1.375;stroke-miterlimit:10;}
+	.st19{fill:#E8513D;}
+	.st20{fill:#1E1E1E;}
+	.st21{fill:#FFC36D;}
+	.st22{fill:#9FCBFF;}
+	.st23{fill:#E9F7FF;}
+	.st24{fill:#62707C;}
+	.st25{fill:#7A8896;}
+	.st26{fill:#57BFFF;}
+	.st27{fill:#E69D35;}
+	.st28{fill:#9CFF73;}
+	.st29{fill:#4891CC;}
+	.st30{fill:#474747;}
+	.st31{fill:#CCA05E;}
+	.st32{opacity:0.67;}
+	.st33{opacity:0.3;}
+	.st34{fill:#EAEAEA;}
+	.st35{fill:#FFE945;}
+	.st36{fill:#FFCF8C;}
+	.st37{fill:#FF5252;}
+	.st38{opacity:0.12;}
+	.st39{fill:#45A5F4;}
+	.st40{fill:url(#SVGID_1_);}
+	.st41{fill:url(#SVGID_2_);}
+	.st42{opacity:0.05;}
+	.st43{fill:#3D81F5;}
+	.st44{fill:#CECECE;}
+	.st45{fill:#B5B5B5;}
+	.st46{opacity:0.4;}
+	.st47{fill:#595959;}
+	.st48{fill:#80FF80;}
+	.st49{fill:#C8FF80;}
+	.st50{fill:#FFEE80;}
+	.st51{fill:#FFA680;}
+	.st52{fill:#FF8080;}
+	.st53{fill:none;}
+	.st54{fill:#007AFF;}
+	.st55{fill:#EFFF78;}
+	.st56{fill:#FFDA00;}
+	.st57{fill:#3EADFF;}
+	.st58{opacity:0.67;fill:#FFFFFF;}
+	.st59{fill:#2E92FF;}
+	.st60{fill:#3AEA00;}
+	.st61{fill:#303030;}
+</style>
+
+<path
+   style="font-size:16.4841px;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue';fill:#9d9d9d;stroke-width:0;paint-order:stroke fill markers"
+   d="m 6.7331828,12.527608 v 1.829735 H 8.5629179 V 12.527608 Z M 4.0462744,6.2636495 H 5.447423 q 0,-0.5769436 0.1318728,-1.0714666 Q 5.7111686,4.6976599 5.9913983,4.3350097 6.2881121,3.9723595 6.7166987,3.7580662 7.1452853,3.5437729 7.7387129,3.5437729 q 0.8901414,0 1.4011485,0.5110071 Q 9.6673526,4.5657871 9.7332891,5.4724126 9.7662573,6.0823243 9.5849321,6.510911 9.403607,6.9394976 9.0904091,7.3021478 8.7936953,7.6483139 8.4310451,7.9779959 8.084879,8.2911938 7.755197,8.6703281 7.4419991,9.0494624 7.2112217,9.5439854 6.9969284,10.022024 6.9639602,10.714357 v 0.774752 h 1.4011485 v -0.64288 q 0,-0.428586 0.1153887,-0.758268 Q 8.6123702,9.7417946 8.8101794,9.4615649 9.0244727,9.1648511 9.2717342,8.9175896 9.5354798,8.653844 9.7992255,8.4065825 10.062971,8.1428369 10.310233,7.8626072 q 0.263745,-0.2802297 0.461554,-0.6099117 0.19781,-0.329682 0.313198,-0.7253004 0.131873,-0.4121026 0.131873,-0.9231097 0,-0.7912368 -0.263746,-1.4011485 Q 10.705851,3.5932252 10.244296,3.1811227 9.7827414,2.7525361 9.1398614,2.5382428 8.5134656,2.3074654 7.7387129,2.3074654 q -0.8571732,0 -1.5495054,0.2967138 Q 5.4968753,2.900893 5.0188364,3.4448683 4.5407974,3.9723595 4.2770518,4.6976599 4.0297903,5.4229603 4.0462744,6.2636495 Z"
+   id="text1"
+   transform="scale(1.0383436,0.96307233)"
+   aria-label="?" /></svg>
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/metrics_namespace.svg b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/metrics_namespace.svg
new file mode 100644
index 0000000..e5332be
--- /dev/null
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/metrics_namespace.svg
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+
+<svg
+   version="1.1"
+   id="Vector_Icons"
+   x="0px"
+   y="0px"
+   width="16px"
+   height="16px"
+   viewBox="0 0 16 16"
+   style="enable-background:new 0 0 16 16;"
+   xml:space="preserve"
+   sodipodi:docname="metrics_namespace.svg"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs17027" /><sodipodi:namedview
+   id="namedview17025"
+   pagecolor="#ffffff"
+   bordercolor="#666666"
+   borderopacity="1.0"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   showgrid="false"
+   inkscape:zoom="29.651788"
+   inkscape:cx="7.8241487"
+   inkscape:cy="5.0924416"
+   inkscape:window-width="1576"
+   inkscape:window-height="1049"
+   inkscape:window-x="202"
+   inkscape:window-y="49"
+   inkscape:window-maximized="0"
+   inkscape:current-layer="Vector_Icons"
+   inkscape:showpageshadow="2"
+   inkscape:deskcolor="#d1d1d1" />
+<style
+   type="text/css"
+   id="style17020">
+	.st0{fill:#FFFFFF;}
+	.st1{opacity:0.25;}
+	.st2{fill:#FAFAFA;}
+	.st3{opacity:0.33;}
+	.st4{fill:none;stroke:#474747;stroke-miterlimit:10;}
+	.st5{opacity:0.42;}
+	.st6{fill:#CAE3FF;}
+	.st7{opacity:0.2;}
+	.st8{opacity:0.03;}
+	.st9{opacity:0.1;}
+	.st10{opacity:0.15;}
+	.st11{opacity:0.45;}
+	.st12{fill:#FFE1B0;}
+	.st13{fill:#B3DBFF;}
+	.st14{fill:#FBDC7C;}
+	.st15{fill:#FFDB43;}
+	.st16{fill:#E79B00;}
+	.st17{fill:#3883CE;}
+	.st18{fill:none;stroke:#003399;stroke-width:1.375;stroke-miterlimit:10;}
+	.st19{fill:#E8513D;}
+	.st20{fill:#1E1E1E;}
+	.st21{fill:#FFC36D;}
+	.st22{fill:#9FCBFF;}
+	.st23{fill:#E9F7FF;}
+	.st24{fill:#62707C;}
+	.st25{fill:#7A8896;}
+	.st26{fill:#57BFFF;}
+	.st27{fill:#E69D35;}
+	.st28{fill:#9CFF73;}
+	.st29{fill:#4891CC;}
+	.st30{fill:#474747;}
+	.st31{fill:#CCA05E;}
+	.st32{opacity:0.67;}
+	.st33{opacity:0.3;}
+	.st34{fill:#EAEAEA;}
+	.st35{fill:#FFE945;}
+	.st36{fill:#FFCF8C;}
+	.st37{fill:#FF5252;}
+	.st38{opacity:0.12;}
+	.st39{fill:#45A5F4;}
+	.st40{fill:url(#SVGID_1_);}
+	.st41{fill:url(#SVGID_2_);}
+	.st42{opacity:0.05;}
+	.st43{fill:#3D81F5;}
+	.st44{fill:#CECECE;}
+	.st45{fill:#B5B5B5;}
+	.st46{opacity:0.4;}
+	.st47{fill:#595959;}
+	.st48{fill:#80FF80;}
+	.st49{fill:#C8FF80;}
+	.st50{fill:#FFEE80;}
+	.st51{fill:#FFA680;}
+	.st52{fill:#FF8080;}
+	.st53{fill:none;}
+	.st54{fill:#007AFF;}
+	.st55{fill:#EFFF78;}
+	.st56{fill:#FFDA00;}
+	.st57{fill:#3EADFF;}
+	.st58{opacity:0.67;fill:#FFFFFF;}
+	.st59{fill:#2E92FF;}
+	.st60{fill:#3AEA00;}
+	.st61{fill:#303030;}
+</style>
+
+<path
+   style="font-size:16.4841px;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue';fill:#9d9d9d;stroke-width:0;paint-order:stroke fill markers"
+   d="m 6.7331828,12.527608 v 1.829735 H 8.5629179 V 12.527608 Z M 4.0462744,6.2636495 H 5.447423 q 0,-0.5769436 0.1318728,-1.0714666 Q 5.7111686,4.6976599 5.9913983,4.3350097 6.2881121,3.9723595 6.7166987,3.7580662 7.1452853,3.5437729 7.7387129,3.5437729 q 0.8901414,0 1.4011485,0.5110071 Q 9.6673526,4.5657871 9.7332891,5.4724126 9.7662573,6.0823243 9.5849321,6.510911 9.403607,6.9394976 9.0904091,7.3021478 8.7936953,7.6483139 8.4310451,7.9779959 8.084879,8.2911938 7.755197,8.6703281 7.4419991,9.0494624 7.2112217,9.5439854 6.9969284,10.022024 6.9639602,10.714357 v 0.774752 h 1.4011485 v -0.64288 q 0,-0.428586 0.1153887,-0.758268 Q 8.6123702,9.7417946 8.8101794,9.4615649 9.0244727,9.1648511 9.2717342,8.9175896 9.5354798,8.653844 9.7992255,8.4065825 10.062971,8.1428369 10.310233,7.8626072 q 0.263745,-0.2802297 0.461554,-0.6099117 0.19781,-0.329682 0.313198,-0.7253004 0.131873,-0.4121026 0.131873,-0.9231097 0,-0.7912368 -0.263746,-1.4011485 Q 10.705851,3.5932252 10.244296,3.1811227 9.7827414,2.7525361 9.1398614,2.5382428 8.5134656,2.3074654 7.7387129,2.3074654 q -0.8571732,0 -1.5495054,0.2967138 Q 5.4968753,2.900893 5.0188364,3.4448683 4.5407974,3.9723595 4.2770518,4.6976599 4.0297903,5.4229603 4.0462744,6.2636495 Z"
+   id="text1"
+   transform="scale(1.0383436,0.96307233)"
+   aria-label="?" /></svg>
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/steps/DatabaseConnectionStep.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/steps/DatabaseConnectionStep.java
index c7c0226..acc3733 100644
--- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/steps/DatabaseConnectionStep.java
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/steps/DatabaseConnectionStep.java
@@ -39,7 +39,8 @@
  */
 @NbBundle.Messages({
     "SelectDBConnection=Select Database Connection",
-    "AddNewConnection=<Add a new Connection>"
+    "AddNewConnection=<Add a new Connection>",
+    "OADB=Oracle Autonomous Database"
 })
 public final class DatabaseConnectionStep extends AbstractStep<DatabaseItem> {
 
@@ -68,7 +69,7 @@
         List<QuickPick.Item> items = new LinkedList<>();
         items.add(new QuickPick.Item(Bundle.AddNewConnection(), Bundle.AddNewConnection()));
         for (Entry<String, DatabaseItem> adbConnection : adbConnections.entrySet()) {
-            items.add(new QuickPick.Item(adbConnection.getKey(), "Connection " + adbConnection.getValue()));
+            items.add(new QuickPick.Item(adbConnection.getKey(), Bundle.OADB()));
         }
         return new NotifyDescriptor.QuickPick(Bundle.SelectDBConnection(), Bundle.SelectDBConnection(), items, false);
     }
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/steps/ItemTypeStep.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/steps/ItemTypeStep.java
index 2e4235a..f6ba58e 100644
--- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/steps/ItemTypeStep.java
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/steps/ItemTypeStep.java
@@ -44,6 +44,7 @@
             put(Bundle.Bucket(), "Bucket"); //NOI18N 
             put(Bundle.Vault(), "Vault"); //NOI18N
             put(Bundle.ContainerRepository(), "ContainerRepository"); //NOI18N
+            put(Bundle.MetricsNamespace(), "MetricsNamespace"); //NOI18N
         }
     };
     private String selected;
diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/steps/SuggestedStep.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/steps/SuggestedStep.java
index 082b082..8814a2c 100644
--- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/steps/SuggestedStep.java
+++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/steps/SuggestedStep.java
@@ -38,6 +38,7 @@
 import org.netbeans.modules.cloud.oracle.compute.ComputeInstanceNode;
 import org.netbeans.modules.cloud.oracle.database.DatabaseNode;
 import org.netbeans.modules.cloud.oracle.developer.ContainerRepositoryNode;
+import org.netbeans.modules.cloud.oracle.developer.MetricsNamespaceNode;
 import org.netbeans.modules.cloud.oracle.items.OCIItem;
 import org.netbeans.modules.cloud.oracle.vault.VaultNode;
 import org.openide.NotifyDescriptor;
@@ -56,6 +57,7 @@
     "Compute=Compute Instance",
     "SelectItem=Select {0}",
     "ContainerRepository=Container Repository",
+    "MetricsNamespace=Metrics Namespace",
 })
 public class SuggestedStep extends AbstractStep<OCIItem> {
     private static final Logger LOG = Logger.getLogger(SuggestedStep.class.getName());
@@ -92,6 +94,8 @@
                 return Bundle.Compute();
             case "ContainerRepository":
                 return Bundle.ContainerRepository();
+            case "MetricsNamespace":
+                return Bundle.MetricsNamespace();
         }
         throw new MissingResourceException("Missing OCI type", null, suggestedType);
     }
@@ -143,6 +147,8 @@
                     items.add(new CreateNewResourceItem());
                     items.addAll(ContainerRepositoryNode.getContainerRepositories().apply(parent));
                     return items;
+                case "MetricsNamespace": //NOI18N
+                    return MetricsNamespaceNode.getMetricNamespaces().apply(parent);
                 default:
                     return Collections.emptyList();
             }
diff --git a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/cloud-cookies.contextValues b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/cloud-cookies.contextValues
index e226eff..ec8d31f 100644
--- a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/cloud-cookies.contextValues
+++ b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/cloud-cookies.contextValues
@@ -27,4 +27,6 @@
 org.netbeans.modules.cloud.oracle.bucket.BucketItem
 org.netbeans.modules.cloud.oracle.vault.VaultItem
 org.netbeans.modules.cloud.oracle.developer.ContainerRepositoryItem
-org.netbeans.modules.cloud.oracle.developer.ContainerTagItem
\ No newline at end of file
+org.netbeans.modules.cloud.oracle.developer.ContainerTagItem
+org.netbeans.modules.cloud.oracle.developer.MetricsNamespaceItem
+org.netbeans.modules.cloud.oracle.developer.MetricsItem
diff --git a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml
index 8141315..9538480 100644
--- a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml
+++ b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml
@@ -62,6 +62,7 @@
                 <attr name="action:org.netbeans.modules.cloud.oracle.actions.AddSuggestedItemAction" stringvalue="Tools"/>
                 <attr name="action:org.netbeans.modules.cloud.oracle.actions.RemoveFromProject" stringvalue="Tools"/>
                 <attr name="action:org.netbeans.modules.cloud.oracle.actions.SetReferenceName" stringvalue="Tools"/>
+                <attr name="action:org.netbeans.modules.cloud.oracle.adm.ShowInBrowserAction" stringvalue="Tools"/>
             </file>
         </folder>
         <folder name="AutoupdateType">
diff --git a/java/java.lsp.server/vscode/package.json b/java/java.lsp.server/vscode/package.json
index 067096c..9a2af26 100644
--- a/java/java.lsp.server/vscode/package.json
+++ b/java/java.lsp.server/vscode/package.json
@@ -570,6 +570,11 @@
 				"icon": "$(add)"
 			},
 			{
+				"command": "nbls:Tools:org.netbeans.modules.cloud.oracle.adm.ShowInBrowserAction",
+				"title": "Open In Browser",
+				"icon": "$(link-external)"
+			},
+			{
 				"command": "nbls.db.add.connection",
 				"title": "Add JDBC Database Connection"
 			},
@@ -865,6 +870,10 @@
 					"when": "false"
 				},
 				{
+					"command": "nbls:Tools:org.netbeans.modules.cloud.oracle.adm.ShowInBrowserAction",
+					"when": "false"
+				},
+				{
 					"command": "nbls:Tools:org.netbeans.modules.cloud.oracle.actions.AddRepository",
 					"when": "false"
 				},
@@ -1078,6 +1087,11 @@
 					"group": "oci@1000"
 				},
 				{
+					"command": "nbls:Tools:org.netbeans.modules.cloud.oracle.adm.ShowInBrowserAction",
+					"when": "viewItem =~ /class:oracle.developer.MetricsItem/",
+					"group": "inline@10"
+				},
+				{
 					"command": "nbls.cloud.computeInstance.ssh",
 					"when": "viewItem =~ /publicIp:.*/ && viewItem =~ /^(?!.*imageUrl:).*/",
 					"group": "inline@10"
@@ -1104,7 +1118,7 @@
 				},
 				{
 					"command": "nbls:Tools:org.netbeans.modules.cloud.oracle.actions.AddToProject",
-					"when": "viewItem =~ /(ComputeInstanceItem|ClusterItem|BucketItem|DatabaseItem|VaultItem|ContainerRepositoryItem)/ && view != cloud.assets",
+					"when": "viewItem =~ /(ComputeInstanceItem|ClusterItem|BucketItem|DatabaseItem|VaultItem|ContainerRepositoryItem|MetricsNamespaceItem)/ && view != cloud.assets",
 					"group": "inline@14"
 				},
 				{
@@ -1223,6 +1237,14 @@
 				"codeicon": "archive"
 			},
 			{
+                "uriExpression": "nbres:/org/netbeans/modules/cloud/oracle/resources/metrics.svg",
+                "codeicon": "graph-line"
+            },
+            {
+                "uriExpression": "nbres:/org/netbeans/modules/cloud/oracle/resources/metrics_namespace.svg",
+                "codeicon": "symbol-namespace"
+            },
+			{
 				"uriExpression": "nbres:/org/netbeans/modules/cloud/oracle/resources/computeinstance.svg",
 				"codeicon": "server-environment"
 			},
diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts
index e094374..f907a2d 100644
--- a/java/java.lsp.server/vscode/src/extension.ts
+++ b/java/java.lsp.server/vscode/src/extension.ts
@@ -972,8 +972,35 @@
     terminal.show();
 }
 
-function runDockerSSH(username: string, host: string, dockerImage: string) {
-   const sshCommand = `ssh ${username}@${host} "docker pull ${dockerImage} && docker run -p 8080:8080 -it ${dockerImage}"`;
+interface ConfigFiles {
+    applicationProperties : string | null;
+    bootstrapProperties: string | null;
+}
+
+async function runDockerSSH(username: string, host: string, dockerImage: string) {
+    const configFiles: ConfigFiles = await vscode.commands.executeCommand('nbls.config.file.path') as ConfigFiles;
+    const { applicationProperties, bootstrapProperties } = configFiles;
+
+    const applicationPropertiesRemotePath = `/home/${username}/application.properties`;
+    const bootstrapPropertiesRemotePath = `/home/${username}/bootstrap.properties`;
+    const applicationPropertiesContainerPath = "/home/app/application.properties";
+    const bootstrapPropertiesContainerPath = "/home/app/bootstrap.properties";
+
+    let sshCommand = "";
+    let mountVolume = "";
+    let micronautConfigFilesEnv = "";
+    if (bootstrapProperties) {
+        sshCommand = `scp "${bootstrapProperties}" ${username}@${host}:${bootstrapPropertiesRemotePath} && `;
+        mountVolume = `-v ${bootstrapPropertiesRemotePath}:${bootstrapPropertiesContainerPath}:Z `;
+        micronautConfigFilesEnv = `${bootstrapPropertiesContainerPath}`;
+    }
+
+    if (applicationProperties) {
+        sshCommand += `scp "${applicationProperties}" ${username}@${host}:${applicationPropertiesRemotePath} && `;
+        mountVolume += ` -v ${applicationPropertiesRemotePath}:${applicationPropertiesContainerPath}:Z`;
+        micronautConfigFilesEnv += `${bootstrapProperties ? "," : ""}${applicationPropertiesContainerPath}`;
+    } 
+    sshCommand += `ssh ${username}@${host} "docker pull ${dockerImage} && docker run -p 8080:8080 ${mountVolume} -e MICRONAUT_CONFIG_FILES=${micronautConfigFilesEnv} -it ${dockerImage}"`;
 
     const terminal = vscode.window.createTerminal('Remote Docker');
     terminal.sendText(sshCommand);
diff --git a/java/java.lsp.server/vscode/webviews/run-image-guide.handlebars b/java/java.lsp.server/vscode/webviews/run-image-guide.handlebars
index 1144aa5..54fa100 100644
--- a/java/java.lsp.server/vscode/webviews/run-image-guide.handlebars
+++ b/java/java.lsp.server/vscode/webviews/run-image-guide.handlebars
@@ -128,9 +128,20 @@
                             <li>Verify Docker installation with: <span class="propertyValue">docker --version</span></li>
                             {{#if isRepositoryPrivate}}
                             <li>Authenticate Docker client with a Docker registry: <span class="propertyValue">docker login {{ registryUrl }}</span></li>
+                            <li>When prompted for <b>Username</b> enter the name of the user you will be using in the format: <span class="propertyValue">&lt;tenancy-namespace&gt;/&lt;username&gt;</span></li>
+                            <li>When prompted for <b>Password</b> enter the user's Oracle Cloud Infrastructure auth token</li>
                             {{/if}}
                         </ul>
                     </div>
+
+                    <div class="subtitle">
+                        <p>References:
+                            <a href="https://docs.oracle.com/en-us/iaas/Content/Compute/Tasks/accessinginstance.htm" title="Connecting to an Compute Instance">Connecting to an Compute Instance</a>,
+                            <a href="https://docs.oracle.com/en-us/iaas/Content/Network/Concepts/securitylists.htm" title="Security lists">Security lists</a>,
+                            <a href="https://docs.oracle.com/en-us/iaas/Content/Functions/Tasks/functionslogintoocir.htm" title="Logging in to Oracle Cloud Infrastructure Registry">Logging in to Oracle Cloud Infrastructure Registry</a>
+                        </p>
+                    </div>
+
                 </div>
                 <div class="footer">
                     <p class="guideControl">
diff --git a/java/java.lsp.server/vscode/webviews/ssh-guide.handlebars b/java/java.lsp.server/vscode/webviews/ssh-guide.handlebars
index a11f92c..9b2c25d 100644
--- a/java/java.lsp.server/vscode/webviews/ssh-guide.handlebars
+++ b/java/java.lsp.server/vscode/webviews/ssh-guide.handlebars
@@ -71,6 +71,12 @@
                         <pre>chmod 400 {{dummyKeyPathLocation}}</pre>
                     </div>
                     <p>This command sets the permissions so that only the owner of the file can read it.</p>
+
+                    <div class="subtitle">
+                        <p>References:
+                            <a href="https://docs.oracle.com/en-us/iaas/Content/Compute/Tasks/accessinginstance.htm" title="Connecting to an Compute Instance">Connecting to an Compute Instance</a>
+                        </p>
+                    </div>
                 </div>
                 <div class="footer">
                     <p class="guideControl">