Heritrix 3.1.0 소스 해석(14)

39079 단어 Heritrix
BdbFrontier 대상의void schedule(Crawl URI caURI), Crawl URI next(), void finished(Crawl URI cURI) 방법을 분석하고 있습니다. 사실 아직 관련 환경이 분석되지 않았습니다. 사실 저는 좀 피곤합니다.
본고는 다음에 다중 루틴 환경에서Heritrix3을 분석한다.1.0 시스템에서 관련 객체 속성의 일관성을 유지하는 방법 및 관련 객체의 속성 값을 사용자 정의하여 구성하는 방법
Work Queue Frontier 클래스의void schedule(Crawl URI curi) 방법에서 볼 수 있습니다.
@Override

    public void schedule(CrawlURI curi) {

        sheetOverlaysManager.applyOverlaysTo(curi);

        try {

              KeyedProperties.loadOverridesFrom(curi);

            //KeyedProperties.withOverridesDo(ocontext, todo)

            if(curi.getClassKey()==null) {

                // remedial processing

                preparer.prepare(curi);

            }

            processScheduleIfUnique(curi);

        } finally {

            KeyedProperties.clearOverridesFrom(curi); 

        }

    }

Sheet Overlays Manager 대상과 Keyed Properties 대상과 관련이 있습니다. 우선 Keyed Properties 클래스는Concurrent HashMap 동기화 용기에서 계승됩니다.
이것은 맵 키 값이 맞는 형식으로 상하문에 대상을 저장하는 속성입니다. 이것은 우리가 필요로 하는 속성을 ThreadLocal 변수에 저장합니다. (루트 국부 변수)
 /**

     * ThreadLocal (contextual) collection of pushed override maps

     */

    static ThreadLocal<ArrayList<OverlayContext>> threadOverrides = 

        new ThreadLocal<ArrayList<OverlayContext>>() {

        protected ArrayList<OverlayContext> initialValue() {

            return new ArrayList<OverlayContext>();

        }

    };

ThreadLocal 대상에 저장된 대상은 ArrayList 유형의 대상입니다. 다음은 이 ArrayList 집합 대상과 관련된 추가 및 제거 방법입니다.
/**

     * Add an override map to the stack 

     * @param m Map to add

     */

    static public void pushOverrideContext(OverlayContext ocontext) {

        threadOverrides.get().add(ocontext);

    }

    

    /**

     * Remove last-added override map from the stack

     * @return Map removed

     */

    static public OverlayContext popOverridesContext() {

        // TODO maybe check that pop is as expected

        return threadOverrides.get().remove(threadOverrides.get().size()-1);

    }

    

    static public void clearAllOverrideContexts() {

        threadOverrides.get().clear(); 

    }

    

    static public void loadOverridesFrom(OverlayContext ocontext) {

        assert ocontext.haveOverlayNamesBeenSet();

        pushOverrideContext(ocontext);

    }

    

    static public boolean clearOverridesFrom(OverlayContext ocontext) {

        return threadOverrides.get().remove(ocontext);

    }

    

    static public void withOverridesDo(OverlayContext ocontext, Runnable todo) {

        try {

            loadOverridesFrom(ocontext);

            todo.run();

        } finally {

            clearOverridesFrom(ocontext); 

        }

    }



    public static boolean overridesActiveFrom(OverlayContext ocontext) {

        return threadOverrides.get().contains(ocontext);

    }

다음 방법은 키 값에 따라 속성 값을 가져오는 것입니다. (OverlayContext 인터페이스 리셋)
/** the alternate global property-paths leading to this map 

     * TODO: consider if deterministic ordered list is important */

    HashSet<String> externalPaths = new HashSet<String>(); 

    

    /**

     * Add a path by which the outside world can reach this map

     * @param path String path

     */

    public void addExternalPath(String path) {

        externalPaths.add(path);

    }



    /**

     * Get the given value, checking override maps if appropriate.

     * 

     * @param key

     * @return discovered override, or local value

     */

    public Object get(String key) {

        ArrayList<OverlayContext> overlays = threadOverrides.get();

        for(int i = overlays.size()-1; i>=0; i--) {

            OverlayContext ocontext = overlays.get(i); 

            for(int j = ocontext.getOverlayNames().size()-1; j>=0; j--) {

                String name = ocontext.getOverlayNames().get(j);

                Map<String,Object> m = ocontext.getOverlayMap(name);

                for(String ok : getOverrideKeys(key)) {

                    Object val = m.get(ok);

                    if(val!=null) {

                        return val;

                    }

                }

            }

        }



        return super.get(key);

    }



    /**

     * Compose the complete keys (externalPath + local key name) to use

     * for checking for contextual overrides. 

     * 

     * @param key local key to compose

     * @return List of full keys to check

     */

    protected List<String> getOverrideKeys(String key) {

        ArrayList<String> keys = new ArrayList<String>(externalPaths.size());

        for(String path : externalPaths) {

            keys.add(path+"."+key);

        }

        return keys;

    }

