java - 无法在 OSGi Apache Felix Web 控制台中添加加号按钮来创建新的配置实例

标签 java osgi apache-felix

我使用 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/

相关文章:

java - 如何替换 blueprint/context.xml 中加载的 cfg 文件中的文本值

java - 如何以编程方式连接到嵌入式 HornetQ 服务器

java - 如何在 Apache Felix Gogo shell 上清屏?

java - 如何使 Java jtable、单元格编辑器和撤消协同工作而不创建无关的撤消事件?

java - 限定方法调用是否会降低 Java 中的性能?

java - Scala/Clojure 互操作可以在 PC 上运行,但在另一台 PC 上失败并出现 java.lang.ExceptionInInitializerError

java - 在 pax 考试测试阶段未创建配置管理和声明性服务

java - Activity 必须导出或包含 Intent 过滤器

java - 当用户请求时以编程方式创建 ipojo 组件实例

java - 停止使用的服务包时会发生什么