📄 versioningfileprovider.java
字号:
/* JSPWiki - a JSP-based WikiWiki clone. Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */package com.ecyrd.jspwiki.providers;import java.io.*;import java.util.Collection;import java.util.Iterator;import java.util.Properties;import java.util.Date;import java.util.ArrayList;import java.util.List;import org.apache.log4j.Logger;import com.ecyrd.jspwiki.*;/** * Provides a simple directory based repository for Wiki pages. * Pages are held in a directory structure: * <PRE> * Main.txt * Foobar.txt * OLD/ * Main/ * 1.txt * 2.txt * page.properties * Foobar/ * page.properties * </PRE> * * In this case, "Main" has three versions, and "Foobar" just one version. * <P> * The properties file contains the necessary metainformation (such as author) * information of the page. DO NOT MESS WITH IT! * * <P> * All files have ".txt" appended to make life easier for those * who insist on using Windows or other software which makes assumptions * on the files contents based on its name. * */public class VersioningFileProvider extends AbstractFileProvider implements VersioningProvider{ private static final Logger log = Logger.getLogger(VersioningFileProvider.class); /** Name of the directory where the old versions are stored. */ public static final String PAGEDIR = "OLD"; /** Name of the property file which stores the metadata. */ public static final String PROPERTYFILE = "page.properties"; private CachedProperties m_cachedProperties; /** * {@inheritDoc} */ public void initialize( WikiEngine engine, Properties properties ) throws NoRequiredPropertyException, IOException { super.initialize( engine, properties ); // some additional sanity checks : File oldpages = new File(getPageDirectory(), PAGEDIR); if (!oldpages.exists()) { if (!oldpages.mkdirs()) { throw new IOException("Failed to create page version directory " + oldpages.getAbsolutePath()); } } else { if (!oldpages.isDirectory()) { throw new IOException("Page version directory is not a directory: " + oldpages.getAbsolutePath()); } if (!oldpages.canWrite()) { throw new IOException("Page version directory is not writable: " + oldpages.getAbsolutePath()); } } log.info("Using directory " + oldpages.getAbsolutePath() + " for storing old versions of pages"); } /** * Returns the directory where the old versions of the pages * are being kept. */ private File findOldPageDir( String page ) { if( page == null ) { throw new InternalWikiException("Page may NOT be null in the provider!"); } File oldpages = new File( getPageDirectory(), PAGEDIR ); return new File( oldpages, mangleName(page) ); } /** * Goes through the repository and decides which version is * the newest one in that directory. * * @return Latest version number in the repository, or -1, if * there is no page in the repository. */ // FIXME: This is relatively slow. /* private int findLatestVersion( String page ) { File pageDir = findOldPageDir( page ); String[] pages = pageDir.list( new WikiFileFilter() ); if( pages == null ) { return -1; // No such thing found. } int version = -1; for( int i = 0; i < pages.length; i++ ) { int cutpoint = pages[i].indexOf( '.' ); if( cutpoint > 0 ) { String pageNum = pages[i].substring( 0, cutpoint ); try { int res = Integer.parseInt( pageNum ); if( res > version ) { version = res; } } catch( NumberFormatException e ) {} // It's okay to skip these. } } return version; }*/ private int findLatestVersion( String page ) throws ProviderException { int version = -1; try { Properties props = getPageProperties( page ); for( Iterator i = props.keySet().iterator(); i.hasNext(); ) { String key = (String)i.next(); if( key.endsWith(".author") ) { int cutpoint = key.indexOf('.'); if( cutpoint > 0 ) { String pageNum = key.substring(0,cutpoint); try { int res = Integer.parseInt( pageNum ); if( res > version ) { version = res; } } catch( NumberFormatException e ) {} // It's okay to skip these. } } } } catch( IOException e ) { log.error("Unable to figure out latest version - dying...",e); } return version; } /** * Reads page properties from the file system. */ private Properties getPageProperties( String page ) throws IOException { File propertyFile = new File( findOldPageDir(page), PROPERTYFILE ); if( propertyFile.exists() ) { long lastModified = propertyFile.lastModified(); // // The profiler showed that when calling the history of a page the propertyfile // was read just as much times as there were versions of that file. The loading // of a propertyfile is a cpu-intensive job. So now hold on to the last propertyfile // read because the next method will with a high probability ask for the same propertyfile. // The time it took to show a historypage with 267 versions dropped with 300%. // CachedProperties cp = m_cachedProperties; if( cp != null && cp.m_page.equals(page) && cp.m_lastModified == lastModified) { return cp.m_props; } InputStream in = null; try { in = new BufferedInputStream(new FileInputStream( propertyFile )); Properties props = new Properties(); props.load(in); cp = new CachedProperties(); cp.m_page = page; cp.m_lastModified = lastModified; cp.m_props = props; m_cachedProperties = cp; // Atomic return props; } finally { if( in != null ) in.close(); } } return new Properties(); // Returns an empty object } /** * Writes the page properties back to the file system. * Note that it WILL overwrite any previous properties. */ private void putPageProperties( String page, Properties properties ) throws IOException { File propertyFile = new File( findOldPageDir(page), PROPERTYFILE ); OutputStream out = null; try { out = new FileOutputStream( propertyFile ); properties.store( out, " JSPWiki page properties for "+page+". DO NOT MODIFY!" ); } finally { if( out != null ) out.close(); } } /** * Figures out the real version number of the page and also checks * for its existence. * * @throws NoSuchVersionException if there is no such version. */ private int realVersion( String page, int requestedVersion ) throws NoSuchVersionException, ProviderException { // // Quickly check for the most common case. // if( requestedVersion == WikiProvider.LATEST_VERSION ) { return -1; } int latest = findLatestVersion(page); if( requestedVersion == latest || (requestedVersion == 1 && latest == -1 ) ) { return -1; } else if( requestedVersion <= 0 || requestedVersion > latest ) { throw new NoSuchVersionException("Requested version "+requestedVersion+", but latest is "+latest ); } return requestedVersion; } /** * {@inheritDoc} */ public synchronized String getPageText( String page, int version ) throws ProviderException { File dir = findOldPageDir( page ); version = realVersion( page, version ); if( version == -1 ) { // We can let the FileSystemProvider take care // of these requests. return super.getPageText( page, WikiPageProvider.LATEST_VERSION ); } File pageFile = new File( dir, ""+version+FILE_EXT ); if( !pageFile.exists() ) throw new NoSuchVersionException("Version "+version+"does not exist."); return readFile( pageFile ); } // FIXME: Should this really be here? private String readFile( File pagedata ) throws ProviderException { String result = null; InputStream in = null; if( pagedata.exists() ) { if( pagedata.canRead() ) { try { in = new FileInputStream( pagedata ); result = FileUtil.readContents( in, m_encoding ); } catch( IOException e ) { log.error("Failed to read", e); throw new ProviderException("I/O error: "+e.getMessage()); } finally { try { if( in != null ) in.close(); } catch( Exception e ) { log.fatal("Closing failed",e); } } } else { log.warn("Failed to read page from '"+pagedata.getAbsolutePath()+"', possibly a permissions problem"); throw new ProviderException("I cannot read the requested page."); } } else { // This is okay. // FIXME: is it? log.info("New page"); } return result; } // FIXME: This method has no rollback whatsoever. /* This is how the page directory should look like: version pagedir olddir none empty empty 1 Main.txt (1) empty 2 Main.txt (2) 1.txt 3 Main.txt (3) 1.txt, 2.txt */ /** * {@inheritDoc} */ public synchronized void putPageText( WikiPage page, String text ) throws ProviderException {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -