|  |  | 
 |  |  | package com.dy.common.mw.protocol; | 
 |  |  |  | 
 |  |  | import java.net.URI; | 
 |  |  | import java.net.URL; | 
 |  |  | import java.util.Collection; | 
 |  |  | import java.util.HashMap; | 
 |  |  | import java.util.List; | 
 |  |  | import java.util.Set; | 
 |  |  |  | 
 |  |  | import com.dy.common.util.ClassScan; | 
 |  |  | import com.dy.common.util.NumUtil; | 
 |  |  | import org.apache.logging.log4j.LogManager; | 
 |  |  | import org.apache.logging.log4j.Logger; | 
 |  |  | import org.reflections.Reflections; | 
 |  |  |  | 
 |  |  | /** | 
 |  |  |  * 扫描: | 
 |  |  | 
 |  |  |  */ | 
 |  |  | @SuppressWarnings("unused") | 
 |  |  | public class AnnotationScan { | 
 |  |  | 	 | 
 |  |  |    private static String scanRootPackage = "com.dy.common.mw.protocol." ; | 
 |  |  |  | 
 |  |  |    private static final Logger log = LogManager.getLogger(AnnotationScan.class); | 
 |  |  |  | 
 |  |  |    private static String scanRootPackage = "com.dy.common.mw.protocol" ; | 
 |  |  |  | 
 |  |  |    private static AnnotationScan instance ; | 
 |  |  | 	 | 
 |  |  |  | 
 |  |  |    private AnnotationScan(){ | 
 |  |  |    } | 
 |  |  | 	 | 
 |  |  |  | 
 |  |  |    /** | 
 |  |  |     * 得到唯一实例, | 
 |  |  |     * 并在生成唯一实例时,扫描注解类 | 
 |  |  | 
 |  |  |       } | 
 |  |  |       return instance ; | 
 |  |  |    } | 
 |  |  | 	 | 
 |  |  |  | 
 |  |  |    /** | 
 |  |  |     * 扫描出注解的类 | 
 |  |  |     * @throws ClassNotFoundException 异常 | 
 |  |  |     * @throws Exception 异常 | 
 |  |  |     */ | 
 |  |  |    private void scanEndpointAnnotations() throws Exception{ | 
 |  |  |       ClassLoader load = this.getClass().getClassLoader() ; | 
 |  |  | 		 | 
 |  |  |       if(!scanRootPackage.endsWith(".")){ | 
 |  |  |          scanRootPackage += "." ; | 
 |  |  |       } | 
 |  |  |       URL url = AnnotationScan.class.getResource("/" + scanRootPackage.replace('.', '/')); | 
 |  |  |       if(url != null){ | 
 |  |  |          String urlStr = url.toString() ; | 
 |  |  |          if(urlStr != null){ | 
 |  |  |             URI uri = new URI(url.toString()); | 
 |  |  |    private void scanEndpointAnnotations() throws Exception { | 
 |  |  |       Reflections reflections = new Reflections(scanRootPackage); // 指定包名 | 
 |  |  |       Set<Class<?>> driverClasses = reflections.getTypesAnnotatedWith(AnnotationDriver.class); | 
 |  |  |       if (driverClasses != null && driverClasses.size() > 0) { | 
 |  |  |          String protocolName; | 
 |  |  |          short protocolVersion; | 
 |  |  |          String key ; | 
 |  |  |          int priority; | 
 |  |  |          int onLineDataMinLength; | 
 |  |  |          int headMinLength; | 
 |  |  |  | 
 |  |  |             List<String> classNames = new ClassScan().searchClassFromUrl(new URI[]{uri}, scanRootPackage) ; | 
 |  |  |             if(classNames != null && classNames.size() > 0){ | 
 |  |  |                String protocolName ; | 
 |  |  |                int priority; | 
 |  |  |                int onLineDataMinLength; | 
 |  |  |                int headMinLength ; | 
 |  |  |          HashMap<String, AnnotationDriverVo> driverMap = ProtocolCache.getDriverMap(); | 
 |  |  |          HashMap<String, AnnotationPrefixedDataAvailableVo> prefixedDataAvailableMap = ProtocolCache.getPrefixedDataAvailableMap(); | 
 |  |  |          HashMap<String, AnnotationOnLineVo> onLineMap = ProtocolCache.getOnLineMap(); | 
 |  |  |  | 
 |  |  |                HashMap<String, AnnotationDriverVo> driverMap = ProtocolCach.getDriverMap() ; | 
 |  |  |                HashMap<String, AnnotationPrefixedDataAvailableVo> prefixedDataAvailableMap = ProtocolCach.getPrefixedDataAvailableMap() ; | 
 |  |  |                HashMap<String, AnnotationOnLineVo> onLineMap = ProtocolCach.getOnLineMap() ; | 
 |  |  |          for (Class<?> clazz : driverClasses) { | 
 |  |  |             AnnotationDriver ann = clazz.getAnnotation(AnnotationDriver.class); | 
 |  |  |             if (ann != null) { | 
 |  |  |                if (ann.enable()) { | 
 |  |  |                   protocolName = ann.name(); | 
 |  |  |                   protocolVersion = ann.version() ; | 
 |  |  |                   if(protocolName == null || protocolName.trim().equals("")){ | 
 |  |  |                      throw new Exception("严重错误,协议驱动名称注解值为空字符串"); | 
 |  |  |                   } | 
 |  |  |                   if(protocolVersion == -1){ | 
 |  |  |                      throw new Exception("严重错误,协议驱动版本号未配置"); | 
 |  |  |                   } | 
 |  |  |                   key = protocolName + protocolVersion ; | 
 |  |  |                   if (driverMap.containsKey(key)) { | 
 |  |  |                      throw new Exception("严重错误,协议驱动(名称+版本号)" + key + "出现了重复注解!"); | 
 |  |  |                   } | 
 |  |  |                   driverMap.put(key, new AnnotationDriverVo(clazz)); | 
 |  |  |                } | 
 |  |  |             } | 
 |  |  |          } | 
 |  |  |  | 
 |  |  |                for(String cName : classNames){ | 
 |  |  |                   String className = cName.substring(0,  cName.lastIndexOf('.')) ; | 
 |  |  |                   Class<?> clazz = load.loadClass(className) ; | 
 |  |  |                   if(clazz.isAnnotationPresent(AnnotationDriver.class)){ | 
 |  |  |                      AnnotationDriver ann = clazz.getAnnotation(AnnotationDriver.class) ; | 
 |  |  |                      if(ann != null){ | 
 |  |  |                         protocolName = ann.name() ; | 
 |  |  |                         if(!(protocolName.trim().equals(""))){ | 
 |  |  |                            if(driverMap.containsKey(protocolName)){ | 
 |  |  |                               throw new Exception("严重错误,协议驱动名称" + protocolName + "出现了重复注解!") ; | 
 |  |  |                            } | 
 |  |  |                            driverMap.put(protocolName, new AnnotationDriverVo(clazz)) ; | 
 |  |  |                         }else{ | 
 |  |  |                            throw new Exception("严重错误,协议驱动名称注解值为空字符串") ; | 
 |  |  |                         } | 
 |  |  |          Set<Class<?>> prefixedClass = reflections.getTypesAnnotatedWith(AnnotationPrefixedDataAvailable.class); | 
 |  |  |          for (Class<?> clazz : prefixedClass) { | 
 |  |  |             AnnotationPrefixedDataAvailable ann = clazz.getAnnotation(AnnotationPrefixedDataAvailable.class); | 
 |  |  |             if (ann != null) { | 
 |  |  |                if (ann.enable()) { | 
 |  |  |                   protocolName = ann.protocolName(); | 
 |  |  |                   if (!(protocolName.trim().equals(""))) { | 
 |  |  |                      if (prefixedDataAvailableMap.containsKey(protocolName)) { | 
 |  |  |                         throw new Exception("严重错误, 上行数据完整性检查所配协议驱动" + protocolName + "出现了重复注解!"); | 
 |  |  |                      } | 
 |  |  |                   } else { | 
 |  |  |                      throw new Exception("严重错误,上行数据完整性检查所配协议驱动注解值为空字符串"); | 
 |  |  |                   } | 
 |  |  |  | 
 |  |  |                   protocolVersion = ann.protocolVersion(); | 
 |  |  |                   if (protocolVersion == -1) { | 
 |  |  |                      throw new Exception("严重错误, 上行数据完整性检查所配协议版本号未配置"); | 
 |  |  |                   } | 
 |  |  |  | 
 |  |  |                   if(clazz.isAnnotationPresent(AnnotationPrefixedDataAvailable.class)){ | 
 |  |  |                      AnnotationPrefixedDataAvailable ann = clazz.getAnnotation(AnnotationPrefixedDataAvailable.class) ; | 
 |  |  |                      if(ann != null){ | 
 |  |  |                         protocolName = ann.protocolName() ; | 
 |  |  |                         if(!(protocolName.trim().equals(""))){ | 
 |  |  |                            if(prefixedDataAvailableMap.containsKey(protocolName)){ | 
 |  |  |                               throw new Exception("严重错误, 上行数据完整性检查所配协议驱动" + protocolName + "出现了重复注解!") ; | 
 |  |  |                            } | 
 |  |  |                         }else{ | 
 |  |  |                            throw new Exception("严重错误,上行数据完整性检查所配协议驱动注解值为空字符串") ; | 
 |  |  |                         } | 
 |  |  |                   priority = ann.priority(); | 
 |  |  |                   if (priority == 0) { | 
 |  |  |                      throw new Exception("严重错误, 上行数据完整性检查所配优先级注解不能为0"); | 
 |  |  |                   } | 
 |  |  |                   if (isRepeatPrefixedDataAvailablePriority(priority, prefixedDataAvailableMap)) { | 
 |  |  |                      throw new Exception("严重错误, 上行数据完整性检查所配优先级注解(priority)数值" + priority + "重复"); | 
 |  |  |                   } | 
 |  |  |  | 
 |  |  |                         priority = ann.priority() ; | 
 |  |  |                         if(priority == 0){ | 
 |  |  |                            throw new Exception("严重错误, 上行数据完整性检查所配优先级注解不能为0") ; | 
 |  |  |                         } | 
 |  |  |                         if(isRepeatPrefixedDataAvailablePriority(priority, prefixedDataAvailableMap)){ | 
 |  |  |                            throw new Exception("严重错误, 上行数据完整性检查所配优先级注解(priority)数值" + priority + "重复") ; | 
 |  |  |                         } | 
 |  |  |  | 
 |  |  |                         onLineDataMinLength = ann.onLineDataMinLength() ; | 
 |  |  |                   onLineDataMinLength = ann.onLineDataMinLength(); | 
 |  |  |                   /*气象协议为0 | 
 |  |  |                   if(onLineDataMinLength == 0){ | 
 |  |  |                      throw new Exception("严重错误, 上行数据完整性检查所配上线数据最小长度注解不能为0") ; | 
 |  |  |                   } | 
 |  |  |                   */ | 
 |  |  |                         headMinLength = ann.headMinLength() ; | 
 |  |  |                   headMinLength = ann.headMinLength(); | 
 |  |  |                   /*气象协议为0 | 
 |  |  |                   if(headMinLength == 0){ | 
 |  |  |                      throw new Exception("严重错误, 上行数据完整性检查所配上报数据的头部最小长度注解不能为0") ; | 
 |  |  |                   } | 
 |  |  |                   */ | 
 |  |  |  | 
 |  |  |                         prefixedDataAvailableMap.put(protocolName, new AnnotationPrefixedDataAvailableVo(clazz, protocolName, priority, onLineDataMinLength, headMinLength, ProtocolConstant.errorMaxLength)) ; | 
 |  |  |                      } | 
 |  |  |                   } | 
 |  |  |  | 
 |  |  |                   if(clazz.isAnnotationPresent(AnnotationOnLine.class)){ | 
 |  |  |                      AnnotationOnLine ann = clazz.getAnnotation(AnnotationOnLine.class) ; | 
 |  |  |                      if(ann != null){ | 
 |  |  |                         protocolName = ann.protocolName() ; | 
 |  |  |                         if(!(protocolName.trim().equals(""))){ | 
 |  |  |                            if(onLineMap.containsKey(protocolName)){ | 
 |  |  |                               throw new Exception("严重错误, 上线数据分析所配协议驱动" + protocolName + "出现了重复注解!") ; | 
 |  |  |                            } | 
 |  |  |                         }else{ | 
 |  |  |                            throw new Exception("严重错误,上线数据分析所配协议驱动注解值为空字符串") ; | 
 |  |  |                         } | 
 |  |  |  | 
 |  |  |                         priority = ann.priority() ; | 
 |  |  |                         if(priority == 0){ | 
 |  |  |                            throw new Exception("严重错误, 上线数据分析所配优先级注解不能为0") ; | 
 |  |  |                         } | 
 |  |  |                         if(isRepeatOnLinePriority(priority, onLineMap)){ | 
 |  |  |                            throw new Exception("严重错误, 上线数据分析所配优先级注解(priority)数值" + priority + "重复") ; | 
 |  |  |                         } | 
 |  |  |  | 
 |  |  |                         onLineMap.put(protocolName, new AnnotationOnLineVo(clazz, protocolName, priority)) ; | 
 |  |  |                      } | 
 |  |  |                   } | 
 |  |  |                   key = protocolName + protocolVersion ; | 
 |  |  |                   prefixedDataAvailableMap.put(key, new AnnotationPrefixedDataAvailableVo(clazz, protocolName, protocolVersion, priority, onLineDataMinLength, headMinLength, ProtocolConstant.errorMaxLength)); | 
 |  |  |                } | 
 |  |  |  | 
 |  |  |                String error = this.hasErrorInDriver(driverMap) ; | 
 |  |  |                if(error != null){ | 
 |  |  |                   throw new Exception(error) ; | 
 |  |  |                }else{ | 
 |  |  |                   error = this.hasErrorInPrefixedDataAvailable(driverMap, prefixedDataAvailableMap) ; | 
 |  |  |                   if(error != null){ | 
 |  |  |                      throw new Exception(error) ; | 
 |  |  |                   }else{ | 
 |  |  |                      error = this.hasErrorInOnLine(driverMap, onLineMap) ; | 
 |  |  |                      if(error != null){ | 
 |  |  |                         throw new Exception(error) ; | 
 |  |  |                      } | 
 |  |  |                   } | 
 |  |  |                } | 
 |  |  |             }else{ | 
 |  |  |                throw new Exception("严重错误, 扫描协议相关注解所得到类型集合为空,扫描根路径是" + scanRootPackage) ; | 
 |  |  |             } | 
 |  |  |          } | 
 |  |  |  | 
 |  |  |          Set<Class<?>> onLineClass = reflections.getTypesAnnotatedWith(AnnotationOnLine.class); | 
 |  |  |          for (Class<?> clazz : onLineClass) { | 
 |  |  |             AnnotationOnLine ann = clazz.getAnnotation(AnnotationOnLine.class); | 
 |  |  |             if (ann != null) { | 
 |  |  |                if (ann.enable()) { | 
 |  |  |                   protocolName = ann.protocolName(); | 
 |  |  |                   if (!(protocolName.trim().equals(""))) { | 
 |  |  |                      if (onLineMap.containsKey(protocolName)) { | 
 |  |  |                         throw new Exception("严重错误, 上线数据分析所配协议驱动" + protocolName + "出现了重复注解!"); | 
 |  |  |                      } | 
 |  |  |                   } else { | 
 |  |  |                      throw new Exception("严重错误,上线数据分析所配协议驱动注解值为空字符串"); | 
 |  |  |                   } | 
 |  |  |  | 
 |  |  |                   protocolVersion = ann.protocolVersion(); | 
 |  |  |                   if (protocolVersion == -1) { | 
 |  |  |                      throw new Exception("严重错误, 上线数据分析所配协议版本号未配置"); | 
 |  |  |                   } | 
 |  |  |  | 
 |  |  |                   priority = ann.priority(); | 
 |  |  |                   if (priority == 0) { | 
 |  |  |                      throw new Exception("严重错误, 上线数据分析所配优先级注解不能为0"); | 
 |  |  |                   } | 
 |  |  |                   if (isRepeatOnLinePriority(priority, onLineMap)) { | 
 |  |  |                      throw new Exception("严重错误, 上线数据分析所配优先级注解(priority)数值" + priority + "重复"); | 
 |  |  |                   } | 
 |  |  |  | 
 |  |  |                   key = protocolName + protocolVersion ; | 
 |  |  |                   onLineMap.put(key, new AnnotationOnLineVo(clazz, protocolName, protocolVersion, priority)); | 
 |  |  |                } | 
 |  |  |             } | 
 |  |  |          } | 
 |  |  |  | 
 |  |  |          //进行验证 | 
 |  |  |          String error = this.hasErrorInDriver(driverMap); | 
 |  |  |          if (error != null) { | 
 |  |  |             throw new Exception(error); | 
 |  |  |          } else { | 
 |  |  |             error = this.hasErrorInPrefixedDataAvailable(driverMap, prefixedDataAvailableMap); | 
 |  |  |             if (error != null) { | 
 |  |  |                throw new Exception(error); | 
 |  |  |             } else { | 
 |  |  |                error = this.hasErrorInOnLine(driverMap, onLineMap); | 
 |  |  |                if (error != null) { | 
 |  |  |                   throw new Exception(error); | 
 |  |  |                } | 
 |  |  |             } | 
 |  |  |          } | 
 |  |  |       } else { | 
 |  |  |          throw new Exception("严重错误, 扫描协议相关注解所得到类型集合为空,扫描根路径是" + scanRootPackage); | 
 |  |  |       } | 
 |  |  |    } | 
 |  |  |  | 
 |  |  |    /** | 
 |  |  |     * 检查优先级重复 | 
 |  |  |     * @param priority 优先级 | 
 |  |  |     * @return 结果 | 
 |  |  |     */ | 
 |  |  |    private boolean isRepeatPrefixedDataAvailablePriority(int priority, HashMap<String, AnnotationPrefixedDataAvailableVo> prefixedDataAvailableMap){ | 
 |  |  |       Collection<AnnotationPrefixedDataAvailableVo> col = prefixedDataAvailableMap.values();  | 
 |  |  |       Collection<AnnotationPrefixedDataAvailableVo> col = prefixedDataAvailableMap.values(); | 
 |  |  |       for(AnnotationPrefixedDataAvailableVo vo : col){ | 
 |  |  |          if(vo.priority == priority){ | 
 |  |  |             return true ; | 
 |  |  | 
 |  |  |     * @return 结果 | 
 |  |  |     */ | 
 |  |  |    private boolean isRepeatOnLinePriority(int priority, HashMap<String, AnnotationOnLineVo> onLineMap){ | 
 |  |  |       Collection<AnnotationOnLineVo> col = onLineMap.values();  | 
 |  |  |       Collection<AnnotationOnLineVo> col = onLineMap.values(); | 
 |  |  |       for(AnnotationOnLineVo vo : col){ | 
 |  |  |          if(vo.priority == priority){ | 
 |  |  |             return true ; | 
 |  |  | 
 |  |  |       } | 
 |  |  |       return false ; | 
 |  |  |    } | 
 |  |  | 	 | 
 |  |  |  | 
 |  |  |    private String hasErrorInDriver(HashMap<String, AnnotationDriverVo> driverMap){ | 
 |  |  |       if(driverMap.size() == 0){ | 
 |  |  |          return "严重错误,未注解任何协议驱动" ; | 
 |  |  | 
 |  |  |       return null ; | 
 |  |  |    } | 
 |  |  |  | 
 |  |  |    private String hasErrorInPrefixedDataAvailable(HashMap<String, AnnotationDriverVo> driverMap,  | 
 |  |  |          HashMap<String, AnnotationPrefixedDataAvailableVo> prefixedDataAvailableMap){ | 
 |  |  |       Collection<AnnotationPrefixedDataAvailableVo> col = prefixedDataAvailableMap.values();  | 
 |  |  |    private String hasErrorInPrefixedDataAvailable(HashMap<String, AnnotationDriverVo> driverMap, | 
 |  |  |                                        HashMap<String, AnnotationPrefixedDataAvailableVo> prefixedDataAvailableMap){ | 
 |  |  |       Collection<AnnotationPrefixedDataAvailableVo> col = prefixedDataAvailableMap.values(); | 
 |  |  |       for(AnnotationPrefixedDataAvailableVo vo : col){ | 
 |  |  |          if(!driverMap.containsKey(vo.protocolName)){ | 
 |  |  |             return "严重错误,上行数据完整性检查所配驱动名称(" + vo.protocolName + ")在协议驱动中未配置" ; | 
 |  |  |          if(!driverMap.containsKey(vo.protocolName + vo.protocolVersion)){ | 
 |  |  |             return "严重错误,上行数据完整性检查所配驱动名称(" + (vo.protocolName + vo.protocolVersion) + ")在协议驱动中未配置" ; | 
 |  |  |          } | 
 |  |  |       } | 
 |  |  | 		 | 
 |  |  |  | 
 |  |  |       int[] prioritys = new int[prefixedDataAvailableMap.size()] ; | 
 |  |  |       int count = 0 ; | 
 |  |  |       col = prefixedDataAvailableMap.values();  | 
 |  |  |       col = prefixedDataAvailableMap.values(); | 
 |  |  |       for(AnnotationPrefixedDataAvailableVo vo : col){ | 
 |  |  |          prioritys[count++] = vo.priority ; | 
 |  |  |       } | 
 |  |  |       NumUtil.sort(prioritys, true) ; | 
 |  |  | 		 | 
 |  |  |  | 
 |  |  |       int firstPriority = prioritys[0] ; | 
 |  |  |       if(ProtocolConstant.firstPriority != firstPriority){ | 
 |  |  |          return "严重错误,上行数据完整性检查所配优先级必须从 " + ProtocolConstant.firstPriority + " 开始" ; | 
 |  |  | 
 |  |  |       } | 
 |  |  |       return null ; | 
 |  |  |    } | 
 |  |  | 	 | 
 |  |  |  | 
 |  |  |    private String hasErrorInOnLine(HashMap<String, AnnotationDriverVo> driverMap, | 
 |  |  |          HashMap<String, AnnotationOnLineVo> onLineMap){ | 
 |  |  |       Collection<AnnotationOnLineVo> col = onLineMap.values();  | 
 |  |  |                            HashMap<String, AnnotationOnLineVo> onLineMap){ | 
 |  |  |       Collection<AnnotationOnLineVo> col = onLineMap.values(); | 
 |  |  |       for(AnnotationOnLineVo vo : col){ | 
 |  |  |          if(!driverMap.containsKey(vo.protocolName)){ | 
 |  |  |             return "严重错误,上线数据分析所配驱动名称(" + vo.protocolName + ")在协议驱动中未配置" ; | 
 |  |  |          if(!driverMap.containsKey(vo.protocolName + vo.protocolVersion)){ | 
 |  |  |             return "严重错误,上线数据分析所配驱动名称(" + (vo.protocolName + vo.protocolVersion) + ")在协议驱动中未配置" ; | 
 |  |  |          } | 
 |  |  |       } | 
 |  |  | 		 | 
 |  |  |  | 
 |  |  |       int[] prioritys = new int[onLineMap.size()] ; | 
 |  |  |       int count = 0 ; | 
 |  |  |       col = onLineMap.values();  | 
 |  |  |       col = onLineMap.values(); | 
 |  |  |       for(AnnotationOnLineVo vo : col){ | 
 |  |  |          prioritys[count++] = vo.priority ; | 
 |  |  |       } | 
 |  |  |       NumUtil.sort(prioritys, true) ; | 
 |  |  | 		 | 
 |  |  |  | 
 |  |  |       int firstPriority = prioritys[0] ; | 
 |  |  |       if(ProtocolConstant.firstPriority != firstPriority){ | 
 |  |  |          return "严重错误,上线数据分析所配优先级必须从 " + ProtocolConstant.firstPriority + " 开始" ; |