簡體   English   中英

無法在OSGi Apache Felix Web Console中添加加號按鈕以創建新的配置實例

[英]Can't add the plus button in OSGi Apache Felix Web Console to create new configuration instances

我使用ManagedServiceFactory通過配置文件中包含的參數來創建新實例。 我想通過Apache Felix Web Console來做到這一點,但是它沒有給我加號按鈕來添加新配置。
我想我缺少了一些東西。 請你幫助我好嗎?
這是我的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;
    }
}

我使用ManagedServiceFactory通過配置文件中包含的參數來創建新實例。

您正在使用聲明式服務(您的類帶有@Component注釋),但也正在實現ManagedServiceFactory。 正如其他人提到的那樣,這是一種不良做法,您不應該這樣做。 此外,您的代碼不是線程安全的,並且Map<String, Component> components可能會損壞。

一個更好的解決方法是按照使組件的建議configurationPolicy=ConfigurationPolicy.REQUIRE並使用@Activate方法來接收配置和@Destroy方法來處理缺失。 然后,您根本不需要地圖。

我想通過Apache Felix Web Console來做到這一點,但是它沒有給我加號按鈕來添加新配置。

Felix Web控制台正在使用元類型來生成此用戶界面。 編寫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方法中。

@Activate
void activate(MyConfig config) {
    // process config...
}

您也可以根據需要注入地圖:

@Activate
void activate(MyConfig config, Map<String, Object> rawConfig) {
    // process config...
}

一旦定義了元類型,就會顯示+圖標,以及用於配置組件的自定義UI。

也許有些我不知道,但是AFAIK不能通過Configuration Admin Service (Web控制台配置使用的)創建托管服務的新實例。

ManagedServiceFactory是一個工廠,您(或代表您的框架)調用該工廠以按需創建服務。 您可以使用Configuration Admin Service來配置工廠本身,但是由工廠負責配置其創建的服務實例。

另一方面,您可以使用元類型服務來描述任何非托管服務的配置。 如果這樣做,則在提供新配置時,Felix Web Console和Apache File Install之類的工具可以使用該信息來創建服務的新實例。 這是您在Felix Web Console配置屏幕中看到加號按鈕的時間。

我認為您根本不需要實現ManagedServiceFactory 獲取多次創建的組件,即每個Config Admin記錄一個實例。 您只需要創建一個配置屬性為“ require”的普通組件。 例如:

@Component(name = "camel, configurationPolicy=ConfigurationPolicy.REQUIRE)
public class ConfigReaderComponent {

    @Activate
    void activate(Map<String, Object> configProps) {
        // process config...
    }
}

對於帶有camel的工廠PID的每個配置記錄,整個類將實例化一次。 WebConsole將意識到這是一個工廠,並將啟用加號按鈕。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM