/*
* Backup.java
*
* Created on April 27, 2007, 8:06 AM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.atomojo.app.admin;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URLDecoder;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.atomojo.app.Storage;
import org.atomojo.app.db.DB;
import org.atomojo.app.db.Entry;
import org.atomojo.app.db.EntryMedia;
import org.atomojo.app.db.Feed;
import org.infoset.xml.XMLException;
import org.infoset.xml.util.WriterItemDestination;
import org.restlet.data.Reference;
import org.restlet.representation.Representation;
/**
*
* @author alex
*/
public class Backup
{
static final String FEED_DOCUMENT_NAME = ".feed.atom";
abstract class BackupContext {
byte [] buffer = new byte[1024*32];
abstract void push(Feed feed)
throws IOException;
abstract void pop()
throws IOException;
abstract OutputStream startFeedOutput()
throws IOException;
abstract void endFeedOutput()
throws IOException;
abstract OutputStream startMediaOutput(EntryMedia media)
throws IOException;
abstract void endMediaOutput()
throws IOException;
}
Storage storage;
DB db;
Reference resourceBase;
/** Creates a new instance of Backup */
public Backup(DB db,Storage storage,Reference resourceBase)
{
this.db = db;
this.storage = storage;
this.resourceBase = resourceBase;
}
public void toDirectory(File dir)
throws SQLException,IOException
{
Writer w = new OutputStreamWriter(new FileOutputStream(new File(dir,"_introspection_.xml")),"UTF-8");
try {
db.getIntrospection(
storage,
"",
new DB.CollectionLocator() {
public String makeHref(Feed feed)
throws SQLException
{
String path = feed.getPath();
if (path.length()==0) {
return ".feed.atom";
} else {
return path+".feed.atom";
}
}
},
new WriterItemDestination(w,"UTF-8")
);
} catch (XMLException ex) {
throw new IOException(ex.getMessage());
}
w.flush();
w.close();
final List<File> dirs = new ArrayList<File>();
dirs.add(dir);
BackupContext context = new BackupContext() {
OutputStream current = null;
public void push(Feed feed)
throws IOException
{
String dirName = null;
try {
dirName = URLDecoder.decode(feed.getName(),"UTF-8");
} catch (UnsupportedEncodingException ex) {
throw new IOException("Cannot decode feed name '"+feed.getName()+"' : "+ex.getMessage());
}
File dir = new File(dirs.get(dirs.size()-1),dirName);
if (!dir.exists() && !dir.mkdir()) {
throw new IOException("Cannot create directory "+dir.getAbsolutePath());
}
dirs.add(dir);
}
public void pop() {
dirs.remove(dirs.size()-1);
}
public OutputStream startFeedOutput()
throws IOException
{
File feedFile = new File(dirs.get(dirs.size()-1),FEED_DOCUMENT_NAME);
FileOutputStream out = new FileOutputStream(feedFile);
current = out;
return out;
}
public void endFeedOutput()
throws IOException
{
if (current!=null) {
current.close();
}
}
public OutputStream startMediaOutput(EntryMedia media)
throws IOException
{
String name = URLDecoder.decode(media.getName(),"UTF-8");
File mediaFile = new File(dirs.get(dirs.size()-1),name);
FileOutputStream mout = new FileOutputStream(mediaFile);
current = mout;
return mout;
}
public void endMediaOutput()
throws IOException
{
if (current!=null) {
current.close();
}
}
};
Iterator<Feed> roots = db.getRootFeeds();
while (roots.hasNext()) {
Feed root = roots.next();
backup(context,root);
}
}
public void toZip(final String baseName,final File zipFile)
throws SQLException,IOException
{
final ZipOutputStream zipStream = new ZipOutputStream(new FileOutputStream(zipFile));
zipStream.setMethod(ZipOutputStream.DEFLATED);
Writer w = new OutputStreamWriter(zipStream,"UTF-8");
try {
ZipEntry theEntry = new ZipEntry(baseName+"/_introspection_.xml");
zipStream.putNextEntry(theEntry);
db.getIntrospection(
storage,
"",
new DB.CollectionLocator() {
public String makeHref(Feed feed)
throws SQLException
{
String path = feed.getPath();
if (path.length()==0) {
return ".feed.atom";
} else {
return path+".feed.atom";
}
}
},
new WriterItemDestination(w,"UTF-8")
);
zipStream.flush();
zipStream.closeEntry();
} catch (XMLException ex) {
throw new IOException(ex.getMessage());
}
final List<String> paths = new ArrayList<String>();
paths.add(baseName+"/");
BackupContext context = new BackupContext() {
public void push(Feed feed)
throws IOException
{
String dirName = null;
try {
dirName = URLDecoder.decode(feed.getName(),"UTF-8");
} catch (UnsupportedEncodingException ex) {
throw new IOException("Cannot decode feed name '"+feed.getName()+"' : "+ex.getMessage());
}
String current = paths.get(paths.size()-1);
String path = dirName.length()==0 ? current : current+dirName+"/";
paths.add(path);
}
public void pop() {
paths.remove(paths.size()-1);
}
public OutputStream startFeedOutput()
throws IOException
{
String path = paths.get(paths.size()-1)+FEED_DOCUMENT_NAME;
db.getLogger().info("Adding: "+path);
ZipEntry theEntry = new ZipEntry(path);
zipStream.putNextEntry(theEntry);
return zipStream;
}
public void endFeedOutput()
throws IOException
{
zipStream.flush();
zipStream.closeEntry();
}
public OutputStream startMediaOutput(EntryMedia media)
throws IOException
{
String name = URLDecoder.decode(media.getName(),"UTF-8");
String path = paths.get(paths.size()-1)+name;
db.getLogger().info("Adding: "+path);
ZipEntry theEntry = new ZipEntry(path);
zipStream.putNextEntry(theEntry);
return zipStream;
}
public void endMediaOutput()
throws IOException
{
zipStream.flush();
zipStream.closeEntry();
}
};
Iterator<Feed> roots = db.getRootFeeds();
while (roots.hasNext()) {
Feed root = roots.next();
backup(context,root);
}
zipStream.close();
}
protected void backup(BackupContext context,Feed feed)
throws SQLException,IOException
{
context.push(feed);
String fpath = feed.getPath();
Representation feedRep = storage.getFeed(fpath,feed.getUUID(),feed.getEntries());
if (feedRep!=null) {
OutputStream out = context.startFeedOutput();
feedRep.write(out);
context.endFeedOutput();
feedRep.release();
Iterator<Entry> entries = feed.getEntries();
while (entries.hasNext()) {
Entry entry = entries.next();
Iterator<EntryMedia> resources = entry.getResources();
while (resources.hasNext()) {
EntryMedia media = resources.next();
Representation mediaRep = storage.getMedia(fpath,feed.getUUID(),media.getName());
if (mediaRep==null) {
throw new IOException("Cannot get media "+media.getName()+" for feed at path "+fpath);
}
OutputStream mout = context.startMediaOutput(media);
mediaRep.write(mout);
context.endMediaOutput();
mediaRep.release();
}
}
Iterator<Feed> children = feed.getChildren();
while (children.hasNext()) {
Feed child = children.next();
backup(context,child);
}
} else {
throw new IOException("Cannot get feed representation for path "+fpath);
}
context.pop();
}
protected void copy(BackupContext context,InputStream is,OutputStream os)
throws IOException
{
int len;
while ((len=is.read(context.buffer))>0) {
os.write(context.buffer,0,len);
}
}
}