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

Java 如何使用Configuration Admin为同一类创建多个配置?,java,osgi,Java,Osgi,我正在开发一个实体组件系统游戏引擎,它将利用OSGi框架。 我希望用户/开发人员能够以模块化的方式创建自己的组件类型,类似于Bethesda创建工具包 我考虑的方法是创建一个表示组件类型的类,然后使用Configuration Admin创建配置,但我不确定我的理解是否正确 我有一个类要用作组件类型 @Component( configurationPid = "Species", configurationPolicy = ConfigurationPolicy.REQUIR

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

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

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

@Component(
    configurationPid = "Species",
    configurationPolicy = ConfigurationPolicy.REQUIRE,
    service = Species.class
)
public final class Species {
    // ...
}
为了测试这一点,我为ApacheGogo创建了一个命令来创建一个
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);
    }
}
@组件(
属性={
CommandProcessor.COMMAND_SCOPE+“=物种”,
CommandProcessor.COMMAND_函数+“=创建”
},
服务=CreateSpeciesCommand.class
)
公共类CreateSpeciesCommand{
/*L1*/
@参考(bind=“bindConfigurationAdmin”)
私有配置管理员配置管理员;
@描述符(“创建一个物种”)
public void create(@Descriptor(“物种id”)最终字符串speciesId)抛出IOException,InvalidSyntaxException{
最终字符串筛选器=String.format((%s=%s)”,Constants.OBJECTCLASS,Species.class.getSimpleName();
最终配置[]existingConfigurations=configurationAdmin.listConfigurations(过滤器);
System.out.println(Arrays.toString(现有配置));
最终配置speciesConfiguration=configurationAdmin.getConfiguration(Species.class.getSimpleName(),“?”;
Dictionary configProperties=新哈希表();
configProperties.put(Constants.SERVICE_PID,“Species”);
speciesConfiguration.update(配置属性);
}
}
但所发生的一切是它修改了配置,而不是创建一个新的配置

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

2018-06-19编辑:

进行以下指定的更改:

  • 添加
    @specify
    注释到
    物种
  • @Component#name
    设置为唯一的名称
  • @Component#configurationPolicy
    设置为
    configurationPolicy.REQUIRE
  • @ObjectClassDefinition
    添加到
    Species.Config
  • 使用
    ConfigurationAdmin#getConfiguration
    createConfiguration
    不存在,只有此和
    createFactoryConfiguration
    )并将
    @组件名称作为pid

结果只创建一个配置,并随后续调用进行更新。

OSGi configuration Admin有两种不同类型的配置:

  • Singleton–具有PID
  • Factory–有一个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函数):

@组件(
属性={
CommandProcessor.COMMAND_SCOPE+“=物种”,
CommandProcessor.COMMAND_函数+“=创建”,
CommandProcessor.COMMAND_函数+“=列表”,
CommandProcessor.COMMAND_函数+“=删除”
},
服务=CreateSpeciesCommand.class
)
公共类CreateSpeciesCommand{
@参考文献
配置管理员配置管理员;
公共配置创建(字符串speciesId)引发异常{
配置c=configurationAdmin.createFactoryConfiguration(“species.pid”,“?”);
Hashtable d=新的Hashtable();
d、 put(“id”,speciesId);
c、 更新(d);
返回c;
}
公共配置[]列表()引发异常{
返回configurationAdmin。
列表配置(((service.factoryPid=species.pid)”;
}
公共布尔删除(字符串id)引发异常{
配置[]列表=配置管理员。
列表配置(&(service.factoryPid=species.pid)(id=“+id+”));
if(list==null){
返回false;
}
用于(配置c:列表){
c、 删除();
}
返回true;
}
}
一些注意事项:

  • 未编译而编写,因此可能存在一些编译错误
  • WebConsole更适合创建和删除物种
  • 为了便于阅读,跳过了Gogo注释
  • 显然,对“过滤”注入攻击没有防御

OSGi配置管理员有两种不同类型的配置:

  • Singleton–具有PID
  • Factory–有一个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函数):

@组件(
属性={
CommandProcessor.COMMAND_SCOPE+“=物种”,
CommandProcessor.COMMAND_函数+“=创建”,
CommandProcessor.COMMAND_函数+“=列表”,
CommandProcessor.COMMAND_函数+“=删除”
},
服务=CreateSpeciesCommand.class
)
公共类CreateSpeciesCommand{
@参考文献
配置管理员配置管理员;
公共配置创建(字符串speciesId)引发异常{
配置c=configurationAdmin.createFactoryConfiguration(“species.pid”,“?”);
Hashtable d=新的Hashtable();
d、 put(“id”,speciesId);
c、 更新(d);
返回c;
}
公共配置[]列表()引发异常{
返回configurationAdmin。
列表配置(((service.factoryPid=species.pid)”;
}
公共布尔删除(字符串id)引发异常{
配置[]列表=配置管理员。
列表配置(&(service.factoryPid=species.pid)(id=“+id+”));
if(list==null){
返回false;
}
对于(配置c:
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();
    }
}
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;
    }
}