我使用 ManagedServiceFactory 通过配置文件中包含的参数创建新实例。我想通过 Apache Felix Web Console 来完成此操作,但它没有给我添加新配置的加号按钮。
我想我错过了一些东西。你能帮我一下吗?
这是image我的 Apache Felix Web 控制台
这是实现ManagedServiceFactory的类
@org.osgi.service.component.annotations.Component(
name = "camel_config",
property = {
"service.pid=camel",
"factory=true"
},
configurationPolicy = ConfigurationPolicy.IGNORE
)
public class ConfigReaderFactory implements ManagedServiceFactory {
private static final String DELETE_CONDITIONS = "readLock=changed&idempotent=false&noop=true&delete=true";
private static final String NON_DELETE_CONDITIONS = "noop=true";
private volatile DependencyManager dependencyManager;
private final Map<String, Component> components = new HashMap<>();
private List<String> attributes;
private List<String> csvTypes;
private CamelService camel;
private TypeConverter converter;
private EventPublisher publisher;
private String url;
private String name;
private int confLine;
private String endpointType;
private String ip;
private String username;
private String password;
private String folder;
private boolean delete;
private Double latitude;
private Double longitude;
private String email;
@Override
public String getName() {
return this.getClass().getName();
}
@Override
public void updated(String pid, @SuppressWarnings("rawtypes") Dictionary props) throws ConfigurationException {
if (components.containsKey(pid)) {
return;
}
if (props != null) {
attributes = new ArrayList<>();
csvTypes = new ArrayList<>();
int count = 1;
String configurationLine;
while ((configurationLine = (String) props.get(Integer.toString(count++))) != null) {
List<String> values = Utils.getValuesFromLine(configurationLine);
attributes.add(values.size() >= 1 ? values.get(0) : TypeConverter.NAMELESS);
csvTypes.add(values.size() >= 2 ? values.get(1) : TypeConverter.NAMELESS);
}
confLine = Integer.parseInt((String) props.get(Config.CONFIG_LINE));
name = (String) props.get(Config.NAME);
initConfigParameters(pid, props);
buildURL();
System.out.println("[URL] " + url);
try {
Map<String, Object> params = new HashMap<>();
putParameters(params);
camel.start(params);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void deleted(String pid) {
Component component = components.remove(pid);
dependencyManager.remove(component);
component.stop();
}
private void buildURL() {
url = "";
switch(endpointType) {
case Constants.FTP:
url += "ftp://" + username + "@" + ip + "/" + folder + "?";
if(!password.equals("")) {
url += "password=" + password + "&";
}
break;
case Constants.FILE:
url += "file://" + folder + "?";
break;
case Constants.EMAIL:
url += "imaps://imap.gmail.com?username="+email+"&password="+password
+"&delete=false&unseen=false";
}
if(endpointType.equals(Constants.FTP) || endpointType.equals(Constants.FILE)) {
if (delete) {
url += DELETE_CONDITIONS;
} else {
url += NON_DELETE_CONDITIONS;
}
}
}
private void initConfigParameters(String pid, @SuppressWarnings("rawtypes") Dictionary props) {
confLine = Integer.parseInt((String) props.get(Config.CONFIG_LINE));
name = (String) props.get(Config.NAME);
endpointType = (String) props.get(Config.ENDPOINT_TYPE);
ip = (String) props.get(Config.IP_ADDRESS);
username = (String) props.get(Config.USERNAME);
password = (String) props.get(Config.PASSWORD);
folder = (String) props.get(Config.FOLDER);
email = (String) props.get(Config.EMAIL);
delete = ((String) props.get(Config.DELETE)).equals("true");
if((String) props.get(Config.LATITUDE)!=null) {
latitude = Double.parseDouble((String) props.get(Config.LATITUDE));
}
if((String) props.get(Config.LONGITUDE)!=null) {
longitude = Double.parseDouble((String) props.get(Config.LONGITUDE));
}
printParameters(pid);
}
private void putParameters(Map<String, Object> params) {
params.put(Constants.ATTRIBUTES, attributes);
params.put(Constants.TYPES, csvTypes);
params.put(Constants.CONF_LINE, confLine);
params.put(Constants.SOURCE, name);
params.put(Constants.PUBLISHER, publisher);
params.put(Constants.CONVERTER, converter);
params.put(Constants.LATITUDE, latitude);
params.put(Constants.LONGITUDE, longitude);
params.put(Constants.ENDPOINT_TYPE, endpointType);
params.put(Constants.EMAIL, email);
params.put(Constants.CONTEXT, FrameworkUtil.getBundle(this.getClass()).getBundleContext());
Processor processor = new CSVProcessor(params);
params.put(Constants.PROCESSOR, processor);
params.put(Constants.URL, url);
}
private void printParameters(String pid) {
System.out.println("\nStarting camel with parameters:");
System.out.println("Config file name "+pid);
System.out.println("[sensor_name]::" + name);
if(latitude!=null && longitude!=null) {
System.out.println("[latitude]::" + latitude);
System.out.println("[longitude]::" + longitude);
}
System.out.println("[endpoint_type]::" + endpointType);
if(endpointType.equals("ftp")) {
System.out.println("[ip_address]::" + ip);
System.out.println("[folder]::" + folder);
System.out.println("[user]::" + username);
System.out.println("[password]::" + password);
} else if(endpointType.equals("file")) {
System.out.println("[folder]::" + folder);
} else if(endpointType.equals("email")) {
System.out.println("[email]::" + email);
System.out.println("[password]::" + password);
}
System.out.println("[delete]::" + delete);
}
@Reference(service = TypeConverter.class)
public void setTypeConverter(TypeConverter converter) {
this.converter = converter;
}
public void unsetTypeConverter(TypeConverter converter) {
this.converter = null;
}
@Reference(service = EventPublisher.class)
public void setEventPublisher(EventPublisher publisher) {
this.publisher = publisher;
}
public void unsetEventPublisher(EventPublisher publisher) {
this.publisher = null;
}
@Reference(service = CamelService.class)
public void setCamelService(CamelService camel) {
this.camel = camel;
}
public void unsetCamelService(CamelService camel) {
this.camel = null;
}
}
最佳答案
I use a ManagedServiceFactory to create new instances by the parameters that are included in the configuration files.
您正在使用声明性服务(您的类被注释为 @Component
),但也实现了 ManagedServiceFactory。正如其他人提到的那样,这是一种不好的做法,您不应该这样做。此外,您的代码不是线程安全的,并且 Map<String, Component> components
可能会被损坏。
更好的解决方案是遵循制作组件 configurationPolicy=ConfigurationPolicy.REQUIRE
的建议并使用 @Activate
接收配置和 @Destroy
的方法处理删除的方法。这样您就根本不需要 map 了。
I want to do it by the Apache Felix Web Console but it doesn't give me the plus button to add new configurations.
Felix Web 控制台使用 Metatype 生成此用户界面。编写元类型 XML 非常可怕,人类不应该尝试,但幸运的是您可以使用 org.osgi.service.metatype.annotations
定义你的元类型。这些注释应用于描述配置布局的接口(interface)或注释。例如:
@ObjectClassDefinition
public @interface MyConfig {
// This defines the property key "myProp" with
// a default value of "foo" and it will show
// up in the UI with the name "My Prop"
String myProp() default "foo";
// This defines the property key "my.prop"
// with a default value of 42. The @AD
// allows customisation of the UI
@AD(description="Something descriptive")
int my_num() default 42;
}
您可以使用 @Designate 注释将此配置属性类型与您的组件链接起来:
@org.osgi.service.component.annotations.Component(
name = "camel_config", configurationPid=camel",
configurationPolicy = ConfigurationPolicy.REQUIRE
)
@Designate(ocd=MyConfig.class)
public class ConfigReaderFactory {
...
}
使用 DS 1.3 时,您还可以将此配置类型直接注入(inject)到您的激活方法中。
@Activate
void activate(MyConfig config) {
// process config...
}
如果您愿意,您也可以注入(inject) map :
@Activate
void activate(MyConfig config, Map<String, Object> rawConfig) {
// process config...
}
定义元类型后,+
将出现图标以及用于配置组件的自定义 UI。
关于java - 无法在 OSGi Apache Felix Web 控制台中添加加号按钮来创建新的配置实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47550999/