OverlayContext 인터페이스 소스는 다음과 같습니다.
/**

 * Interface for objects that can contribute 'overlays' to replace the

 * usual values in configured objects. 

 * @contributor gojomo

 */

public interface OverlayContext {

    /** test if this context has actually been configured with overlays

     * (even if in fact no overlays were added) */

    public boolean haveOverlayNamesBeenSet();

    /** return a list of the names of overlay maps to consider */ 

    ArrayList<String> getOverlayNames();

    /** get the map corresponding to the overlay name */ 

    Map<String,Object> getOverlayMap(String name);

}

OverlayContext 인터페이스는 하나의 구현 클래스 CrawlURI만 있고 인터페이스 구현과 관련된 방법은 다음과 같다(OverlayMapsSource 인터페이스 리셋 방법)
 //

    // OverridesSource implementation

    //

    transient protected ArrayList<String> overlayNames = null;

    transient protected OverlayMapsSource overlayMapsSource; 

    public boolean haveOverlayNamesBeenSet() {

        return overlayNames != null;

    }

    

    public ArrayList<String> getOverlayNames() {

        if(overlayNames == null) {

            overlayNames = new ArrayList<String>(); 

        }

        return overlayNames;

    }



    public Map<String, Object> getOverlayMap(String name) {

        return overlayMapsSource.getOverlayMap(name);

    }



    public void setOverlayMapsSource(OverlayMapsSource overrideMapsSource) {

        this.overlayMapsSource = overrideMapsSource;

    }

OverlayMapsSource 인터페이스 소스는 다음과 같습니다.
/**

 * Interface for a source of overlay maps by name. 

 * 

 * @contributor gojomo

 */

public interface OverlayMapsSource {

    public Map<String,Object> getOverlayMap(String name); 

}

Overlay MapsSource 인터페이스는 클래스SheetOverlays Manager를 실현하고, SheetOverlays Manager 클래스는 BeanFactory Aware 인터페이스와ApplicationListener 인터페이스를 실현한다.
SheetOverlays Manager 클래스 구성원은 다음과 같습니다. (여기는 실질적으로 Sheet 설정과 CrawlURI 대상과 Sheet의 매핑)
BeanFactory beanFactory; 

    /** all SheetAssociations by DecideRule evaluation */ 

    SortedSet<DecideRuledSheetAssociation> ruleAssociations = 

        new ConcurrentSkipListSet<DecideRuledSheetAssociation>();

    NavigableMap<String,List<String>> sheetNamesBySurt = new ConcurrentSkipListMap<String,List<String>>(); 

    

    /** all sheets by (bean)name*/

    Map<String,Sheet> sheetsByName = new ConcurrentHashMap<String, Sheet>();

OverlayMapsSource 인터페이스 구현 방법(키(String name 매개 변수)에 따라 Sheet 대상을 가져오고 Sheet 대상의 Map 용기 대상을 가져옴)
 /**

     * Retrieve the named overlay Map.

     * 

     * @see org.archive.spring.OverlayMapsSource#getOverlayMap(java.lang.String)

     */

    public Map<String, Object> getOverlayMap(String name) {

        return sheetsByName.get(name).getMap();

    }

ApplicationListener 인터페이스 사항은 다음과 같습니다.
/** 

     * Ensure all sheets are 'primed' after the entire ApplicatiotnContext

     * is assembled. This ensures target HasKeyedProperties beans know

     * any long paths by which their properties are addressed, and 

     * handles (by either PropertyEditor-conversion or a fast-failure)

     * any type-mismatches between overlay values and their target

     * properties.

     * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)

     */

    public void onApplicationEvent(ApplicationEvent event) {

        if(event instanceof ContextRefreshedEvent) {

            for(Sheet s: sheetsByName.values()) {

                s.prime(); // exception if Sheet can't target overridable properties

            }

            // log warning for any sheets named but not present

            HashSet<String> allSheetNames = new HashSet<String>();

            for(DecideRuledSheetAssociation assoc : ruleAssociations) {

                allSheetNames.addAll(assoc.getTargetSheetNames());

            }

            for(List<String> names : sheetNamesBySurt.values()) {

                allSheetNames.addAll(names);

            }

            for(String name : allSheetNames) {

                if(!sheetsByName.containsKey(name)) {

                    logger.warning("sheet '"+name+"' referenced but absent");

                }

            }

        }

    }

