001// ______________________________________________________
002// Generated by codegen - https://gitee.com/l0km/codegen 
003// template: decorator/spring.controller.class.vm
004// ______________________________________________________
005/**
006 * decorator pattern 装饰者模式代理{@link FeatureSe}接口<br>
007 * 将{@link FeatureSe}实例封装为一个spring controler<br>
008 * 计算机生成代码(generated by automated tools DecoratorGenerator @author guyadong)<br>
009 * @author guyadong
010 *
011 */
012package net.gdface.sdk.fse;
013import java.util.ServiceLoader;
014import java.io.PrintWriter;
015import java.io.StringWriter;
016import java.util.Iterator;
017import java.util.Objects;
018
019import org.slf4j.Logger;
020import org.slf4j.LoggerFactory;
021import org.springframework.web.bind.annotation.*;
022import io.swagger.annotations.*;
023
024/**
025 * 特征码内存搜索引擎(feature search engine)接口<br>
026 * 提供高速的人脸特征相似度比对搜索/排序,支持多线程并行搜索,适用于百万级以上人脸库的快速搜索。<br>
027 * 1.使用 {@link #addFeature(byte[], byte[], String)}方法将特征添加到搜索引擎<br>
028 * 2.使用 {@link #searchCode(byte[], double, int)}在内存中搜索与指定特征相似的的特征返回搜索结果
029 * @author guyadong
030 */
031@RestController
032@Api(value="FeatureSe",tags={"FeatureSe Controller"})
033public class FeatureSeSpringController {
034    private static final Logger logger = LoggerFactory.getLogger(FeatureSeSpringController.class);
035    private static InstanceSupplier instanceSupplier = getInstanceSupplier();
036    private final ResponseFactory responseFactory = loadResponseFactory();
037    /**
038     * SPI(Service Provider Interface)机制加载 {@link InstanceSupplier}实例,没有找到则返回{@code null},
039     * 返回{@link InstanceSupplier}提供的{@link FeatureSe}实例
040     * @return 返回{@link FeatureSe}实例
041     */
042    private static final InstanceSupplier getInstanceSupplier() {
043            /* SPI(Service Provider Interface)机制加载 {@link InstanceSupplier}实例,没有找到则抛出异常 */
044            ServiceLoader<InstanceSupplier> providers = ServiceLoader.load(InstanceSupplier.class);
045            Iterator<InstanceSupplier> itor = providers.iterator();
046            return itor.hasNext() ? itor.next() : null;
047    }
048    /**
049         * @param instanceSupplier 要设置的 instanceSupplier
050         */
051        public static void setInstanceSupplier(InstanceSupplier instanceSupplier) {
052                FeatureSeSpringController.instanceSupplier = instanceSupplier;
053        }
054    /**
055     * SPI(Service Provider Interface)加载{@link ResponseFactory}接口实例,
056     * 没有找到则返回{@link DefaultResponseFactory}实例
057     * @return 返回{@link ResponseFactory}实例
058     */
059    private static final ResponseFactory loadResponseFactory() {
060            ServiceLoader<ResponseFactory> providers = ServiceLoader.load(ResponseFactory.class);
061            Iterator<ResponseFactory> itor = providers.iterator();
062            return itor.hasNext() ? itor.next() : new DefaultResponseFactory();
063    }  
064    public FeatureSeSpringController() {
065    }
066
067    /**
068     * @return 返回被装饰的{@link FeatureSe}实例
069     */
070    protected FeatureSe delegate() {
071        return Objects.requireNonNull(
072                instanceSupplier == null ? null : instanceSupplier.instanceOfFeatureSe(),
073                "FeatureSe  instance is null"    );
074    }
075    // port-1
076    /**
077     * 添加一条特征码到内存表<br>
078     * @param featureId 特征码ID(MD5校验码),为null时,native library会自动计算MD5作为特征码ID
079     * @param feature 特征码字节数组,为{@code null}时返回false
080     * @param imgMD5 特征所属图的MD5(32字节HEX字符串),可为null
081     * @return 添加成功返回true, 否则返回false
082     */
083    @ResponseBody
084    @RequestMapping(value = "/FeatureSe/addFeatureToFse", method = RequestMethod.POST)
085    @ApiOperation(value = "添加一条特征码到内存表<br>", notes = "添加一条特征码到内存表<br>",httpMethod="POST")
086    public Response addFeature( @RequestBody AddFeatureToFseArgs args) 
087    {
088            Response response = responseFactory.newFeatureSeResponse();
089            try{
090                response.onComplete(delegate().addFeature(args.featureId,args.feature,args.imgMD5));
091            }
092            catch(Exception e){
093                logger.error(e.getMessage(),e);
094                response.onError(e);
095            }
096            return response;
097    }
098    // port-2
099    /**
100     * 添加一条特征码到内存表<br>
101     * @param featureId 特征码ID(MD5校验码),为null时,native library会自动计算MD5作为特征码ID
102     * @param feature 特征码字节数组,为{@code null}时返回false
103     * @param appid 应用id,由调用者定义,可为null
104     * @return 添加成功返回true, 否则返回false
105     */
106    @ResponseBody
107    @RequestMapping(value = "/FeatureSe/addFeatureToFseWithAppId", method = RequestMethod.POST)
108    @ApiOperation(value = "添加一条特征码到内存表<br>", notes = "添加一条特征码到内存表<br>",httpMethod="POST")
109    public Response addFeature( @RequestBody AddFeatureToFseWithAppIdArgs args) 
110    {
111            Response response = responseFactory.newFeatureSeResponse();
112            try{
113                response.onComplete(delegate().addFeature(args.featureId,args.feature,args.appid));
114            }
115            catch(Exception e){
116                logger.error(e.getMessage(),e);
117                response.onError(e);
118            }
119            return response;
120    }
121    // port-3
122    /**
123     * 删除内存表中所有特征数据
124     */
125    @ResponseBody
126    @RequestMapping(value = "/FeatureSe/clearAllOfFse", method = RequestMethod.POST)
127    @ApiOperation(value = "删除内存表中所有特征数据", notes = "删除内存表中所有特征数据",httpMethod="POST")
128    public Response clearAll() 
129    {
130            Response response = responseFactory.newFeatureSeResponse();
131            try{
132                delegate().clearAll();
133                response.onComplete();
134            }
135            catch(Exception e){
136                logger.error(e.getMessage(),e);
137                response.onError(e);
138            }
139            return response;
140    }
141    // port-4
142    /**
143     * 根据特征码ID在表中查找指定的记录
144     * @param featureId 特征码ID,MD5校验码(16 bytes)
145     * @return 返回指定的特征记录,没有找到则返回{@code null},{@code featureId}为{@code null}或空返回{@code null}
146     */
147    @ResponseBody
148    @RequestMapping(value = "/FeatureSe/getFeatureFromFse", method = RequestMethod.POST)
149    @ApiOperation(value = "根据特征码ID在表中查找指定的记录", notes = "根据特征码ID在表中查找指定的记录",httpMethod="POST")
150    public Response getFeature( @RequestBody GetFeatureFromFseArgs args) 
151    {
152            Response response = responseFactory.newFeatureSeResponse();
153            try{
154                response.onComplete(delegate().getFeature(args.featureId));
155            }
156            catch(Exception e){
157                logger.error(e.getMessage(),e);
158                response.onError(e);
159            }
160            return response;
161    }
162    // port-5
163    /**
164     * 根据特征码ID在表中查找指定的记录
165     * @param featureId 特征码ID,MD5校验码(32字节HEX字符串)
166     * @return 返回指定的特征记录,没有找到则返回{@code null},{@code featureId}为{@code null}或空返回{@code null}
167     */
168    @ResponseBody
169    @RequestMapping(value = "/FeatureSe/getFeatureByHexFromFse", method = RequestMethod.POST)
170    @ApiOperation(value = "根据特征码ID在表中查找指定的记录", notes = "根据特征码ID在表中查找指定的记录",httpMethod="POST")
171    public Response getFeatureByHex( @RequestBody GetFeatureByHexFromFseArgs args) 
172    {
173            Response response = responseFactory.newFeatureSeResponse();
174            try{
175                response.onComplete(delegate().getFeatureByHex(args.featureId));
176            }
177            catch(Exception e){
178                logger.error(e.getMessage(),e);
179                response.onError(e);
180            }
181            return response;
182    }
183    // port-6
184    /**
185     * 根据特征码ID中表中删除指定的记录
186     * @param featureId  特征码ID,MD5校验码(16 bytes)
187     * @return 成功删除则返回true,否则返回false
188     */
189    @ResponseBody
190    @RequestMapping(value = "/FeatureSe/removeFeatureFromFse", method = RequestMethod.POST)
191    @ApiOperation(value = "根据特征码ID中表中删除指定的记录", notes = "根据特征码ID中表中删除指定的记录",httpMethod="POST")
192    public Response removeFeature( @RequestBody RemoveFeatureFromFseArgs args) 
193    {
194            Response response = responseFactory.newFeatureSeResponse();
195            try{
196                response.onComplete(delegate().removeFeature(args.featureId));
197            }
198            catch(Exception e){
199                logger.error(e.getMessage(),e);
200                response.onError(e);
201            }
202            return response;
203    }
204    // port-7
205    /**
206     * 根据特征码ID中表中删除指定的记录
207     * @param featureId 特征码ID,MD5校验码(32字节HEX字符串)
208     * @return 成功删除则返回true,否则返回false
209     */
210    @ResponseBody
211    @RequestMapping(value = "/FeatureSe/removeFeatureByHexFromFse", method = RequestMethod.POST)
212    @ApiOperation(value = "根据特征码ID中表中删除指定的记录", notes = "根据特征码ID中表中删除指定的记录",httpMethod="POST")
213    public Response removeFeatureByHex( @RequestBody RemoveFeatureByHexFromFseArgs args) 
214    {
215            Response response = responseFactory.newFeatureSeResponse();
216            try{
217                response.onComplete(delegate().removeFeatureByHex(args.featureId));
218            }
219            catch(Exception e){
220                logger.error(e.getMessage(),e);
221                response.onError(e);
222            }
223            return response;
224    }
225    // port-8
226    /**
227     * 在内存表中根据比对相似度进行特征码搜索
228     * @param code 要比对的特征码
229     * @param sim 相似度阀值
230     * @param rows  最大返回的记录数
231     * @return 返回包含相似度(降序)的结果数组,如果没有查到匹配的记录则返回空数组
232     */
233    @ResponseBody
234    @RequestMapping(value = "/FeatureSe/searchCodeFromFse", method = RequestMethod.POST)
235    @ApiOperation(value = "在内存表中根据比对相似度进行特征码搜索", notes = "在内存表中根据比对相似度进行特征码搜索",httpMethod="POST")
236    public Response searchCode( @RequestBody SearchCodeFromFseArgs args) 
237    {
238            Response response = responseFactory.newFeatureSeResponse();
239            try{
240                response.onComplete(delegate().searchCode(args.code,args.sim,args.rows));
241            }
242            catch(Exception e){
243                logger.error(e.getMessage(),e);
244                response.onError(e);
245            }
246            return response;
247    }
248    // port-9
249    /**
250     * @return 内存表中元素个数
251     */
252    @ResponseBody
253    @RequestMapping(value = "/FeatureSe/sizeOfFse", method = RequestMethod.POST)
254    @ApiOperation(value = "", notes = "",httpMethod="POST")
255    public Response size() 
256    {
257            Response response = responseFactory.newFeatureSeResponse();
258            try{
259                response.onComplete(delegate().size());
260            }
261            catch(Exception e){
262                logger.error(e.getMessage(),e);
263                response.onError(e);
264            }
265            return response;
266    }
267    /**
268     * argClass-1<br>
269     * wrap arguments for method {@link #addFeature(AddFeatureToFseArgs)}
270     */
271    public static class AddFeatureToFseArgs{
272        @ApiModelProperty(value ="特征码ID(MD5校验码),为null时,native library会自动计算MD5作为特征码ID" ,required=true ,dataType="byte[]")
273        public byte[] featureId;
274        @ApiModelProperty(value ="特征码字节数组,为{@code null}时返回false" ,required=true ,dataType="byte[]")
275        public byte[] feature;
276        @ApiModelProperty(value ="特征所属图的MD5(32字节HEX字符串),可为null" ,required=true ,dataType="String")
277        public String imgMD5;
278    }
279    /**
280     * argClass-2<br>
281     * wrap arguments for method {@link #addFeature(AddFeatureToFseWithAppIdArgs)}
282     */
283    public static class AddFeatureToFseWithAppIdArgs{
284        @ApiModelProperty(value ="特征码ID(MD5校验码),为null时,native library会自动计算MD5作为特征码ID" ,required=true ,dataType="byte[]")
285        public byte[] featureId;
286        @ApiModelProperty(value ="特征码字节数组,为{@code null}时返回false" ,required=true ,dataType="byte[]")
287        public byte[] feature;
288        @ApiModelProperty(value ="应用id,由调用者定义,可为null" ,required=true ,dataType="long")
289        public long appid;
290    }
291    /**
292     * argClass-4<br>
293     * wrap arguments for method {@link #getFeature(GetFeatureFromFseArgs)}
294     */
295    public static class GetFeatureFromFseArgs{
296        @ApiModelProperty(value ="特征码ID,MD5校验码(16 bytes)" ,required=true ,dataType="byte[]")
297        public byte[] featureId;
298    }
299    /**
300     * argClass-5<br>
301     * wrap arguments for method {@link #getFeatureByHex(GetFeatureByHexFromFseArgs)}
302     */
303    public static class GetFeatureByHexFromFseArgs{
304        @ApiModelProperty(value ="特征码ID,MD5校验码(32字节HEX字符串)" ,required=true ,dataType="String")
305        public String featureId;
306    }
307    /**
308     * argClass-6<br>
309     * wrap arguments for method {@link #removeFeature(RemoveFeatureFromFseArgs)}
310     */
311    public static class RemoveFeatureFromFseArgs{
312        @ApiModelProperty(value ="特征码ID,MD5校验码(16 bytes)" ,required=true ,dataType="byte[]")
313        public byte[] featureId;
314    }
315    /**
316     * argClass-7<br>
317     * wrap arguments for method {@link #removeFeatureByHex(RemoveFeatureByHexFromFseArgs)}
318     */
319    public static class RemoveFeatureByHexFromFseArgs{
320        @ApiModelProperty(value ="特征码ID,MD5校验码(32字节HEX字符串)" ,required=true ,dataType="String")
321        public String featureId;
322    }
323    /**
324     * argClass-8<br>
325     * wrap arguments for method {@link #searchCode(SearchCodeFromFseArgs)}
326     */
327    public static class SearchCodeFromFseArgs{
328        @ApiModelProperty(value ="要比对的特征码" ,required=true ,dataType="byte[]")
329        public byte[] code;
330        @ApiModelProperty(value ="相似度阀值" ,required=true ,dataType="double")
331        public double sim;
332        @ApiModelProperty(value ="最大返回的记录数" ,required=true ,dataType="int")
333        public int rows;
334    }
335    /**
336     * 获取{@link FeatureSe}实例的接口,
337     * 用于应用层SPI方式提供{@link FeatureSe}实例
338     * @author guyadong
339     *
340     */
341    public static interface InstanceSupplier{
342        FeatureSe instanceOfFeatureSe();
343    }
344    /**
345     * web响应数据接口
346     * @author guyadong
347     *
348     */
349    public static interface Response{
350        /**
351         * 接口方法调用成功
352         * @param result 调用返回值
353         */
354        void onComplete(Object result);
355        /**
356         * 接口方法调用成功,调用方法返回类型为void
357         */
358        void onComplete();        
359        /**
360         * 接口方法调用抛出异常
361         * @param e 异常
362         */
363        void onError(Exception e);
364    }
365    /**
366     * 获取{@link Response}接口实例的工厂类接口
367     * @author guyadong
368     *
369     */
370    public static interface ResponseFactory{
371        /**
372         * @return 返回新的{@link Response}接口实例
373         */
374        Response newFeatureSeResponse();
375    }
376    /**
377     * {@link Response}默认实现
378     * @author guyadong
379     *
380     */
381    public static class DefaultResponse implements Response{
382        private static boolean outStrackTrace = false;
383        private boolean success;
384        /** RPC调用的返回值 */
385        private Object result;
386        /** 异常信息 */
387        private String errorMessage;
388        /** 异常堆栈信息 */
389        private String stackTrace;
390        @Override
391        public void onComplete(Object result) {
392            this.success = true;
393            this.result = result;
394        }
395        @Override
396        public void onComplete() {
397            onComplete(null);
398        }
399        @Override
400        public void onError(Exception e) {
401            success = false;
402            errorMessage = e.getMessage();
403            if(errorMessage == null){
404                errorMessage = e.getClass().getSimpleName();
405            }
406            if(outStrackTrace){
407                StringWriter writer = new StringWriter();
408                e.printStackTrace(new PrintWriter(writer));
409                stackTrace = writer.toString();
410            }
411        }
412
413        public boolean isSuccess() {
414            return success;
415        }
416
417        public void setSuccess(boolean success) {
418            this.success = success;
419        }
420
421        public Object getResult() {
422            return result;
423        }
424
425        public void setResult(Object result) {
426            this.result = result;
427        }
428
429        public String getErrorMessage() {
430            return errorMessage;
431        }
432
433        public void setErrorMessage(String errorMessage) {
434            this.errorMessage = errorMessage;
435        }
436
437        public String getStackTrace() {
438            return stackTrace;
439        }
440
441        public void setStackTrace(String stackTrace) {
442            this.stackTrace = stackTrace;
443        }
444        
445        @Override
446        public String toString() {
447            StringBuilder builder = new StringBuilder();
448            builder.append("DefaultResponse [success=");
449            builder.append(success);
450            builder.append(", ");
451            if (result != null) {
452                builder.append("result=");
453                builder.append(result);
454                builder.append(", ");
455            }
456            if (errorMessage != null) {
457                builder.append("errorMessage=");
458                builder.append(errorMessage);
459                builder.append(", ");
460            }
461            if (stackTrace != null) {
462                builder.append("stackTrace=");
463                builder.append(stackTrace);
464            }
465            builder.append("]");
466            return builder.toString();
467        }
468        /**
469         * 开启输出堆栈信息(默认为不开启)<br>
470         * 开发时为了调试需要获取详细的异常堆栈信息可以开启
471         * @param outStrackTrace 要设置的 outStrackTrace
472         */
473        public static void enableStrackTrace() {
474            outStrackTrace = true;
475        }
476    }
477    /**
478     * {@link ResponseFactory}接口默认实现
479     * @author guyadong
480     *
481     */
482    public static class DefaultResponseFactory implements ResponseFactory{
483
484        @Override
485        public Response newFeatureSeResponse() {
486            return new DefaultResponse();
487        }
488    }
489    public static String DESCRIPTION = "特征码内存搜索引擎(feature search engine)接口<br>\n"
490+" 提供高速的人脸特征相似度比对搜索/排序,支持多线程并行搜索,适用于百万级以上人脸库的快速搜索。<br>\n"
491+" 1.使用 {@link #addFeature(byte[], byte[], String)}方法将特征添加到搜索引擎<br>\n"
492+" 2.使用 {@link #searchCode(byte[], double, int)}在内存中搜索与指定特征相似的的特征返回搜索结果";
493}