Code Search for Developers
 
 
  

FolderArchiveWriter.java from BIRT at Krugle


Show FolderArchiveWriter.java syntax highlighted

/*******************************************************************************
 * Copyright (c) 2004 Actuate Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *  Actuate Corporation  - initial API and implementation
 *******************************************************************************/

package org.eclipse.birt.core.archive;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;

public class FolderArchiveWriter implements IDocArchiveWriter
{
	private String folderName;
	private IStreamSorter streamSorter = null;
	private LinkedList openStreams = new LinkedList( );
	

	/**
	 * @param absolute fileName the archive file name
	 */
	public FolderArchiveWriter( String folderName ) throws IOException
	{
		if ( folderName == null ||
				folderName.length() == 0 )
			throw new IOException("The folder name is null or empty string.");
		
		File fd = new File( folderName );
		folderName = fd.getCanonicalPath();   // make sure the file name is an absolute path
		this.folderName = folderName;		
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.birt.core.archive.IDocArchiveWriter#initialize()
	 */
	public void initialize() 
	{
		new File(folderName).mkdirs( );
		// Do nothing
	}

	/* (non-Javadoc)
	 * @see org.eclipse.birt.core.archive.IDocArchiveWriter#createRandomAccessStream(java.lang.String)
	 */
	public RAOutputStream createRandomAccessStream( String relativePath ) throws IOException
	{
		String path = ArchiveUtil.generateFullPath(folderName, relativePath);
		File fd = new File(path);

		ArchiveUtil.createParentFolder(fd);

		RAFolderOutputStream out = new RAFolderOutputStream(this, fd);
		synchronized (openStreams) 
		{
			openStreams.add(out);
		}
		return out;
	}

	/**
	 * Delete a stream from the archive and make sure the stream has been
	 * closed.
	 * 
	 * @param relativePath -
	 *            the relative path of the stream
	 * @return whether the delete operation was successful
	 * @throws IOException
	 */
	public boolean dropStream( String relativePath )
	{
		String path = ArchiveUtil.generateFullPath( folderName, relativePath );
		File fd = new File( path );
		return removeFileAndFolder( fd );
	}

	/* (non-Javadoc)
	 * @see org.eclipse.birt.core.archive.IDocArchiveWriter#getName()
	 */
	public String getName() 
	{
		return folderName;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.birt.core.archive.IDocArchiveWriter#exists()
	 */
	public boolean exists( String relativePath ) 
	{
		String path = ArchiveUtil.generateFullPath( folderName, relativePath );
		File fd = new File(path);
		return fd.exists();
	}	

	public void setStreamSorter( IStreamSorter streamSorter )
	{
		this.streamSorter = streamSorter;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.birt.core.archive.IDocArchiveWriter#finish()
	 */
	public void finish() throws IOException
	{
		closeAllStream( );
	}
	
	/**
	 * Convert the current folder archive to file archive. 
	 * The original folder archive will NOT be removed.
	 * @param fileArchiveName
	 * @throws IOException
	 */
	public void toFileArchive( String fileArchiveName ) throws IOException
	{
		// Write the temp archive content to the compound file	
		createFileFromFolder( fileArchiveName ); 
	}
	
	public void toFileArchive( RandomAccessFile compoundFile ) throws IOException
	{
		// Write the temp archive content to the compound file	
		createFileFromFolder( compoundFile ); 
	}


	/**
	 * files used to record the reader count reference.
	 */
	static final String READER_COUNT_FILE_NAME = "/.reader.count";
	/**
	 * files which should not be copy into the archives
	 */
	static final String[] SKIP_FILES = new String[]{READER_COUNT_FILE_NAME};

	static boolean needSkip( String file )
	{
		for ( int i = 0; i < SKIP_FILES.length; i++ )
		{
			if ( SKIP_FILES[i].equals( file ) )
			{
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Compound File Format: <br>
	 * 1long(stream section position) + 1long(entry number in lookup map) + lookup map section + stream data section <br>
	 * The Lookup map is a hash map. The key is the relative path of the stram. The entry contains two long number.
	 * The first long is the start postion. The second long is the length of the stream. <br>
	 * @param tempFolder
	 * @param fileArchiveName - the file archive name
	 * @return Whether the compound file was created successfully.
	 */
	private void createFileFromFolder( String fileArchiveName ) throws IOException
	{
		// Create the file
		File targetFile = new File( fileArchiveName );
		ArchiveUtil.DeleteAllFiles( targetFile );	// Delete existing file or folder that has the same name of the file archive.
		RandomAccessFile compoundFile = null;
		compoundFile = new RandomAccessFile( targetFile, "rw" );  //$NON-NLS-1$
		createFileFromFolder(compoundFile);
		compoundFile.close( );
	}
	private void createFileFromFolder( RandomAccessFile compoundFile ) throws IOException
	{
		compoundFile.setLength( 0 );
		compoundFile.seek( 0 );

		compoundFile.writeLong(0); 	// reserve a spot for writing the start position of the stream data section in the file
		compoundFile.writeLong(0);	// reserve a sopt for writing the entry number of the lookup map.

		ArrayList fileList = new ArrayList();
		getAllFiles( new File( folderName ), fileList );	
		
		if ( streamSorter != null )
		{
			ArrayList streamNameList = new ArrayList();
			for ( int i=0; i<fileList.size(); i++ )
			{
				File file = (File)fileList.get(i);
				streamNameList.add( ArchiveUtil.generateRelativePath(folderName, file.getAbsolutePath()) );
			}
					
			ArrayList sortedNameList = streamSorter.sortStream( streamNameList ); // Sort the streams by using the stream sorter (if any).
			
			if ( sortedNameList != null )
			{
				fileList.clear();			
				for ( int i=0; i<sortedNameList.size(); i++ )
				{
					String fileName = ArchiveUtil.generateFullPath( folderName, (String)sortedNameList.get(i) );
					fileList.add( new File(fileName) );
				}
			}			
		}

		// Generate the in-memory lookup map and serialize it to the compound file.
		long streamRelativePosition = 0;
		long entryNum = 0;
		for ( int i=0; i<fileList.size(); i++ )
		{
			File file = (File)fileList.get(i);				
			String relativePath = ArchiveUtil.generateRelativePath( folderName, file.getAbsolutePath() );
			if ( !needSkip( relativePath ) )
			{
				compoundFile.writeUTF( relativePath );
				compoundFile.writeLong( streamRelativePosition );
				compoundFile.writeLong( file.length() );
				
				streamRelativePosition += file.length();
				entryNum++;
			}
		}

		// Write the all of the streams to the stream data section in the compound file
		long streamSectionPos = compoundFile.getFilePointer();
		for ( int i=0; i<fileList.size(); i++ )
		{
			File file = (File)fileList.get(i);
			String relativePath = ArchiveUtil.generateRelativePath( folderName, file.getAbsolutePath() );
			if ( !needSkip( relativePath ) )
			{
				copyFileIntoTheArchive( file, compoundFile );
			}
		}			
		
		// go back and write the start position of the stream data section and the entry number of the lookup map 
		compoundFile.seek( 0 );						 
		compoundFile.writeLong( streamSectionPos );	
		compoundFile.writeLong( entryNum );
	}

	/**
	 * Get all the files under the specified folder (including all the files under sub-folders)
	 * @param dir - the folder to look into
	 * @param fileList - the fileList to be returned
	 */
	private void getAllFiles( File dir, ArrayList fileList )
	{
		if ( dir.exists() &&
			 dir.isDirectory() )
		{
			File[] files = dir.listFiles();
			if ( files == null )
				return;

			for ( int i=0; i<files.length; i++ )
			{
				File file = files[i];
				if ( file.isFile() )
				{
					fileList.add( file );
				}
				else if ( file.isDirectory() )
				{
					getAllFiles( file, fileList );
				}
			}
		}
	}
	
	/**
	 * Copy files from in to out
	 * @param in - input file
	 * @param out - output compound file. Since the input is only part of the file, the compound file output should be be closed by caller. 
	 * @throws Exception
	 */
	private long copyFileIntoTheArchive( File in, RandomAccessFile out ) 
		throws IOException 
	{	
		long totalBytesWritten = 0;
	    FileInputStream fis  = new FileInputStream(in);
	    byte[] buf = new byte[1024 * 5];
	    
	    int i = 0;
	    while( (i=fis.read(buf))!=-1 ) 
	    {
	      out.write(buf, 0, i);
	      totalBytesWritten += i;
	    }
	    fis.close();
	    
	    return totalBytesWritten;
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.eclipse.birt.core.archive.IDocArchiveWriter#flush()
	 */
	public void flush( ) throws IOException
	{
		IOException ioex = null;
		synchronized ( openStreams )
		{
			Iterator iter = openStreams.iterator( );
			while ( iter.hasNext( ) )
			{
				RAFolderOutputStream stream = (RAFolderOutputStream) iter
						.next( );
				if ( stream != null )
				{
					try
					{
						stream.flush( );
					}
					catch ( IOException ex )
					{
						ioex = ex;
					}
				}
			}
		}
		if ( ioex != null )
		{
			throw ioex;
		}
	}
	
	void removeStream(RAFolderOutputStream stream)
	{
		synchronized (openStreams)
		{
			openStreams.remove(stream);
		}
		//remove the stream out from the ouptutStreams.
	}

	protected void closeAllStream()
	{
		synchronized ( openStreams )
		{
			LinkedList streams = new LinkedList(openStreams);
			Iterator iter = streams.iterator( );
			while ( iter.hasNext( ) )
			{
				RAFolderOutputStream stream = (RAFolderOutputStream) iter
						.next( );
				if ( stream != null )
				{
					try
					{
						stream.close( );
					}
					catch ( IOException ex )
					{
					}
				}
			}
			openStreams.clear( );
		}
	}
	
	/**
	 * delete file or folder with its sub-folders and sub-files
	 * 
	 * @param file
	 *            file/folder which need to be deleted
	 * @return if files/folders can not be deleted, return false, or true
	 */
	private boolean removeFileAndFolder( File file )
	{
		assert ( file != null );
		if ( file.isDirectory( ) )
		{
			File[] children = file.listFiles( );
			if ( children != null )
			{
				for ( int i = 0; i < children.length; i++ )
				{
					removeFileAndFolder( children[i] );
				}
			}
		}
		if ( file.exists( ) )
		{
			return file.delete( );
		}
		return true;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.core.archive.IDocArchiveReader#lock(java.lang.String)
	 */
	public Object lock( String stream ) throws IOException
	{
		String path = ArchiveUtil.generateFullPath( folderName, stream + ".lck" );
		return DocArchiveLockManager.getInstance( ).lock( path );
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.core.archive.IDocArchiveReader#unlock(java.lang.Object)
	 */
	public void unlock( Object lock )
	{
		DocArchiveLockManager.getInstance( ).unlock( lock );
	}
}



See more files for this project here

BIRT

BIRT is an open source, Eclipse-based reporting system that integrates with your application to produce compelling reports for both web and PDF.

Project homepage: http://www.eclipse.org/birt/phoenix/
Programming language(s): Java,XML
License: gpl2

  ArchiveUtil.java
  DocArchiveLockManager.java
  FileArchiveReader.java
  FileArchiveWriter.java
  FolderArchive.java
  FolderArchiveReader.java
  FolderArchiveWriter.java
  IDocArchiveReader.java
  IDocArchiveWriter.java
  IStreamSorter.java
  RAFileInputStream.java
  RAFileOutputStream.java
  RAFolderInputStream.java
  RAFolderOutputStream.java
  RAInputStream.java
  RAOutputStream.java
  RAStreamBuffer.java
  RAStreamBufferMgr.java