我正在开发一个利用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' answer指定的更改:
@Designate
注释添加到Species
类@Component#name
设为唯一@Component#configurationPolicy
设为ConfigurationPolicy.REQUIRE
@ObjectClassDefinition
添加到Species.Config
类ConfigurationAdmin#getConfiguration
(createConfiguration
不存在,只有createFactoryConfiguration
)@Component#name
作为pid 只会创建一个配置,后续调用会更新。
答案 0 :(得分:2)
OSGi Configuration Admin有两种不同类型的配置:
在OSGi&gt; = 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;
}
}
一些注意事项:
答案 1 :(得分:0)
为了获得每个呼叫的新配置,我需要更改以下内容:
Species
类的ConfigurationAdmin#createFactoryConfiguration
值设置为唯一值getConfiguration
方法代替@Designate
方法我尝试应用Peter Kriens' answer指定的更改:
Species
类添加@Component#name
注释@Component#configurationPolicy
设置为唯一的内容ConfigurationPolicy.REQUIRE
设置为@ObjectClassDefinition
Species.Config
添加到ConfigurationAdmin#getConfiguration
类createConfiguration
作为pid使用createFactoryConfiguration
(@Component#name
不存在,只有createFactoryConfiguration
); @Component#factory
使用来自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;
}
}
control_conversion test_conversion
day1 100 101
day3 140 200
day5 200 320
day7 400 800