All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.aspire.nm.component.common.keyword.KeyWordUtil Maven / Gradle / Ivy

/*
 * @(#)KeywordCharFinder.java
 * 
 * Create Version: 1.0.0
 * Author: James Liu
 * Create Date: 2014-03-03
 * 
 * Copyright (c) 2014 Aspire Information Technologies Ltd. All Right Reserved.
 */
package com.aspire.nm.component.common.keyword;


import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.aspire.nm.component.common.keyword.Strategy.LoadKeyWordStrategy;
import com.aspire.nm.component.common.keyword.Strategy.Impl.db.UpdateTimes;
import com.aspire.nm.component.commonUtil.log.ReleaseLogger;




/**
 * 关键字查找器。
 * 将所有关键字单词组装成单字树,遍历待查字符串的每个字,发现关键字树根有这个字开始检查。
 * 使用字符实现.
 * 
 * @version 1.0.0   2014-03-03
 * @author  James Liu
 */
public class KeyWordUtil extends Thread{
    
    private static Logger logger = Logger.getLogger(KeyWordUtil.class);
    private static Logger releaselogger = Logger.getLogger(ReleaseLogger.class);
    
    private static final int REFRESH_SEC = 60;

    private static String updateKeyWordTime;
    
    private static boolean stop = false;
    
    
    private LoadKeyWordStrategy loadKeyWordStrategy;

    public KeyWordUtil(LoadKeyWordStrategy loadKeyWordStrategy){
        this(loadKeyWordStrategy,true);
    }
    
    public KeyWordUtil(LoadKeyWordStrategy loadKeyWordStrategy,boolean availability){
        this.loadKeyWordStrategy = loadKeyWordStrategy;
        if(availability){
            init();
        }
    }
    private void init(){
        doRun();
        start();
    }
    
    
    public void run(){
        
        while(true){
            
            try {
                Thread.sleep(REFRESH_SEC * 1000);
            } catch (InterruptedException e) {}
            
            if(stop){
                break;
            }
            doRun();
            
            
        }
    }
    
    private void doRun(){
        
        UpdateTimes updateTimes = loadKeyWordStrategy.getUpdateTimes();
        if(updateTimes == null) return;
        
        if(updateKeyWordTime == null || !updateTimes.getUpdateKeyWordTime().equals(updateKeyWordTime)){
            
            updateKeyWordTime = updateTimes.getUpdateKeyWordTime();
            
            logger.debug("reLoadKeyWords...");
            
            WriteLock writeLock = lock.writeLock();
            try {
                writeLock.lock();
                root = new HashMap();
                for(String keyword : loadKeyWordStrategy.loadKeyWords()){
                    parseWord(keyword);
                }
            } catch(Exception e) {
                logger.error("[更新关键字失败]" + root.size(), e);
                e.printStackTrace();
            } finally {
                writeLock.unlock();
            }
            
            logger.debug("reLoadKeyWords Done , size = " + root.size());
        }
        
    }


    
    

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private Map root = new HashMap();
    