sheet 설정에서 대상과 속성 형식이 일치하는지 확인하고, 그 다음에 설정에 존재하지 않는sheet 이름이 있는지 확인합니다. (초기화할 때 호출)
void applyOverlaysTo(CrawlURI curi) 방법
/**

     * Apply the proper overlays (by Sheet beanName) to the given CrawlURI,

     * according to configured associations.  

     * 

     * TODO: add guard against redundant application more than once? 

     * TODO: add mechanism for reapplying overlays after settings change? 

     * @param curi

     */

    public void applyOverlaysTo(CrawlURI curi) {

        curi.setOverlayMapsSource(this); 

        // apply SURT-based overlays

        curi.getOverlayNames().clear(); // clear previous info

        String effectiveSurt = SurtPrefixSet.getCandidateSurt(curi.getPolicyBasisUURI());

        List<String> foundPrefixes = PrefixFinder.findKeys(sheetNamesBySurt, effectiveSurt);       

        for(String prefix : foundPrefixes) {

            for(String name : sheetNamesBySurt.get(prefix)) {

                curi.getOverlayNames().add(name);

            }

        }

        // apply deciderule-based overlays

        for(DecideRuledSheetAssociation assoc : ruleAssociations) {

            if(assoc.getRules().accepts(curi)) {

                curi.getOverlayNames().addAll(assoc.getTargetSheetNames());

            }

        }

        // even if no overlays set, let creation of empty list signal

        // step has occurred -- helps ensure overlays added once-only

        curi.getOverlayNames();

    }

먼저 CrawlURI curi 대상의 구성원 변수인 OverlayMapsSource overlayMapsSource를 설정하고 이 CrawlURI curi 대상의 설정을 불러옵니다. (키워드에 따라 다른 대상이 호출되고 관련 속성 값을 가져오는 데 사용)
우리가 지금 계속 알아야 할 것은 Sheet류이다. 먼저 Crawler-beans에 익숙해져라.cxml 파일의 설정 (클래스의 속성을 덮어쓰는 데 사용)
<!-- veryPolite: any URI to which this sheet's settings are applied 

     will cause its queue to take extra-long politeness snoozes -->

<bean id='veryPolite' class='org.archive.spring.Sheet'>

 <property name='map'>

  <map>

   <entry key='disposition.delayFactor' value='10'/>

   <entry key='disposition.minDelayMs' value='10000'/>

   <entry key='disposition.maxDelayMs' value='1000000'/>

   <entry key='disposition.respectCrawlDelayUpToSeconds' value='3600'/>

  </map>

 </property>

</bean>

Sheet의 구성원 변수는 다음과 같습니다.
/**

     * unique name of this Sheet; if Sheet has a beanName from original

     * configuration, that is always the name -- but the name might 

     * also be another string, in the case of Sheets added after 

     * initial container wiring

     */

    String name;    

    /** map of full property-paths (from BeanFactory to individual 

     * property) and their changed value when this Sheet of overrides

     * is in effect

     */

    Map<String,Object> map = new ConcurrentHashMap<String, Object>(); 

void prime () 방법은 대상과 해당 속성 유형이 일치하는지 검사하는 데 사용됩니다
/**

     * Ensure any properties targetted by this Sheet know to 

     * check the right property paths for overrides at lookup time,

     * and that the override values are compatible types for their 

     * destination properties. 

     * 

     * Should be done as soon as all possible targets are 

     * constructed (ApplicationListener ContextRefreshedEvent)

     * 

     * TODO: consider if  an 'un-priming' also needs to occur to 

     * prevent confusing side-effects. 

     * TODO: consider if priming should move to another class

     */

    public void prime() {

        for (String fullpath : map.keySet()) {

            int lastDot =  fullpath.lastIndexOf(".");

            String beanPath = fullpath.substring(0,lastDot);

            String terminalProp = fullpath.substring(lastDot+1);

            Object value = map.get(fullpath); 

            int i = beanPath.indexOf(".");

            Object bean; 

            HasKeyedProperties hkp;

            if (i < 0) {

                bean = beanFactory.getBean(beanPath);

            } else {

                String beanName = beanPath.substring(0,i);

                String propPath = beanPath.substring(i+1);

                BeanWrapperImpl wrapper = new BeanWrapperImpl(beanFactory.getBean(beanName));

                bean = wrapper.getPropertyValue(propPath);  

            }

            try {

                hkp = (HasKeyedProperties) bean;

            } catch (ClassCastException cce) {

                // targetted bean has no overridable properties

                throw new TypeMismatchException(bean,HasKeyedProperties.class,cce);

            }

            // install knowledge of this path 

            hkp.getKeyedProperties().addExternalPath(beanPath);

            // verify type-compatibility

            BeanWrapperImpl wrapper = new BeanWrapperImpl(hkp);

            Class<?> requiredType = wrapper.getPropertyType(terminalProp);

            try {

                // convert for destination type

                map.put(fullpath, wrapper.convertForProperty(value,terminalProp));

            } catch(TypeMismatchException tme) {

                TypeMismatchException tme2 = 

                    new TypeMismatchException(

                            new PropertyChangeEvent(

                                    hkp,

                                    fullpath,

                                    wrapper.getPropertyValue(terminalProp),

                                    value), requiredType, tme);

                throw tme2;

            }

        }

    }

위에서 주의해야 할 것은hkp이다.getKeyedProperties().addExternalPath(beanPath)
Keyed Properties 클래스의HashSet external Paths = new HashSet () 는 중복 값이 없는 집합이기 때문에 중복 추가된 요소beanPath를 필터합니다
추상 클래스 SheetAssociation 정의 대상 Sheet 객체의 이름 집합
/**

 * Represents target Sheets that should be associated with 

 * some grouping of URIs. 

 * 

 * Subclasses specify the kind of association (as by SURT prefix 

 * matching, or arbitrary decide-rules).

 * 

 * @contributor gojomo

 */

public abstract class SheetAssociation {

    List<String> targetSheetNames = new LinkedList<String>();

    public List<String> getTargetSheetNames() {

        return targetSheetNames;

    }

    public void setTargetSheetNames(List<String> targetSheets) {

        this.targetSheetNames = targetSheets;

    }

}

SheetAssociation의 하위 클래스SurtPrefixes SheetAssociation, CrawlURI curi 대상의classkey 값과sheet 집합의 매핑을 설정합니다
/**

 * SheetAssociation applied on the basis of matching SURT prefixes. 

 * 

 * @contributor gojomo

 */

public class SurtPrefixesSheetAssociation extends SheetAssociation {

    List<String> surtPrefixes;



    public List<String> getSurtPrefixes() {

        return surtPrefixes;

    }

    @Required

    public void setSurtPrefixes(List<String> surtPrefixes) {

        this.surtPrefixes = surtPrefixes;

    }

}

Crawler-beans에서.cxml 파일의 설정 예는 다음과 같다
<bean class='org.archive.crawler.spring.SurtPrefixesSheetAssociation'>

 <property name='surtPrefixes'>

  <list>

   <value>http://(org,example,</value>

   <value>http://(com,example,www,)/</value>

  </list>

 </property>

 <property name='targetSheetNames'>

  <list>

   <value>veryPolite</value>

   <value>smallBudget</value>

  </list>

 </property>

</bean>

SheetAssociation 클래스의 다른 하위 클래스인 DecideRuledSheetAssociation 코드는 다음과 같습니다. (DecideRule 대상과 Sheet 집합의 매핑을 설정하는 데 사용됩니다)
/**

 * SheetAssociation applied on the basis of DecideRules. If the

 * final ruling is ACCEPT, the named sheets will be overlaid. 

 * 

 * @contributor gojomo

 */

public class DecideRuledSheetAssociation extends SheetAssociation 

implements Ordered, Comparable<DecideRuledSheetAssociation>, BeanNameAware {

    DecideRule rules;

    int order = 0; 

    

    public DecideRule getRules() {

        return rules;

    }

    @Required

    public void setRules(DecideRule rules) {

        this.rules = rules;

    }



    public int getOrder() {

        return order;

    }

    public void setOrder(int order) {

        this.order = order;

    }



    // compare on the basis of Ordered value

    public int compareTo(DecideRuledSheetAssociation o) {

        int cmp = order - ((Ordered)o).getOrder();

        if(cmp!=0) {

            return cmp;

        }

        return name.compareTo(o.name); 

    }

    

    String name;

    public void setBeanName(String name) {

        this.name = name;

    }

}

프로필crawler-beans.cxml에서 나는 아직 예시를 찾지 못했다. (그러나 우리는 사용자 정의 설정을 할 수 있다.)
---------------------------------------------------------------------------
본 시리즈의 Heritrix 3.1.0 원본 해석은 본인이 창작한 것입니다.
전재 는 출처 가 블로그 정원 고슴도치 의 온순함 을 밝혀 주십시오
본문 링크http://www.cnblogs.com/chenying99/archive/2013/04/20/3031937.html

좋은 웹페이지 즐겨찾기