繁体   English   中英

如何使用Configuration Admin为同一类创建多个配置?

[英]How do I create multiple configurations for the same class with Configuration Admin?

我正在研究将利用OSGi框架的实体组件系统游戏引擎。 我希望用户/开发人员能够以模块化方式创建自己的组件类型,类似于Bethesda Creation Kit。

创建套件对象窗口

我考虑过的方法是创建一个代表组件类型的类,然后使用Configuration Admin创建配置,但是我不确定我的理解是否正确。

我有一个要用作组件类型的类

@Component(
    configurationPid = "Species",
    configurationPolicy = ConfigurationPolicy.REQUIRE,
    service = Species.class
)
public final class Species {
    // ...
}

为了测试这一点,我为Apache Gogo创建了一个创建Species的命令。 我的想法是我应该能够使用此命令创建多个物种。

@Component(
    property = {
        CommandProcessor.COMMAND_SCOPE + "=species",
        CommandProcessor.COMMAND_FUNCTION + "=create"
    },
    service = CreateSpeciesCommand.class
)
public class CreateSpeciesCommand {

    /* L1 */

    @Reference(bind = "bindConfigurationAdmin")
    private ConfigurationAdmin configurationAdmin;

    @Descriptor("creates a species")
    public void create(@Descriptor("id of the species") final String speciesId) throws IOException, InvalidSyntaxException {
        final String filter = String.format("(%s=%s)", Constants.OBJECTCLASS, Species.class.getSimpleName());
        final Configuration[] existingConfigurations = configurationAdmin.listConfigurations(filter);
        System.out.println(Arrays.toString(existingConfigurations));

        final Configuration speciesConfiguration = configurationAdmin.getConfiguration(Species.class.getSimpleName(), "?");
        Dictionary<String, Object> configProperties = new Hashtable<>();
        configProperties.put(Constants.SERVICE_PID, "Species");

        speciesConfiguration.update(configProperties);
    }
}

但是所有发生的事情是它修改了配置,而不是创建一个新的配置。

使用Configuration Admin为同一类创建多个配置时,我需要做什么?

2018-06-19编辑:

进行由Peter Kriens的答案指定的更改:

  • @Designate注释添加到Species
  • @Component#name设置为唯一的@Component#name
  • @Component#configurationPolicy设置为ConfigurationPolicy.REQUIRE
  • @ObjectClassDefinition添加到Species.Config
  • 使用以@Component#name作为pid的ConfigurationAdmin#getConfigurationcreateConfiguration不存在,仅此和createFactoryConfiguration

导致仅创建一个配置,该配置将通过后续调用进行更新。

OSGi Configuration Admin具有2种不同类型的配置:

  • 单例–具有PID
  • 工厂–有一个PID(用于工厂实例)和一个工厂PID用于“实例”组。

因此,在OSGi> = 6中,您可以执行以下操作:

 @Designate( ocd= Species.Config.class, factory=true )
 @Component( name = "species.pid", configurationPolicy=ConfigurationPolicy.REQUIRE )
 public class Species {
      @ObjectClassDefinition
      @interface Config {
          String id();
      }

      @Activate
      void activate( Config config) {
          System.out.println( config.id() );
      }
}

现在,该命令(用list + delete函数扩展):

 @Component(
   property = {
     CommandProcessor.COMMAND_SCOPE + "=species",
     CommandProcessor.COMMAND_FUNCTION + "=create",
     CommandProcessor.COMMAND_FUNCTION + "=list",
     CommandProcessor.COMMAND_FUNCTION + "=delete"
   },
   service = CreateSpeciesCommand.class
 )
 public class CreateSpeciesCommand {
   @Reference
   ConfigurationAdmin configurationAdmin;

   public Configuration create(String speciesId) throws Exception {
     Configuration c = configurationAdmin.createFactoryConfiguration( "species.pid", "?");
     Hashtable<String,Object> d = new Hashtable();
     d.put("id", speciesId);
     c.update( d );
     return c;         
   }

   public Configuration[] list() throws Exception {
     return configurationAdmin.
        listConfigurations( "(service.factoryPid=species.pid)");
   }

   public boolean delete(String id) throws Exception {
     Configuration[] list = configurationAdmin.
        listConfigurations( "(&(service.factoryPid=species.pid)(id="+id+"))");
     if ( list == null) {
        return false;
     }
     for ( Configuration c : list ) {
        c.delete();
     }
     return true;
   }
}

一些注意事项:

  • 编写时未进行编译,因此可能存在一些编译错误
  • WebConsole可以更好地创建和删除种类
  • 跳过Gogo注释以提高可读性
  • 显然没有对“过滤器”注入攻击的防御

为了获得每个呼叫的新配置,我需要更改以下内容:

  • Species类的@Component#factory值设置为唯一的值
  • 使用ConfigurationAdmin#createFactoryConfiguration方法而不是getConfiguration方法

我尝试应用Peter Kriens的答案指定的更改:

  • @Designate注释添加到Species
  • @Component#name设置为唯一的@Component#name
  • @Component#configurationPolicy设置为ConfigurationPolicy.REQUIRE
  • @ObjectClassDefinition添加到Species.Config
  • 使用以@Component#name作为pid的ConfigurationAdmin#getConfigurationcreateConfiguration不存在,只有this和createFactoryConfiguration ); createFactoryConfiguration使用@Component#factory

这不仅可以进行新的配置,还可以同时激活物种成分。 不知道为什么会这样,但我正在调查中。

更新的代码

Species.java

package net.zephyrion.hummingbird.module.species;

import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;

import java.util.Objects;

@Component(
    factory = "Species",
    configurationPolicy = ConfigurationPolicy.REQUIRE,
    service = Species.class
)
public final class Species {

    @interface Config {
        String id() default "";
    }
    private Config config;

    @Activate
    public void configure(final Config config) {
        this.config = Objects.requireNonNull(config);
    }

    private String getId() {
        return config.id();
    }
}

CreateSpeciesCommand.java

package net.zephyrion.hummingbird.module.species;

import org.apache.felix.service.command.CommandProcessor;
import org.apache.felix.service.command.Descriptor;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

import java.io.IOException;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;

@Component(
    property = {
        CommandProcessor.COMMAND_SCOPE + "=species",
        CommandProcessor.COMMAND_FUNCTION + "=create"
    },
    service = CreateSpeciesCommand.class
)
public class CreateSpeciesCommand {

    /* L1 */

    @Reference(bind = "bindConfigurationAdmin")
    private ConfigurationAdmin configurationAdmin;

    @Descriptor("creates a species")
    public void create(@Descriptor("id of the species") final String speciesId) throws IOException {
        try {
            final String factoryPid = Species.class.getSimpleName();
            final String filter = String.format("(&(id=%s)(service.factoryPid=%s))", speciesId, factoryPid);
            final boolean configurationExists = configurationAdmin.listConfigurations(filter) != null;
            if (!configurationExists) {
                final Configuration speciesConfiguration = configurationAdmin.createFactoryConfiguration(factoryPid, "?");
                Dictionary<String, Object> configProperties = new Hashtable<>();
                configProperties.put("id", speciesId);

                speciesConfiguration.update(configProperties);
            }
        }
        catch (InvalidSyntaxException e) {
            e.printStackTrace();
        }
    }

    /* L2 */

    private void bindConfigurationAdmin(final ConfigurationAdmin configurationAdmin) {
        // TODO Obj.rnn
        this.configurationAdmin = configurationAdmin;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM