001package gu.dtalk.client;
002
003import org.apache.commons.cli.CommandLine;
004import org.apache.commons.cli.Option;
005import org.apache.commons.cli.Options;
006import org.apache.commons.cli.ParseException;
007
008import com.google.common.base.Strings;
009import com.google.common.net.HostAndPort;
010
011import gu.dtalk.OptionType;
012import gu.dtalk.activemq.DefaultCustomActivemqConfigProvider;
013import gu.simplemq.Constant;
014import gu.simplemq.MQProperties;
015import gu.simplemq.MessageQueueType;
016import gu.simplemq.utils.URISupport;
017import net.gdface.cli.BaseAppConfig;
018import static redis.clients.jedis.Protocol.*;
019
020import java.net.URI;
021import java.net.URISyntaxException;
022import java.util.HashMap;
023import java.util.Map;
024
025import static com.google.common.base.Preconditions.checkArgument;
026import static com.google.common.base.Preconditions.checkState;
027import static gu.dtalk.client.SampleConsole.run;
028import static net.gdface.utils.ConditionChecks.checkTrue;
029import static gu.dtalk.activemq.ActivemqContext.HELPER;
030import static gu.dtalk.activemq.ActivemqContext.CONST_PROVIDER;
031
032/**
033 * 终端命令行配置参数
034 * @author guyadong
035 *
036 */
037public class SampleConsoleActivemqConfig extends BaseAppConfig implements SampleConsoleConstants,Constant {
038        @SuppressWarnings("serial")
039        private static final HashMap<String, Object> CONSTANTS = 
040                new HashMap<String, Object>(){{put(IMPL_TYPE, MessageQueueType.ACTIVEMQ);}};
041        private final MQProperties activemqProperties = HELPER.initParameters(null);
042
043        private String mac;
044        private SampleConsoleActivemqConfig() {
045                super(true);
046                options.addOption(Option.builder().longOpt(AMQ_HOST_OPTION_LONG)
047                                .desc(AMQ_HOST_OPTION_DESC + CONST_PROVIDER.getDefaultHost()).numberOfArgs(1).build());
048
049                options.addOption(Option.builder().longOpt(AMQ_PORT_OPTION_LONG)
050                                .desc(AMQ_PORT_OPTION_DESC + CONST_PROVIDER.getDefaultPort()).numberOfArgs(1).type(Number.class).build());
051
052                options.addOption(Option.builder(AMQ_USERNAME_OPTION).longOpt(AMQ_USERNAME_OPTION_LONG)
053                                .desc(AMQ_USERNAME_OPTION_DESC).numberOfArgs(1).build());
054
055                options.addOption(Option.builder(AMQ_PWD_OPTION).longOpt(AMQ_PWD_OPTION_LONG)
056                                .desc(AMQ_PWD_OPTION_DESC).numberOfArgs(1).build());
057
058                options.addOption(Option.builder().longOpt(AMQ_URI_OPTION_LONG)
059                                .desc(AMQ_URI_OPTION_DESC).numberOfArgs(1).build());
060
061                options.addOption(Option.builder().longOpt(AMQ_TIMEOUT_OPTION_LONG)
062                                .desc(AMQ_TIMEOUT_OPTION_DESC + DEFAULT_TIMEOUT + " ms.").numberOfArgs(1).type(Number.class).build());
063
064                options.addOption(Option.builder().longOpt(DEVICE_MAC_OPTION_LONG)
065                                .desc(DEVICE_MAC_OPTION_DESC ).numberOfArgs(1).build());
066
067                options.addOption(Option.builder().longOpt(MQTT_OPTION_LONG).desc(MQTT_OPTION_DESC).optionalArg(true).numberOfArgs(1).build());
068                
069                defaultValue.setProperty(AMQ_HOST_OPTION_LONG, activemqProperties.get(MQ_HOST));
070                defaultValue.setProperty(AMQ_PORT_OPTION_LONG, activemqProperties.get(MQ_PORT));
071                defaultValue.setProperty(AMQ_USERNAME_OPTION_DESC, activemqProperties.get(MQ_USERNAME));
072                defaultValue.setProperty(AMQ_PWD_OPTION_LONG, activemqProperties.get(MQ_PASSWORD));
073                defaultValue.setProperty(AMQ_URI_OPTION_LONG, activemqProperties.get(MQ_URI));
074                defaultValue.setProperty(AMQ_TIMEOUT_OPTION_LONG, activemqProperties.get(MQ_TIMEOUT));
075                defaultValue.setProperty(DEVICE_MAC_OPTION_LONG, "");
076
077        }
078        @Override
079        public void loadConfig(Options options, CommandLine cmd) throws ParseException {
080                super.loadConfig(options, cmd);
081                
082                if(hasProperty(MQ_HOST)){
083                        activemqProperties.setProperty(MQ_HOST, (String) getProperty(AMQ_HOST_OPTION_LONG));
084                }
085                if(hasProperty(AMQ_PORT_OPTION_LONG)){
086                        activemqProperties.setProperty(MQ_PORT, (String) getProperty(AMQ_PORT_OPTION_LONG));
087                }
088                if(hasProperty(AMQ_USERNAME_OPTION_LONG)){
089                        activemqProperties.setProperty(MQ_USERNAME, (String) getProperty(AMQ_USERNAME_OPTION_LONG));
090                }
091                if(hasProperty(AMQ_PWD_OPTION_LONG)){
092                        activemqProperties.setProperty(MQ_PASSWORD, (String) getProperty(AMQ_PWD_OPTION_LONG));
093                }
094                if(hasProperty(AMQ_URI_OPTION_LONG)){
095                        activemqProperties.setProperty(MQ_URI, (String) getProperty(AMQ_URI_OPTION_LONG));
096                }
097                if(hasProperty(AMQ_TIMEOUT_OPTION_LONG)){
098                        activemqProperties.setProperty(MQ_TIMEOUT, (String) getProperty(AMQ_TIMEOUT_OPTION_LONG));
099                }
100                this.mac = (String) getProperty(DEVICE_MAC_OPTION_LONG);
101                if(!Strings.isNullOrEmpty(this.mac)){
102                        // 检查输入的mac地址字符串是否符合格式要求
103                        checkTrue(OptionType.MAC.strValidator.apply(this.mac),
104                                        ParseException.class,"INVALID MAC address %s",this.mac);
105                        this.mac = this.mac.replaceAll("[:-]", "");
106                }
107                
108                parseMQTTOption();
109
110        }
111        
112        private void parseMQTTOption() throws ParseException{
113                if(hasProperty(MQTT_OPTION_LONG)){
114                        Object v = getProperty(MQTT_OPTION_LONG);
115                        activemqProperties.setProperty(MQ_PUBSUB_MQTT, "true");
116                        if(v instanceof String){
117                                String value =  (String) v;
118                                try {
119                                        // 尝试解析为端口号(整数)
120                                        int port = Integer.parseInt(value);
121                                        checkArgument(port > 0,"INVALID option %s:%s,as port ,>0 required", MQTT_OPTION_LONG, port);
122                                        activemqProperties.setProperty(MQ_PUBSUB_URI, String.format("mqtt://%s:%d",CONST_PROVIDER.getDefaultHost(), port));
123                                } catch (NumberFormatException e) {
124                                        HostAndPort hostAndPort;
125                                        try {
126                                                // 尝试解析为 HOST:PORT OR HOST 格式
127                                                // 如果为 HOST 格式,则端口号使用默认值
128                                                hostAndPort = HostAndPort.fromString(value).withDefaultPort(DEFAULT_MQTT_PORT); 
129                                        } catch (IllegalArgumentException e2) {
130                                                try {
131                                                        // 尝试解析为URI
132                                                        URI u = new URI(value);
133                                                        // 强制修改schema为mqtt,
134                                                        URI r = URISupport.changeScheme(u, "mqtt");
135                                                        activemqProperties.setProperty(MQ_PUBSUB_URI, r.toString());
136                                                        return ;
137                                                } catch (URISyntaxException e1) {
138                                                        throw new ParseException(String.format("INVALID value %s for option %s", value, MQTT_OPTION_LONG));
139                                                }
140                                        }
141                                        activemqProperties.setProperty(MQ_PUBSUB_URI, String.format("mqtt://%s:%d",hostAndPort.getHost(), hostAndPort.getPort()));
142                                        return;
143                                }
144                        }else {
145                                // v 为 true
146                                checkState(Boolean.TRUE.equals(v),"INVALID VALUE TYPE FOR %s=%s",MQTT_OPTION_LONG,v);
147                                // 参数个数为0时,默认使用 DEFAULT_MQTT_CONNECTOR
148                                activemqProperties.setProperty(MQ_PUBSUB_URI, DEFAULT_MQTT_CONNECTOR);
149                        }
150                }
151        }
152        /**
153         * @return activemqProperties
154         */
155        public MQProperties getActivemqParameters() {
156                return activemqProperties;
157        }
158        /**
159         * @return 目标设备MAC地址
160         */
161        public String getMac() {
162                return mac;
163        }
164
165        @Override
166        protected String getAppName() {
167                return SampleConsole.class.getSimpleName();
168        }
169        @Override
170        protected String getHeader() {
171                return "Text terminal for Dtalk Device(Dtalk设备交互字符终端)";
172        }
173        @Override
174        protected void doAfterParse() {
175                DefaultCustomActivemqConfigProvider.INIT_PROPERTIES.init(activemqProperties);
176        }
177        @Override
178        protected Map<String, Object> doGetConstants() {
179                return CONSTANTS;
180        }
181        public static void main(String []args){
182                run(new SampleConsoleActivemqConfig(), args);
183        }
184}