/*
* Copyright 2011 Uwe Krueger.
*
* Licensed 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.mandelsoft.mand.tools;
import com.mandelsoft.mand.Environment;
import com.mandelsoft.mand.IllegalConfigurationException;
import com.mandelsoft.mand.MandelData;
import com.mandelsoft.io.AbstractFile;
import com.mandelsoft.mand.ColormapName;
import com.mandelsoft.mand.MandelHeader;
import com.mandelsoft.mand.QualifiedMandelName;
import com.mandelsoft.mand.scan.DefaultColormapHandle;
import com.mandelsoft.mand.scan.DefaultMandelHandle;
import com.mandelsoft.mand.scan.ElementHandle;
import com.mandelsoft.mand.scan.MandelInventory;
import com.mandelsoft.mand.util.DefaultMandelListFolderTree;
import com.mandelsoft.mand.util.MandelList;
import com.mandelsoft.mand.util.MandelListFolder;
import com.mandelsoft.mand.util.MandelListFolderTree;
import com.mandelsoft.util.UnclosableInputStream;
import com.mandelsoft.util.UnclosableOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Proxy;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
*
* @author Uwe Krueger
*/
public class Archiver extends Sync {
public Archiver(Environment src, Environment dst, int types)
{
super(src, dst, types);
}
public Archiver(Environment src, Environment dst)
{
super(src, dst);
}
////////////////////////////////////////////////////////////////////////
// Writer
////////////////////////////////////////////////////////////////////////
public static class ZipOS extends UnclosableOutputStream {
public ZipOS(ZipOutputStream zos)
{
super(zos);
}
}
public class ArchiveWriter implements SyncHandler {
private File zipfile;
private MandelInventory inv=new MandelInventory();
private List<ElementHandle> list=new ArrayList<ElementHandle>();
private Map<String, MandelList> lists=new HashMap<String, MandelList>();
private Map<String, MandelListFolderTree> trees=new HashMap<String, MandelListFolderTree>();
private ZipOutputStream zip;
public ArchiveWriter(File zipfile)
{
this.zipfile=zipfile;
}
public void copy(ElementHandle src, AbstractFile dst)
{
AbstractFile mf=src.getFile();
String name=mf.getName();
list.add(src);
inv.add(name, src.getHeader().getType()|MandelData.M_INFOOMITTED, null, mf.
getLastModified());
}
public void backupInfoFile(AbstractFile mf)
{
}
public void backupRasterFile(AbstractFile mf)
{
}
public void backupAreaColormapFile(AbstractFile mf)
{
}
public void syncList(MandelList ml, MandelList dl, String name)
{
lists.put(name, ml);
}
public Set<QualifiedMandelName> syncTree(MandelListFolderTree ml,
MandelListFolderTree dl,
String name)
{
trees.put(name, ml);
return new HashSet<QualifiedMandelName>();
}
public void finish()
{
try {
System.out.println("creating archive "+zipfile);
zip=new ZipOutputStream(new BufferedOutputStream(
new FileOutputStream(zipfile)));
zip.setMethod(ZipOutputStream.DEFLATED);
try {
ZipEntry e=new ZipEntry("inventory");
zip.putNextEntry(e);
inv.write(new ZipOS(zip), "inventory");
zip.closeEntry();
for (ElementHandle h :list) {
System.out.println("writing "+h.getFile().getName());
e=new ZipEntry("mandel/"+h.getFile().getName());
e.setTime(h.getFile().getLastModified());
zip.putNextEntry(e);
putData(h.getFile().getInputStream());
zip.closeEntry();
}
for (String n :lists.keySet()) {
System.out.println("writing list "+n);
e=new ZipEntry("lists/"+n);
zip.putNextEntry(e);
MandelList ml=lists.get(n);
ml.write(new ZipOS(zip),n);
zip.closeEntry();
}
for (String n :trees.keySet()) {
if (n.equals("news")) continue;
System.out.println("writing tree "+n);
e=new ZipEntry("trees/"+n);
zip.putNextEntry(e);
MandelListFolderTree mt=trees.get(n);
mt.write(new ZipOS(zip),n);
zip.closeEntry();
}
}
catch (IOException io) {
System.err.println(""+io);
zip.close();
System.exit(1);
}
finally {
zip.close();
}
}
catch (IOException io) {
System.err.println(""+io);
System.exit(1);
}
}
private void putData(InputStream inp) throws IOException
{
int n;
BufferedInputStream is=new BufferedInputStream(inp);
try {
while ((n=is.read(buffer))>0) {
zip.write(buffer, 0, n);
}
}
finally {
is.close();
}
}
}
//////////////////////////////////////////////////////////////////////////
// Reader
protected void read(File arch) throws IOException
{
ZipEntry e;
int ix;
String name;
String folder;
QualifiedMandelName qmn;
List<QualifiedMandelName> updates=new ArrayList<QualifiedMandelName>();
Set<QualifiedMandelName> favorites=new HashSet<QualifiedMandelName>();
MandelInventory inv=new MandelInventory();
ZipInputStream zis=new ZipInputStream(new FileInputStream(arch));
try {
e=zis.getNextEntry();
if (e.getName().equals("inventory")) {
inv.read(new UnclosableInputStream(zis), "inventory");
while ((e=zis.getNextEntry())!=null) {
if (e.isDirectory()) continue;
name=e.getName();
ix=name.indexOf('/');
if (ix>0) {
folder=name.substring(0, ix);
name=name.substring(ix+1);
if (folder.equals("mandel")) {
MandelInventory.Entry me=inv.get(name);
if (me!=null) {
AbstractFile file=new ZipMandelFile(e, zis);
MandelHeader h=new MandelHeader(me.getType());
ElementHandle eh;
if (h.isColormap()) {
eh=new DefaultColormapHandle(file,ColormapName.create(file),h);
}
else {
eh=new DefaultMandelHandle(file,QualifiedMandelName.create(file),h);
}
boolean found=false;
for (FileType t :types) {
if (t.match(h)) {
found=true;
if (handleFile(t, eh)) {
if (h.hasInfo()) {
qmn=(QualifiedMandelName)eh.getName();
if (qmn!=null) updates.add(qmn);
}
}
}
}
if (!found) {
System.err.println("ignoring "+name);
}
}
else {
System.out.println("unexpected file "+e.getName());
}
}
else {
// handle lists
if (folder.equals("lists")||folder.equals("trees")) {
MandelListFolderTree mt=new DefaultMandelListFolderTree(name);
try {
mt.read(new UnclosableInputStream(zis), e.getName());
MandelListFolderTree dt=findTree(name);
if (dt!=null) {
if (name.equals("favorites")) {
favorites=exec.syncTree(mt, dt, e.getName());
if (favorites!=null) {
System.out.println("found "+favorites.size()+" favorites");
}
else {
System.out.println("no new favorites");
}
}
else {
exec.syncTree(mt, dt, e.getName());
}
}
else {
MandelList dl=findList(name);
if (dl!=null) {
exec.syncList(mt.getRoot().getMandelList(), dl,
e.getName());
}
else
System.out.println("ignoring ("+folder+") "+e.getName());
}
}
catch (IOException io) {
System.out.println("cannot read list "+e.getName()+": "+io);
}
}
else {
System.out.println("ignoring unexpected entry "+e.getName());
}
}
}
}
}
else {
throw new IOException("inventory not found");
}
if (!updates.isEmpty()) {
for (MandelListFolderTree n :dst.getUserLists()) {
if (n.getRoot().getName().equals("news")) {
DateFormat fmt=new SimpleDateFormat("yyyyMMdd-HHmmss");
MandelListFolder uf=n.getRoot().createSubFolder(fmt.format(
new Date()));
MandelListFolder af=uf.createSubFolder("new");
af.getMandelList().addAll(updates);
if (favorites!=null&&!favorites.isEmpty()) {
MandelListFolder ff=uf.createSubFolder("favorites");
ff.getMandelList().addAll(favorites);
}
try {
n.save();
}
catch (IOException w) {
System.out.println("cannot write news: "+w);
}
}
}
}
exec.finish();
}
finally {
zis.close();
}
}
////////////////////////////////////////////////////////////////////////
protected MandelListFolderTree findTree(String name)
{
if (name.equals("favorites")) return dst.getFavorites();
if (name.equals("todos")) return dst.getTodos();
for (MandelListFolderTree t :dst.getUserLists()) {
if (t.getRoot().getName().equals(name)) return t;
}
return null;
}
protected MandelList findList(String name)
{
if (name.equals("seen")) return dst.getSeenRasters();
if (name.equals("areas")) return dst.getAreas();
return null;
}
////////////////////////////////////////////////////////////////////////
static public class ZipMandelFile implements AbstractFile {
ZipEntry e;
ZipInputStream zis;
public ZipMandelFile(ZipEntry e, ZipInputStream zis)
{
this.e=e;
this.zis=zis;
}
public boolean isFile()
{
return false;
}
public Proxy getProxy()
{
return null;
}
public InputStream getInputStream() throws IOException
{
try {
return new UnclosableInputStream(zis);
}
finally {
zis=null;
}
}
public long getLastModified()
{
return e.getTime();
}
public URL getURL()
{
return null;
}
public File getFile()
{
return null;
}
public String getPath()
{
return e.getName();
}
public String getName()
{
int ix=e.getName().lastIndexOf('/');
if (ix>=0) return e.getName().substring(ix+1);
return e.getName();
}
public boolean lock() throws IOException
{
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean tryLock() throws IOException
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void releaseLock() throws IOException
{
throw new UnsupportedOperationException("Not supported yet.");
}
public AbstractFile getParent()
{
return null;
}
public AbstractFile getSub(String name)
{
return null;
}
@Override
public String toString()
{
return getPath();
}
}
//////////////////////////////////////////////////////////////////////////
// Main
//////////////////////////////////////////////////////////////////////////
public static void main(String[] args)
{
int c=0;
String arg;
boolean vflag=false;
boolean wflag=false;
boolean rflag=false;
boolean cflag=false;
File src=new File("C:/work/AccuRev/test/Mandel");
File dst=new File("C:/Tomcat/apache-tomcat-6.0.29/webapps/mandel/mandel");
File arch=new File("mandel.zip");
String sn=null;
String dn=null;
if (args.length>0 && args[0].equals("help")) {
System.out.println("MandelDB Delta Archiver");
System.out.println(" <cmd> <options> <args>");
System.out.println(" -a <achivename> set the name of the used archive");
System.out.println(" -v show wht would be done");
System.out.println(" Archive Writer: <cmd> -w <options> <src> <dst>");
System.out.println(" -w write an archive");
System.out.println(" Archive Reader: <cmd> -r <options> <dst>");
System.out.println(" -r read an archive");
System.out.println(" -c copy mandel list instead of add content");
return;
}
while (args.length>c&&args[c].charAt(0)=='-') {
//System.out.println("arg: "+args[arg]);
arg=args[c++];
for (int i=1; i<arg.length(); i++) {
char opt=arg.charAt(i);
//System.out.println("option: "+opt);
switch (opt) {
case 'v':
vflag=true;
break;
case 'w':
if (rflag) Error("only read or write allowed");
wflag=true;
break;
case 'r':
if (wflag) Error("only read or write allowed");
rflag=true;
break;
case 'c':
cflag=true;
break;
case 'a':
if (args.length>c) {
arch=new File(args[c++]);
}
else Error("archive name missing");
break;
default:
Error("illegal option '"+opt+"'");
}
}
//System.out.println("done");
}
if (wflag==rflag) {
rflag=vflag=true;
}
Archiver a;
int types;
if (wflag) {
try {
if (args.length>c) src=new File(args[c++]);
if (args.length>c) dst=new File(args[c++]);
else Error("mar: [-v] [-a <archive>] -w <srcroot> <dstroot>");
types=parseTypes(c, args);
System.out.println("create update archive from "+src+" to "+dst);
if (!src.isDirectory()) Error(src+" is no directory");
if (!dst.isDirectory()) Error(dst+" is no directory");
Environment env_src=new Environment("mandtool", null, src);
Environment env_dst=new Environment("mandtool", null, dst);
a=new Archiver(env_src, env_dst, types);
if (vflag) {
a.setExecutionHandler(a.new VerboseSyncHandler());
}
else {
a.setExecutionHandler(a.new ArchiveWriter(arch));
}
a.execute();
System.out.println(""+a.count+" copied");
}
catch (IllegalConfigurationException ex) {
ex.printStackTrace(System.err);
Error("error reading config: "+ex);
}
}
else if (rflag) {
try {
if (args.length>c) dst=new File(args[c++]);
else Error("mar: [-v] [-a <archive>] -r <dstroot>");
types=parseTypes(c, args);
System.out.println("extract update archive to "+dst);
if (!dst.isDirectory()) Error(dst+" is no directory");
Environment env_dst=new Environment("mandtool", null, dst);
a=new Archiver(null, env_dst, types);
a.setListCopyMode(cflag);
if (vflag) {
a.setExecutionHandler(a.new VerboseSyncHandler());
}
else {
a.setExecutionHandler(a.new DefaultSyncHandler());
}
try {
a.read(arch);
System.out.println(""+a.count+" copied");
}
catch (IOException ex) {
ex.printStackTrace(System.err);
Error("error reading archive: "+ex);
}
}
catch (IllegalConfigurationException ex) {
ex.printStackTrace(System.err);
Error("error reading config: "+ex);
}
}
}
}