    private void parseWord(String word) {
        if ((word == null) || (word.length() == 0)) return;
        this.parseWord(this.getCharArray(word));
    }
    private void parseWord(Character[] word) {
        
        if ((word == null) || (word.length == 0)) return;
        
        Character parentChar = null;
        Map parentNode = null;
        for (int i = 0; i < word.length; i++) {
            parentNode = this.parseChar(parentChar, parentNode, word[i], (i == (word.length - 1)) ? true : false);
            parentChar = word[i];
            if (parentNode == null) break;
        }
    }
    /*
     * 解析每个字符.
     * 当碰到字符树的分支结束符时,提前结束单词解析。分支结束符的节点是Object,不是Map。
     * 比如:“ab”和“abcd”,当解析“abcd”的“c”时,发现已经有“ab”了,则“abcd”将剔除,不作为关键字。
     * 同样:“abcd”和“ab”,当解析“ab”完成时,会清除掉所有“ab”后面的分支,则“abcd”将剔除,不作为关键字。
     * 
     * @param   prevChar        前一个字符
     * @param   prevNode        前一个节点
     * @param   curChar         当前解析的字符
     * @param   isEndChar       当前解析字符是否是单词最后一个字符
     * 
     * @return  当前字符节点,null为结束单词解析。
     */
    @SuppressWarnings("unchecked")
    private Map parseChar(Character prevChar, Map prevNode, 
                                             Character curChar, boolean isEndChar) {
        
        Map curNode = this.root;
        if (prevChar != null) {
            Object current = prevNode.get(prevChar);
            if (current == null) {
                curNode = null;
            } else if (current instanceof Map) {
                curNode = (Map) current;
            } else {
                return null;
            }
        }
        
        if (curNode == null) {
            curNode = new HashMap();
            if (isEndChar) {
                curNode.put(curChar, new Object());
            } else {
                curNode.put(curChar, null);
            }
            prevNode.put(prevChar, curNode);
        } else {
            Object nextNode = curNode.get(curChar);
            if ((nextNode != null) && !(nextNode instanceof Map)) return null;
            
            if (nextNode == null) {
                if (isEndChar) {
                    curNode.put(curChar, new Object());
                } else {
                    curNode.put(curChar, null);
                }
            } else if (isEndChar) {
                curNode.put(curChar, new Object());
            }
        }
        
        return (isEndChar) ? null : curNode;
    }
    /*
     * 获得字符串字符数组。
     * 
     * @param   s               要转换的字符串
     * 
     * @return  字符串字符数组。如果s是null,则返回null;如果s是空字符串,则返回长度为零的数组。
     */
    private Character[] getCharArray(String s) {
        
        if (s == null) return null;
        
        if (s.length() == 0) return new Character[0];
        
        Character[] result = new Character[s.length()];
        for (int i = 0; i < s.length(); i++) result[i] = s.charAt(i);
        
        return result;
    }
    
    
    
    /*
     * 匹配关键字。
     * 
     * @param   node            要匹配查找的节点
     * @param   chars           字符串字符数组
     * @param   pos             当前要匹配的字符
     * 
     * @return  匹配上的关键字,没有匹配上返回null。
     */
    @SuppressWarnings("unchecked")
    private String match(Map node, Character[] chars, int pos) {
        
        if (pos == chars.length) return null;
        
        Object findResult = node.get(chars[pos]);
        if (findResult == null) {
            return null;
        } else if (findResult instanceof Map) {
            String keyword = this.match((Map) findResult, chars, pos + 1);
            return (keyword == null) ? null : chars[pos].toString() + keyword;
        } else {
            return chars[pos].toString();
        }
    }
    
    
    
    
    
    
    
    
    
    /**
     * 检查字符串是否包含关键字。
     * 
     * @param   s               要检查的字符串
     * 
     * @return  查找结果对象。对象中index是第一个找到的关键字的字符位置,-1为没有找到;keyword是找到的关键字。
     */
    public Result check(String s) {
        if (StringUtils.isEmpty(s)) return new Result(-1, null);
        
        int index = -1;
        String keyword = null;
        
        Character[] chars = this.getCharArray(s);
        ReadLock readLock = lock.readLock();
        try {
            readLock.lock();
            for (int i = 0; i < chars.length; i++) {
                keyword = this.match(this.root, chars, i);
                if (keyword != null) {
                    index = i;
                    break;
                }
            }
        } finally {
            if(readLock != null) readLock.unlock();
        }
        
        return (index == -1) ? new Result(-1, null) : new Result(index, keyword);
    }
    
    

    /**
     * 释放资源(停止线程)
     */
    public void release(){
        stop = true;
        interrupt();
        releaselogger.debug("release KeyWordUtil SUCESS");
    }
    
    
    
    /**
     * 关键字查找器返回的结果类。
     * 类中包含两个字段:index和keyword。
     * index是被查找字符串中第一个和关键字匹配的字符的位置,从0开始。
     * keyword是被查找字符串匹配上的关键字。
     * 
     * @version 1.0.0   2014-03-03
     * @author  James Liu
     */
    public static class Result {
        
        private int index;
        private String keyword;
        
        
        private Result(int index, String keyword) {
            
            this.index = index;
            this.keyword = keyword;
        }
        
        public int getIndex() {
            
            return index;
        }
        
        public String getKeyword() {
            
            return keyword;
        }
        
        @Override
        public String toString() {
            
            StringBuilder builder = new StringBuilder();
            builder.append("Result [index=").append(this.index).append(", keyword=").append(this.keyword).append("]");
            
            return builder.toString();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy