You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2021/12/11 16:30:08 UTC

[karaf] branch karaf-4.3.x updated: KARAF-7289 - Provide config property name completion using MetaType info

This is an automated email from the ASF dual-hosted git repository.

jbonofre pushed a commit to branch karaf-4.3.x
in repository https://gitbox.apache.org/repos/asf/karaf.git


The following commit(s) were added to refs/heads/karaf-4.3.x by this push:
     new 92ee273  KARAF-7289 - Provide config property name completion using MetaType info
92ee273 is described below

commit 92ee273dca9e5bde239ecfd2f6f4616823d78228
Author: jassuncao <jo...@exploitsys.com>
AuthorDate: Wed Dec 8 19:40:09 2021 +0000

    KARAF-7289 - Provide config property name completion using MetaType info
    
    ConfigurationPropertyCompleter now uses the MetaType service to retrieve
    configuration property names in addition to the ones already defined in
    the configuration.
    
    Adds an utility method in MetaServiceCaller to find MetaType info for a
    specified PID. This method accepts a function to do something with the
    result. MetaCommand is refactored to use this function.
    
    Change-Id: Ieab22ed2daaefa55675fbb2eb41e77ac534b5251
    
    (cherry picked from commit 939ce7ae9f2dcd6b60ab3d42e5d58e8498b9f53e)
---
 .../apache/karaf/config/command/MetaCommand.java   | 72 +++++-----------------
 .../completers/ConfigurationPropertyCompleter.java | 62 +++++++++++++++++--
 .../karaf/config/core/impl/MetaServiceCaller.java  | 66 ++++++++++++++++++++
 3 files changed, 139 insertions(+), 61 deletions(-)

diff --git a/config/src/main/java/org/apache/karaf/config/command/MetaCommand.java b/config/src/main/java/org/apache/karaf/config/command/MetaCommand.java
index 3687bb7..165aea3 100644
--- a/config/src/main/java/org/apache/karaf/config/command/MetaCommand.java
+++ b/config/src/main/java/org/apache/karaf/config/command/MetaCommand.java
@@ -16,16 +16,18 @@
  */
 package org.apache.karaf.config.command;
 
-import static org.apache.karaf.config.core.impl.MetaServiceCaller.withMetaTypeService;
+import static org.apache.karaf.config.core.impl.MetaServiceCaller.doWithMetaType;
 
 import java.io.IOException;
 import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
+import java.util.Optional;
 import java.util.function.Function;
 
 import org.apache.karaf.config.command.completers.MetaCompleter;
+import org.apache.karaf.config.core.impl.MetaServiceCaller.MetaInfo;
 import org.apache.karaf.shell.api.action.Argument;
 import org.apache.karaf.shell.api.action.Command;
 import org.apache.karaf.shell.api.action.Completion;
@@ -34,13 +36,10 @@ import org.apache.karaf.shell.api.action.lifecycle.Reference;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 import org.apache.karaf.shell.support.CommandException;
 import org.apache.karaf.shell.support.table.ShellTable;
-import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.metatype.AttributeDefinition;
-import org.osgi.service.metatype.MetaTypeInformation;
-import org.osgi.service.metatype.MetaTypeService;
 import org.osgi.service.metatype.ObjectClassDefinition;
 
 @Command(scope = "config", name = "meta", description = "Lists meta type information.")
@@ -77,9 +76,9 @@ public class MetaCommand extends ConfigCommandSupport {
     public Object doExecute() throws Exception {
         try {
             if (create) {
-                withMetaTypeService(context, new Create());
+                doWithMetaType(context, pid, new Create());
             } else {
-                withMetaTypeService(context, new Print());
+                doWithMetaType(context, pid, new Print());
             }
             return null;
         } catch (Throwable e) {
@@ -95,7 +94,7 @@ public class MetaCommand extends ConfigCommandSupport {
         }
     }
         
-    abstract class AbstractMeta implements Function<MetaTypeService, Void> {
+    abstract class AbstractMeta implements Function<Optional<MetaInfo>, Void> {
         protected String getDefaultValueStr(String[] defaultValues) {
             if (defaultValues == null) {
                 return "";
@@ -112,43 +111,19 @@ public class MetaCommand extends ConfigCommandSupport {
             }
             return result.toString();
         }
-
-        protected MetaInfo getMetatype(MetaTypeService metaTypeService, String pid) {
-            if (metaTypeService != null) {
-                for (Bundle bundle : context.getBundles()) {
-                    MetaTypeInformation info = metaTypeService.getMetaTypeInformation(bundle);
-                    if (info == null) {
-                        continue;
-                    }
-                    String[] pids = info.getPids();
-                    for (String cPid : pids) {
-                        if (cPid.equals(pid)) {
-                            return new MetaInfo(info.getObjectClassDefinition(cPid, null), false);
-                        }
-                    }
-                    pids = info.getFactoryPids();
-                    for (String cPid : pids) {
-                        if (cPid.equals(pid)) {
-                            return new MetaInfo(info.getObjectClassDefinition(cPid, null), true);
-                        }
-                    }
-                }
-            }
-            return null;
-        }
+      
     }
     
     class Create extends AbstractMeta {
 
-        public Void apply(MetaTypeService metaTypeService) {
-            MetaInfo info = getMetatype(metaTypeService, pid);
-            if (info == null) {                
+        public Void apply(Optional<MetaInfo> info) {
+            if (!info.isPresent()) {                
                 System.out.println("No meta type definition found for pid: " + pid);
                 return null;
             }
             
             try {
-                createDefaultConfig(pid, info);
+                createDefaultConfig(pid, info.get());
             } catch (IOException e) {
                  throw new RuntimeException(e.getMessage(), e);
             }
@@ -156,13 +131,13 @@ public class MetaCommand extends ConfigCommandSupport {
         }
         
         private void createDefaultConfig(String pid, MetaInfo info) throws IOException {
-            AttributeDefinition[] attrs = info.definition.getAttributeDefinitions(ObjectClassDefinition.ALL);
+            AttributeDefinition[] attrs = info.getDefinition().getAttributeDefinitions(ObjectClassDefinition.ALL);
             if (attrs == null) {
                 return;
             }
             ConfigurationAdmin configAdmin = configRepository.getConfigAdmin();
             Configuration config;
-            if(info.factory) {
+            if(info.isFactory()) {
                 config = configAdmin.createFactoryConfiguration(pid, null);
             }
             else {
@@ -181,13 +156,12 @@ public class MetaCommand extends ConfigCommandSupport {
     }
     
     class Print extends AbstractMeta {
-        public Void apply(MetaTypeService metaTypeService) {
-            MetaInfo info = getMetatype(metaTypeService, pid);
-            if (info == null) {
+        public Void apply(Optional<MetaInfo> info) {           
+            if (!info.isPresent()) {
                 System.out.println("No meta type definition found for pid: " + pid);
                 return null;
             }
-            if(info.factory) {
+            if(info.get().isFactory()) {
                 System.out.println("Meta type informations for factory pid: " + pid);
             }
             else {
@@ -199,7 +173,7 @@ public class MetaCommand extends ConfigCommandSupport {
             table.column("type");
             table.column("default");
             table.column("description").wrap();
-            AttributeDefinition[] attrs = info.definition.getAttributeDefinitions(ObjectClassDefinition.ALL);
+            AttributeDefinition[] attrs = info.get().getDefinition().getAttributeDefinitions(ObjectClassDefinition.ALL);
             if (attrs != null) {
                 for (AttributeDefinition attr : attrs) {
                     table.addRow().addContent(attr.getID(), attr.getName(), getType(attr.getType()),
@@ -214,17 +188,5 @@ public class MetaCommand extends ConfigCommandSupport {
             return typeMap.get(type);
         }
 
-    }
-    
-    private static class MetaInfo {
-        final ObjectClassDefinition definition;
-        final boolean factory;
-        
-        MetaInfo(ObjectClassDefinition definition, boolean factory) {
-
-            this.definition = definition;
-            this.factory = factory;
-        }
-        
-    }
+    }        
 }
diff --git a/config/src/main/java/org/apache/karaf/config/command/completers/ConfigurationPropertyCompleter.java b/config/src/main/java/org/apache/karaf/config/command/completers/ConfigurationPropertyCompleter.java
index cc0f58e..b42a0cf 100644
--- a/config/src/main/java/org/apache/karaf/config/command/completers/ConfigurationPropertyCompleter.java
+++ b/config/src/main/java/org/apache/karaf/config/command/completers/ConfigurationPropertyCompleter.java
@@ -19,24 +19,33 @@
 
 package org.apache.karaf.config.command.completers;
 
+import static org.apache.karaf.config.core.impl.MetaServiceCaller.doWithMetaType;
+
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Optional;
 import java.util.Set;
 
 import org.apache.karaf.config.command.ConfigCommandSupport;
+import org.apache.karaf.config.core.impl.MetaServiceCaller.MetaInfo;
 import org.apache.karaf.shell.api.action.lifecycle.Reference;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 import org.apache.karaf.shell.api.console.CommandLine;
 import org.apache.karaf.shell.api.console.Completer;
 import org.apache.karaf.shell.api.console.Session;
 import org.apache.karaf.shell.support.completers.StringsCompleter;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.metatype.AttributeDefinition;
+import org.osgi.service.metatype.ObjectClassDefinition;
 
 /**
  * {@link Completer} for Configuration Admin properties.
@@ -52,6 +61,9 @@ public class ConfigurationPropertyCompleter implements Completer {
 
     @Reference
     private ConfigurationAdmin configAdmin;
+    
+    @Reference
+    private BundleContext context;
 
     public int complete(final Session session, final CommandLine commandLine, final List<String> candidates) {
         StringsCompleter strings = new StringsCompleter();
@@ -98,12 +110,12 @@ public class ConfigurationPropertyCompleter implements Completer {
     @SuppressWarnings("rawtypes")
     private Set<String> getPropertyNames(String pid) {
         Set<String> propertyNames = new HashSet<>();
-        if (pid != null) {
-            Configuration configuration = null;
+        if (pid != null) {     
             try {
+                String metaPid = pid;
                 Configuration[] configs = configAdmin.listConfigurations("(service.pid="+pid+")");
                 if (configs != null && configs.length > 0) {
-                    configuration = configs[0];
+                    Configuration configuration = configs[0];
                     if (configuration != null) {
                         Dictionary properties = configuration.getProcessedProperties(null);
                         if (properties != null) {
@@ -111,15 +123,52 @@ public class ConfigurationPropertyCompleter implements Completer {
                             while (keys.hasMoreElements()) {
                                 propertyNames.add(String.valueOf(keys.nextElement()));
                             }
-                        }
+                        } 
+                        //If we have a factory config that is the PID to use
+                        if(configuration.getFactoryPid()!=null) {
+                            metaPid = configuration.getFactoryPid();
+                        }                                              
                     }
-                }
+                }   
+                //Try to fetch additional properties from the Metatype service
+                List<String> metaTypeProperties = getMetaTypeProperties(metaPid);
+                propertyNames.addAll(metaTypeProperties);
             } catch (IOException | InvalidSyntaxException e) {
                 //Ignore
-            }
+            }            
         }
         return propertyNames;
     }
+    
+    private List<String> getMetaTypeProperties(String pid){
+        try {
+            return doWithMetaType(context, pid, this::collectMetaConfigProperties);
+        } catch (Throwable e) {
+            Throwable ncdfe = e;
+            while (ncdfe != null && !(ncdfe instanceof NoClassDefFoundError)) {
+                ncdfe = ncdfe.getCause();
+            }
+            if (ncdfe != null && ncdfe.getMessage().equals("org/osgi/service/metatype/MetaTypeService")) {
+                //It seems we don't have MetaTypeService 
+            } else {
+                throw e;
+            }
+        }
+        return Collections.emptyList();
+            
+    }
+    
+    private List<String> collectMetaConfigProperties(Optional<MetaInfo> info){
+        Optional<AttributeDefinition[]> attrs = info.map(e -> e.getDefinition().getAttributeDefinitions(ObjectClassDefinition.ALL));            
+        if(attrs.isPresent()) {
+            List<String> properties = new ArrayList<>(attrs.get().length);            
+            for (AttributeDefinition attr : attrs.get()) {                
+                properties.add(attr.getID());
+            }           
+            return properties;    
+        }
+        return Collections.emptyList();
+    }
 
     public ConfigurationAdmin getConfigAdmin() {
         return configAdmin;
@@ -128,4 +177,5 @@ public class ConfigurationPropertyCompleter implements Completer {
     public void setConfigAdmin(ConfigurationAdmin configAdmin) {
         this.configAdmin = configAdmin;
     }
+       
 }
diff --git a/config/src/main/java/org/apache/karaf/config/core/impl/MetaServiceCaller.java b/config/src/main/java/org/apache/karaf/config/core/impl/MetaServiceCaller.java
index 1dccbdb..87efeeb 100644
--- a/config/src/main/java/org/apache/karaf/config/core/impl/MetaServiceCaller.java
+++ b/config/src/main/java/org/apache/karaf/config/core/impl/MetaServiceCaller.java
@@ -21,10 +21,12 @@ import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.metatype.MetaTypeInformation;
 import org.osgi.service.metatype.MetaTypeService;
+import org.osgi.service.metatype.ObjectClassDefinition;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Optional;
 import java.util.function.Function;
 
 /**
@@ -66,4 +68,68 @@ public class MetaServiceCaller {
             return pids1;
         });
     }
+    
+    /**
+     * Attempts to find MetaType information for the specified PID and 
+     * invokes the supplied callback with the result of the search   
+     */
+    public static <T> T doWithMetaType(BundleContext context, String pid, Function<Optional<MetaInfo>, T> function) {
+        ServiceReference<MetaTypeService> ref = context.getServiceReference(MetaTypeService.class);
+        if (ref != null) {
+            try {
+                MetaTypeService metaService = context.getService(ref);
+                MetaInfo metaInfo = getMetatype(context, metaService, pid);
+                return function.apply(Optional.ofNullable(metaInfo));
+            } finally {
+                context.ungetService(ref);
+            }
+        }
+        return null;
+    }
+    
+    private static MetaInfo getMetatype(BundleContext context, MetaTypeService metaTypeService, String pid) {
+        if (metaTypeService != null) {
+            for (Bundle bundle : context.getBundles()) {
+                MetaTypeInformation info = metaTypeService.getMetaTypeInformation(bundle);
+                if (info == null) {
+                    continue;
+                }
+                String[] pids = info.getPids();
+                for (String cPid : pids) {
+                    if (cPid.equals(pid)) {
+                        return new MetaInfo(info.getObjectClassDefinition(cPid, null), false);
+                    }
+                }
+                pids = info.getFactoryPids();
+                for (String cPid : pids) {
+                    if (cPid.equals(pid)) {
+                        return new MetaInfo(info.getObjectClassDefinition(cPid, null), true);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+    
+    public static class MetaInfo {
+        private final ObjectClassDefinition definition;
+        private final boolean factory;
+        
+        MetaInfo(ObjectClassDefinition definition, boolean factory) {
+
+            this.definition = definition;
+            this.factory = factory;
+        }
+        
+        public ObjectClassDefinition getDefinition() {
+
+            return definition;
+        }
+        
+        public boolean isFactory() {
+
+            return factory;
+        }
+        
+    }
 }