package webman.stager;
import java.util.*;
import java.io.*;
import com.ringlord.archive.*;
/**
* geht durch die generierte Site, nimmt Informationen aus
*
* SiteStructureConfigReader: Nutzerkonfiguration (welche Dateien/Verzeichnisse sollen bertragen werden)
*
* SiteDocumentsListing: Informationen ber den letzten Stand der Site
* (Dateiliste mit Datum, Gre und Zielverzeichnis) --> welche Dateien sind neu/gendert
*
* schreibt den neuen Stand der Site wieder ins SiteDocumentsListing
*
* Endinformation:
* neuer Status der Site
* die zu bertragenden Dateien
*
* Extendet von webman.stager.SiteDocumentsListing fr leichten Transfer der Dateiliste zum SiteReceiver (Serialisierung)
*
* @author $Author: torsten $
* @version $Revision: 1.22 $
*/
class SitePacker extends SiteDocumentsListing
{
/**Interne Version, entspricht CVS-Revision*/
private final static String INTERNAL_VERSION = "1.15";
/**Umschreibung fr System.out*/
private static PrintStream sysout;
/**IO-Puffergre in Bytes fr Kopieren von Dateien*/
private final static int BUFSIZE = 2048;
/**Verzeichnistrennzeichen*/
private final static String FS = File.separator;
/**das Verzeichnis, von dem aus alle Dateien/Vezeichnisse abgearbeitet werden*/
private String documentRoot;
/**Name der Datei in der die alte Dateiliste gespeichert ist*/
private SiteDocumentsListing oldListing;
/**
* @param docRoot Wurzelverzeichnis fr den Dateisammelprozess; alle Unterverzeichnisse werden besucht
* @param configFile Nutzerkonfiguration der Site-Struktur (z.B. conf/sitedocuments.conf)
* @param targetDir optional kann statt configFile auch nur ein Zielverzeichnis fr den OnlineServer benannt werden
* dann wird die gesamte documentRoot bertragen; sind beide Parameter vorhanden, wird configFile bevorzugt
* @param documentListing Name der Datei in der die alte Dateiliste gespeichert ist und die neue auch gespeichert wird
* @param filterFiles bei false wird nicht beachtet, was die Nutzerkonfiguration aussagt in Bezug darauf
* ob Dateien/Verzeichnisse bertragen werden sollen oder nicht
* @throws IOException wenn beim Zusammentragen der Dateien was schiefgeht
*/
SitePacker(String docRoot, String configFile, String targetDir, SiteDocumentsListing documentListing,
boolean filterFiles) throws IOException
{
super();
sysout = System.out; //Work-around fr Jtest (wenn man statisch inititalisiert, erkennt jtest system.out!!
documentRoot = docRoot;
oldListing = documentListing;
SiteStructureConfigReader sscr = new SiteStructureConfigReader(configFile,targetDir);
sysout.println("SitePacker-Version: " + INTERNAL_VERSION);
try
{
processDirectory(".", sscr, filterFiles);
}
catch ( IOException e )
{
if ( e.getMessage().endsWith(documentRoot + FS + "." + FS + " is no directory or cannot be read.") )
{
throw new IOException("DocumentRoot " + documentRoot + " cannot be read. Check that it's really a readable directory!");
}
}
}
/**
* packt die zu bertragende Site in ein Zip
* egal, wo das Zip gespeichert wird, die interne Dateistruktur entpricht der DocumentRoot
* @param filename Name des zu erstellenden Zips
* @param tempDir Name des temporren Verzeichnisses, in dem die Site fr das Zip zusammengestellt wird
* @param onlyChangedDocuments wenn true werden nur seit der letzten bertragung neue/genderte Dateien bertragen
* @return Referenz auf das fertige Zipfile
* @throws IOException wenn beim Zusammentragen der Dateien was schiefgeht
*/
public File zipSite(String filename, String tempDir, boolean onlyChangedDocuments) throws IOException
{
//making tempdir if dont exist
File f = new File(tempDir);
createDir(f);
// copy files to temp dir
if ( !tempDir.endsWith(FS) && !tempDir.endsWith("/") )
//Windows-Pfadnamen knnen in Java auch mit / gebildet werden. Wenn allerdings tempDir auf /
//endet und ich normalerweise deswegen den FS anhngen wrde, kme ein falscher Pfadname zu Stande
//(den Dateien im Zip wrde dann immer der erste Buchstabe fehlen!!). Deswegen muss ich auch auf / testen
{
tempDir = tempDir + FS;
}
if ( !documentRoot.endsWith(FS) && !tempDir.endsWith("/") ) //Begrndung s.o.
{
documentRoot = documentRoot + FS;
}
// get list of dirs
String[] dirs = getDirectories();
for ( int k = 0; k < dirs.length; k++ )
{
// create targetDirs
createDir(new File(tempDir, dirs[k]));
// sysout.println("copy contents of directory " + dirs[k] + "<br>");
// get list of documents
String[] files;
if ( onlyChangedDocuments )
{
files = getChangedAndNewDocumentNames(dirs[k], oldListing);
}
else
{
files = getDocumentNames(dirs[k]);
}
// copy files
String aDir = dirs[k] + File.separator;
for ( int i = 0; i < files.length; i++ )
{
String fname = aDir + files[i];
//sysout.println("copy file " + fname + " from " + documentRoot + " to " + tempDir + "<br>");
copyFile(new File(documentRoot, fname), new File(tempDir, fname));
}
}
Archive archive = null;
File archiveFile = new File(filename);
try
{
archive = new ArchiveFactory().create(archiveFile);
if ( archive == null )
{
throw new IOException("archive could not be created.");
}
archive.addDir("",new File(tempDir), true);
archive.close();
}
catch (Exception e)
{
if ( e.getMessage().indexOf("ZIP file must have at least one entry") > -1 )
{
sysout.println("Note: zipfile contains no data.");
archiveFile.createNewFile(); //neue, leere Datei erstellen (sonst gibz die Datei nich!)
}
else
{
sysout.println(e);
e.printStackTrace();
}
}
return archiveFile;
}
/**
* Arbeitet Verzeichnis der DocumentRoot ab und sammelt entsprechend der Konfiguration Dateien/Unterverzeichnisse fr die bertragung
* @param subDir das aktuell zu bearbeitende Verzeichnis
* @param sscr die Konfiguration (u.U. aus targetDir hergeleitet, s. Konstruktor)
* @param filterFiles bei false wird nicht beachtet, was die Nutzerkonfiguration aussagt in Bezug darauf
* ob Dateien/Verzeichnisse bertragen werden sollen oder nicht
* @throws IOException wenn beim Zusammentragen der Dateien was schiefgeht
*/
void processDirectory(String subDir, SiteStructureConfigReader sscr, boolean filterFiles) throws IOException
{
String curDir = new File(documentRoot + FS + subDir + FS).getCanonicalPath() + FS;
//jtest duldet keine System.out.println!!
sysout.println("site assembler: processing directory " + curDir + "<br>");
String target = sscr.getTargetDirectory(subDir + FS);
// get contents of current dir
String[] list = (new File(curDir)).list();
//Abfrage wichtig, wenn ich mit DocRoot beginne und die falsch gesetzt war (kme sonst zu NullPointeException)
if ( list == null )
{
throw new IOException(curDir + " is no directory or cannot be read.");
}
// look at every entry
for ( int i = 0; i < list.length; i++ )
{
//System.out.println("packer: " + subDir + FS + list[i] + " ?");
File f = new File(curDir + list[i]);
if ( f.isDirectory() )
{
// test if dir belongs to site
if ( !filterFiles || sscr.belongsToSite(subDir + FS + list[i] + FS) )
{
// recursive call
processDirectory(subDir + FS + list[i], sscr, filterFiles);
}
}
else
{
// test if document belongs to site
if ( !filterFiles || sscr.belongsToSite(subDir + FS + list[i]) )
{
addDocument(subDir, list[i], f.lastModified(), f.length(), target);
//System.out.println("packer: added doc " + subDir + FS + list[i] + "<br>");
}
}
}
}
/**
* Kopiert Dateien/Verzeichnisse
* @param source Quelldatei/-verzeichnis
* @param target Zieldatei/-verzeichnis
* @throws IOException wenn beim Kopieren was schiefgeht
*/
static void copyFile(File source, File target) throws IOException
{
if ( source.isDirectory() ) //kann Directories als solche nicht kopieren
{
if ( !target.mkdir() )
{
throw new IOException("could not create temporary directory " + target.getPath());
}
return; //mehr ist nicht zu tun
}
FileInputStream fis = null;
FileOutputStream fos = null;
try
{
fis = new FileInputStream(source);
fos = new FileOutputStream(target);
byte[] buf = new byte[BUFSIZE];
//int offs = 0;
int read;
while ( (read = fis.read(buf, 0, BUFSIZE)) != -1)
{
fos.write(buf, 0, read);
}
fos.flush();
}
catch (IOException e)
{
throw new IOException("unable to copy file " + source + " to " + target + " (" + e + ")");
}
finally
{
if ( fis != null )
{
fis.close();
}
if ( fos != null )
{
fos.close();
}
}
}
/**
* Erstellt ein Verzeichnis, falls es noch nicht vorhanden ist (und auch keine gleichnamige Datei existiert)
* @param f zu erstellendes Verzeichnis
* @throws IOException wenn beim Zusammentragen der Dateien was schiefgeht
*/
static void createDir(File f) throws IOException
{
if ( !f.exists() )
{
if ( !f.mkdirs() )
{
throw new IOException("unable to create directory: " + f);
}
}
else
{
// must be a directory
if ( !f.isDirectory() )
{
throw new IOException("unable to create directory: " + f + " - a file with that name exist");
}
}
}
}
|