001package net.gdface.sdk;
002
003import java.util.Collections;
004import java.util.HashMap;
005import java.util.Iterator;
006import java.util.LinkedHashMap;
007import java.util.LinkedList;
008import java.util.List;
009import java.util.Map;
010import java.util.ServiceLoader;
011
012import net.gdface.utils.Judge;
013import static net.gdface.utils.SimpleLog.log;
014import static net.gdface.sdk.CapacityFieldConstant.C_SDK_VERSION;
015
016/**
017 * FaceApi应用上下文SPI加载工具类
018 * @author guyadong
019 *
020 */
021public class ContextLoader {
022        private static final Map<GlobalContextField, Object> globalContext = new HashMap<>();
023        private final LinkedHashMap<String, FaceApiContext> classMap = new LinkedHashMap<>();
024        private final LinkedHashMap<String, FaceApiContext> versionMap= new LinkedHashMap<>();
025        /** 所有找到的 FaceApi 上下文实例 */
026        public final List<FaceApiContext> CONTEXTS ;
027        // 延迟加载的单实例
028        private static class Singleton{
029                static final ContextLoader INSTANCE = new ContextLoader();
030        }
031        /**
032         * 全局上下文字段定义
033         */
034        public static enum GlobalContextField{
035                /** 并发限制 [int]*/CONCURRENCY,
036                /** 人脸检测倾向, [boolean] true:多人脸检测,false:用于帧相关单人脸检测 */MULIT_FACE_DETECT_TREND
037        }
038        /**
039         * 上下文字段定义
040         */
041        public static enum ContextField{
042                /** {@link FaceApi}实例 */INSTANCE,
043                /** 授权管理器(LicenceManager)实例 */LICENCE_MANAGER;
044                @SuppressWarnings("unchecked")
045                public <T>T from(FaceApiContext context){
046                        return (T) context.getContext().get(this);
047                }
048        }
049        public  static final ContextLoader getInstance(){
050                return Singleton.INSTANCE;
051        }
052        private ContextLoader() {
053                // SPI 加载所有 FaceApi 上下文实例
054                ServiceLoader<FaceApiContext> providers = ServiceLoader.load(FaceApiContext.class);
055                LinkedList<FaceApiContext> list = new LinkedList<>();
056                for(Iterator<FaceApiContext> itor = providers.iterator();itor.hasNext();){
057                        FaceApiContext context = itor.next();
058                        list.add(context);
059                        FaceApi instance = ContextLoader.ContextField.INSTANCE.<FaceApi>from(context);
060                        if(instance == null){
061                                // 跳过接口实例为空的并报错
062                                log("ERROR:FaceApi instance of {} is null",context.getClass().getName());
063                                continue;
064                        }
065                        classMap.put(instance.getClass().getName(), context);
066                        String sdkVersion = instance.sdkCapacity().get(C_SDK_VERSION);
067                        if(!Judge.isEmpty(sdkVersion)){
068                                versionMap.put(sdkVersion, context);
069                        }
070                }
071                CONTEXTS =  Collections.unmodifiableList(list);
072        }
073        /**
074         * 返回找到的第一个FaceApi应用上下文实例
075         * @return FaceApi应用上下文实例,找不到返回{@code null}
076         */
077        public FaceApiContext getContext(){
078                try {
079                        return CONTEXTS.get(0);
080                } catch (IndexOutOfBoundsException e) {
081                        return null;
082                }
083        }
084        /**
085         * 返回找到的第一个FaceApi应用上下文实例
086         * @return FaceApi应用上下文实例
087         * @throws IllegalStateException 找不到FaceApi应用上下文实例
088         */
089        public FaceApiContext getContextChecked(){
090                try {
091                        return CONTEXTS.get(0);
092                } catch (IndexOutOfBoundsException e) {
093                        throw new IllegalStateException("NOT FOUND any " + FaceApiContext.class.getSimpleName() + " instance");
094                }
095        }
096        /**
097         * 返回包含指定FaceApi实例类名的应用上下文
098         * @param className FaceApi实例类名(全名)
099         * @return FaceApi应用上下文实例,找不到返回{@code null}
100         */
101        public FaceApiContext getContextByInstnaceClass(String className){
102                return classMap.get(className);
103        }
104        /**
105         * 返回包含指定FaceApi实例类名的应用上下文
106         * @param className FaceApi实例类名(全名)
107         * @return FaceApi应用上下文实例
108         * @throws IllegalArgumentException 找不到指定的上下文实例
109         */
110        public FaceApiContext getContextByInstnaceClassChecked(String className){
111                FaceApiContext context = classMap.get(className);
112                if(context == null){
113                        throw new IllegalArgumentException("INVALID instance class name: " + className);
114                }
115                return context;
116        }
117        /**
118         * 返回支持指定SDK版本号的应用上下文
119         * @param className SDK版本号
120         * @return FaceApi应用上下文实例,找不到返回{@code null}
121         */
122        public FaceApiContext getContextBySdkVersion(String sdkVersion){
123                return versionMap.get(sdkVersion);
124        }
125        /**
126         * 返回支持指定SDK版本号的应用上下文
127         * @param className SDK版本号
128         * @return FaceApi应用上下文实例,找不到返回{@code null}
129         * @throws IllegalArgumentException 找不到指定的上下文实例
130         */
131        public FaceApiContext getContextBySdkVersionChecked(String sdkVersion){
132                FaceApiContext context = versionMap.get(sdkVersion);
133                if(context == null){
134                        throw new IllegalArgumentException("INVALID sdkVersion: " + sdkVersion);
135                }
136                return context;
137        }
138        /**
139         * 设置全局上下文,用于应用层在SDK初始化前指定初始化参数<br>
140         * @param field
141         * @param value
142         */
143        public static void setGlobalContext(GlobalContextField field,Object value){
144                if(field != null && value != null){
145                        globalContext.put(field, value);
146                }
147        }
148        @SuppressWarnings("unchecked")
149        public static <T>T getGlobalcontext(GlobalContextField field) {
150                if(field != null ){
151                        return (T) globalContext.get(field);
152                }
153                return null;
154        }
155}