📄 referencemanager.java
字号:
oldRefBy.remove( referrer ); } // If the page is referred to by no one AND it doesn't even // exist, we might just as well forget about this entry. // It will be added again elsewhere if new references appear. if( ( ( oldRefBy == null ) || ( oldRefBy.isEmpty() ) ) && ( m_engine.pageExists( referredPage ) == false ) ) { m_referredBy.remove( referredPage ); } } } /** * When initially building a ReferenceManager from scratch, call this method * BEFORE calling updateReferences() with a full list of existing page names. * It builds the refersTo and referredBy key lists, thus enabling * updateReferences() to function correctly. * <P> * This method should NEVER be called after initialization. It clears all mappings * from the reference tables. * * @param pages a Collection containing WikiPage objects. */ private synchronized void buildKeyLists( Collection pages ) { m_refersTo.clear(); m_referredBy.clear(); if( pages == null ) return; Iterator it = pages.iterator(); try { while( it.hasNext() ) { WikiPage page = (WikiPage)it.next(); // We add a non-null entry to referredBy to indicate the referred page exists m_referredBy.put( page.getName(), new TreeSet<String>() ); // Just add a key to refersTo; the keys need to be in sync with referredBy. m_refersTo.put( page.getName(), null ); } } catch( ClassCastException e ) { log.fatal( "Invalid collection entry in ReferenceManager.buildKeyLists().", e ); } } /** * Marks the page as referred to by the referrer. If the page does not * exist previously, nothing is done. (This means that some page, somewhere, * has a link to a page that does not exist.) * <P> * This method is NOT synchronized. It should only be referred to from * within a synchronized method, or it should be made synced if necessary. */ private void updateReferredBy( String page, String referrer ) { // We're not really interested in first level self-references. /* if( page.equals( referrer ) ) { return; } */ // Neither are we interested if plural forms refer to each other. if( m_matchEnglishPlurals ) { String p2 = page.endsWith("s") ? page.substring(0,page.length()-1) : page+"s"; if( referrer.equals(p2) ) { return; } } Set<String> referrers = m_referredBy.get( page ); // Even if 'page' has not been created yet, it can still be referenced. // This requires we don't use m_referredBy keys when looking up missing // pages, of course. if(referrers == null) { referrers = new TreeSet<String>(); m_referredBy.put( page, referrers ); } referrers.add( referrer ); } /** * Clears the references to a certain page so it's no longer in the map. * * @param pagename Name of the page to clear references for. */ public synchronized void clearPageEntries( String pagename ) { pagename = getFinalPageName(pagename); // // Remove this item from the referredBy list of any page // which this item refers to. // Collection<String> c = m_refersTo.get( pagename ); if( c != null ) { for( String key : c ) { Collection<?> dref = m_referredBy.get( key ); dref.remove( pagename ); } } // // Finally, remove direct references. // m_referredBy.remove( pagename ); m_refersTo.remove( pagename ); } /** * Finds all unreferenced pages. This requires a linear scan through * m_referredBy to locate keys with null or empty values. * * @return The Collection of Strings */ public synchronized Collection findUnreferenced() { ArrayList<String> unref = new ArrayList<String>(); for( String key : m_referredBy.keySet() ) { Set<?> refs = getReferenceList( m_referredBy, key ); if( refs == null || refs.isEmpty() ) { unref.add( key ); } } return unref; } /** * Finds all references to non-existant pages. This requires a linear * scan through m_refersTo values; each value must have a corresponding * key entry in the reference Maps, otherwise such a page has never * been created. * <P> * Returns a Collection containing Strings of unreferenced page names. * Each non-existant page name is shown only once - we don't return information * on who referred to it. * * @return A Collection of Strings */ public synchronized Collection findUncreated() { TreeSet<String> uncreated = new TreeSet<String>(); // Go through m_refersTo values and check that m_refersTo has the corresponding keys. // We want to reread the code to make sure our HashMaps are in sync... Collection<Collection<String>> allReferences = m_refersTo.values(); for( Collection<String> refs : allReferences ) { if( refs != null ) { for( String aReference : refs ) { if( m_engine.pageExists( aReference ) == false ) { uncreated.add( aReference ); } } } } return uncreated; } /** * Searches for the given page in the given Map, and returns * the set of references. This method also takes care of English plural * matching. * * @param coll The Map to search in * @param pagename The name to find. * @return The references list. */ private <T> Set<T> getReferenceList( Map<String,Set<T>> coll, String pagename ) { Set<T> refs = coll.get( pagename ); if( m_matchEnglishPlurals ) { // // We'll add also matches from the "other" page. // Set<T> refs2; if( pagename.endsWith("s") ) { refs2 = coll.get( pagename.substring(0,pagename.length()-1) ); } else { refs2 = coll.get( pagename+"s" ); } if( refs2 != null ) { if( refs != null ) refs.addAll( refs2 ); else refs = refs2; } } return refs; } /** * Find all pages that refer to this page. Returns null if the page * does not exist or is not referenced at all, otherwise returns a * collection containing page names (String) that refer to this one. * <p> * @param pagename The page to find referrers for. * @return A Collection of Strings. (This is, in fact, a Set, and is likely * to change at some point to a Set). May return null, if the page * does not exist, or if it has no references. */ // FIXME: Return a Set instead of a Collection. public synchronized Collection findReferrers( String pagename ) { Set<String> refs = getReferenceList( m_referredBy, pagename ); if( refs == null || refs.isEmpty() ) { return null; } return refs; } /** * Returns all pages that refer to this page. Note that this method * returns an unmodifiable Map, which may be abruptly changed. So any * access to any iterator may result in a ConcurrentModificationException. * <p> * The advantages of using this method over findReferrers() is that * it is very fast, as it does not create a new object. The disadvantages * are that it does not do any mapping between plural names, and you * may end up getting a ConcurrentModificationException. * * @param pageName Page name to query. * @return A Set of Strings containing the names of all the pages that refer * to this page. May return null, if the page does not exist or * has not been indexed yet. * @since 2.2.33 */ public Set findReferredBy( String pageName ) { return m_unmutableReferredBy.get( getFinalPageName(pageName) ); } /** * Returns all pages that this page refers to. You can use this as a quick * way of getting the links from a page, but note that it does not link any * InterWiki, image, or external links. It does contain attachments, though. * <p> * The Collection returned is unmutable, so you cannot change it. It does reflect * the current status and thus is a live object. So, if you are using any * kind of an iterator on it, be prepared for ConcurrentModificationExceptions. * <p> * The returned value is a Collection, because a page may refer to another page * multiple times. * * @param pageName Page name to query * @return A Collection of Strings containing the names of the pages that this page * refers to. May return null, if the page does not exist or has not * been indexed yet. * @since 2.2.33 */ public Collection findRefersTo( String pageName ) { return m_unmutableRefersTo.get( getFinalPageName(pageName) ); } /** * This 'deepHashCode' can be used to determine if there were any * modifications made to the underlying to and by maps of the * ReferenceManager. The maps of the ReferenceManager are not * synchronized, so someone could add/remove entries in them while the * hashCode is being computed. * * @return Sum of the hashCodes for the to and by maps of the * ReferenceManager * @since 2.3.24 */ // // This method traps and retries if a concurrent // modifcaition occurs. // TODO: It is unnecessary to calculate the hashcode; it should be calculated only // when the hashmaps are changed. This is slow. // public int deepHashCode() { boolean failed = true; int signature = 0; while (failed) { signature = 0; try { signature ^= m_referredBy.hashCode(); signature ^= m_refersTo.hashCode(); failed = false; } catch (ConcurrentModificationException e) { Thread.yield(); } } return signature; } /** * Returns a list of all pages that the ReferenceManager knows about. * This should be roughly equivalent to PageManager.getAllPages(), but without * the potential disk access overhead. Note that this method is not guaranteed * to return a Set of really all pages (especially during startup), but it is * very fast. * * @return A Set of all defined page names that ReferenceManager knows about. * @since 2.3.24 */ public Set findCreated() { return new HashSet<String>( m_refersTo.keySet() ); } private String getFinalPageName( String orig ) { try { String s = m_engine.getFinalPageName( orig ); if( s == null ) s = orig; return s; } catch( ProviderException e ) { log.error("Error while trying to fetch a page name; trying to cope with the situation.",e); return orig; } } /** * {@inheritDoc} */ public void actionPerformed(WikiEvent event) { if( (event instanceof WikiPageEvent) && (event.getType() == WikiPageEvent.PAGE_DELETED) ) { String pageName = ((WikiPageEvent) event).getPageName(); if( pageName != null ) { pageRemoved( pageName ); } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -