我使用ManagedServiceFactory通过配置文件中包含的参数创建新实例。我想通过 Apache Felix Web控制台来实现它,但它没有给我添加新配置的加号按钮。
我想我错过了什么。你能帮帮我吗?
这是我的Apache Felix Web控制台的image
这是实现 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;
}
}
答案 0 :(得分:1)
我使用ManagedServiceFactory通过配置文件中包含的参数创建新实例。
您正在使用声明式服务(您的类已注释@Component
),但也正在实现ManagedServiceFactory。正如其他人所说,这是一种不好的做法,你不应该这样做。此外,您的代码不是线程安全的,Map<String, Component> components
可能会损坏。
更好的解决方案是遵循建议使用组件configurationPolicy=ConfigurationPolicy.REQUIRE
并使用@Activate
方法接收配置和@Destroy
方法来处理删除的建议。然后你根本不需要这些地图。
我想通过Apache Felix Web控制台来实现它,但它没有给我添加新配置的加号按钮。
Felix Web控制台正在使用Metatype生成此用户界面。编写元类型XML非常糟糕,人类不应该尝试,但幸运的是,您可以使用org.osgi.service.metatype.annotations
来定义元类型。这些注释应用于描述配置布局的界面或注释。例如:
@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时,您也可以将此配置类型直接注入激活方法。
@Activate
void activate(MyConfig config) {
// process config...
}
如果您愿意,也可以注入地图:
@Activate
void activate(MyConfig config, Map<String, Object> rawConfig) {
// process config...
}
一旦定义了元数据类型,就会出现+
图标,以及用于配置组件的自定义UI。
答案 1 :(得分:0)
可能有一些我不知道的事情,但是AFAIK您无法通过Configuration Admin Service创建托管服务的新实例(这是Web控制台配置使用的)。
ManagedServiceFactory
是您(或代表您的框架)调用以按需创建服务的工厂。您可以使用Configuration Admin Service来配置工厂本身,但是工厂负责配置它创建的服务实例。
另一方面,您可以使用Metatype service来描述任何非托管服务的配置。如果您这样做,那么像Felix Web控制台和Apache文件安装这样的工具可以在提供新配置时使用该信息创建服务的新实例。这是当您在Felix Web控制台配置屏幕中看到加号按钮时。