| package com.dy.common.mw.protocol; | 
|   | 
| import java.util.Collection; | 
| import java.util.HashMap; | 
| import java.util.Set; | 
|   | 
| import com.dy.common.util.NumUtil; | 
| import org.apache.logging.log4j.LogManager; | 
| import org.apache.logging.log4j.Logger; | 
| import org.reflections.Reflections; | 
|   | 
| /** | 
|  * 扫描: | 
|  *   协议驱动类 | 
|  *   上行数据完整性检查类(断包粘包检查) | 
|  *   上线数据(连接后第一包数据)处理类(识别协议及终端地址) | 
|  * @author Administrator | 
|  * | 
|  */ | 
| @SuppressWarnings("unused") | 
| public class AnnotationScan { | 
|   | 
|     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 AnnotationScan | 
|      * @throws Exception 异常 | 
|      */ | 
|     public static AnnotationScan getIntance()throws Exception{ | 
|         if(instance == null){ | 
|             instance = new AnnotationScan() ; | 
|             instance.scanEndpointAnnotations(); | 
|         } | 
|         return instance ; | 
|     } | 
|   | 
|     /** | 
|      * 扫描出注解的类 | 
|      * @throws ClassNotFoundException 异常 | 
|      * @throws Exception 异常 | 
|      */ | 
|     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; | 
|             int priority; | 
|             int onLineDataMinLength; | 
|             int headMinLength; | 
|   | 
|             HashMap<String, AnnotationDriverVo> driverMap = ProtocolCache.getDriverMap(); | 
|             HashMap<String, AnnotationPrefixedDataAvailableVo> prefixedDataAvailableMap = ProtocolCache.getPrefixedDataAvailableMap(); | 
|             HashMap<String, AnnotationOnLineVo> onLineMap = ProtocolCache.getOnLineMap(); | 
|   | 
|             for (Class<?> clazz : driverClasses) { | 
|                 AnnotationDriver ann = clazz.getAnnotation(AnnotationDriver.class); | 
|                 if (ann != null) { | 
|                     if (ann.enable()) { | 
|                         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("严重错误,上行数据完整性检查所配协议驱动注解值为空字符串"); | 
|                         } | 
|   | 
|                         priority = ann.priority(); | 
|                         if (priority == 0) { | 
|                             throw new Exception("严重错误, 上行数据完整性检查所配优先级注解不能为0"); | 
|                         } | 
|                         if (isRepeatPrefixedDataAvailablePriority(priority, prefixedDataAvailableMap)) { | 
|                             throw new Exception("严重错误, 上行数据完整性检查所配优先级注解(priority)数值" + priority + "重复"); | 
|                         } | 
|   | 
|                         onLineDataMinLength = ann.onLineDataMinLength(); | 
|                                     /*气象协议为0 | 
|                                     if(onLineDataMinLength == 0){ | 
|                                         throw new Exception("严重错误, 上行数据完整性检查所配上线数据最小长度注解不能为0") ; | 
|                                     } | 
|                                     */ | 
|                         headMinLength = ann.headMinLength(); | 
|                                     /*气象协议为0 | 
|                                     if(headMinLength == 0){ | 
|                                         throw new Exception("严重错误, 上行数据完整性检查所配上报数据的头部最小长度注解不能为0") ; | 
|                                     } | 
|                                     */ | 
|                         prefixedDataAvailableMap.put(protocolName, new AnnotationPrefixedDataAvailableVo(clazz, protocolName, priority, onLineDataMinLength, headMinLength, ProtocolConstant.errorMaxLength)); | 
|                     } | 
|                 } | 
|             } | 
|   | 
|             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("严重错误,上线数据分析所配协议驱动注解值为空字符串"); | 
|                         } | 
|   | 
|                         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)); | 
|                     } | 
|                 } | 
|             } | 
|   | 
|             //进行验证 | 
|             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(); | 
|         for(AnnotationPrefixedDataAvailableVo vo : col){ | 
|             if(vo.priority == priority){ | 
|                 return true ; | 
|             } | 
|         } | 
|         return false ; | 
|     } | 
|     /** | 
|      * 检查优先级重复 | 
|      * @param priority 优先级 | 
|      * @return 结果 | 
|      */ | 
|     private boolean isRepeatOnLinePriority(int priority, HashMap<String, AnnotationOnLineVo> onLineMap){ | 
|         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(); | 
|         for(AnnotationPrefixedDataAvailableVo vo : col){ | 
|             if(!driverMap.containsKey(vo.protocolName)){ | 
|                 return "严重错误,上行数据完整性检查所配驱动名称(" + vo.protocolName + ")在协议驱动中未配置" ; | 
|             } | 
|         } | 
|   | 
|         int[] prioritys = new int[prefixedDataAvailableMap.size()] ; | 
|         int count = 0 ; | 
|         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 + " 开始" ; | 
|         } | 
|         int  prePriority = prioritys[0] ; | 
|         int  nextPriority; | 
|         if(prioritys.length > 1){ | 
|             for(int i = 1 ; i < prioritys.length; i++){ | 
|                 nextPriority = prioritys[i] ; | 
|                 if(nextPriority - prePriority != 1){ | 
|                     return "严重错误,上行数据完整性检查所配各个优先级必须相差1" ; | 
|                 }else{ | 
|                     prePriority = nextPriority ; | 
|                 } | 
|             } | 
|         } | 
|         return null ; | 
|     } | 
|   | 
|     private String hasErrorInOnLine(HashMap<String, AnnotationDriverVo> driverMap, | 
|                                     HashMap<String, AnnotationOnLineVo> onLineMap){ | 
|         Collection<AnnotationOnLineVo> col = onLineMap.values(); | 
|         for(AnnotationOnLineVo vo : col){ | 
|             if(!driverMap.containsKey(vo.protocolName)){ | 
|                 return "严重错误,上线数据分析所配驱动名称(" + vo.protocolName + ")在协议驱动中未配置" ; | 
|             } | 
|         } | 
|   | 
|         int[] prioritys = new int[onLineMap.size()] ; | 
|         int count = 0 ; | 
|         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 + " 开始" ; | 
|         } | 
|         int  prePriority = prioritys[0] ; | 
|         int  nextPriority; | 
|         if(prioritys.length > 1){ | 
|             for(int i = 1 ; i < prioritys.length; i++){ | 
|                 nextPriority = prioritys[i] ; | 
|                 if(nextPriority - prePriority != 1){ | 
|                     return "严重错误,上线数据分析所配各个优先级必须相差1" ; | 
|                 }else{ | 
|                     prePriority = nextPriority ; | 
|                 } | 
|             } | 
|         } | 
|         return null ; | 
|     } | 
| } |