/*******************************************************************************
* Copyright (c) 2005-2011, G. Weirich and Elexis
* 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:
* G. Weirich - initial implementation
*
*******************************************************************************/
package ch.rgw.tools;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.StreamCorruptedException;
import java.util.ArrayList;
import ch.rgw.compress.CompEx;
/**
* Eine VersionedResource ist ein Datenobjekt, das einen String-Inhalt so speichert, dass bei einer
* neuen Speicherung der alte Inhalt nicht überschrieben, sondern mit Zeitstempel aufbewahrt wird.
* Zu einem späteren Zeitpunkt kann jede frühere Version wiederhergestellt werden. Die innere
* Implementation des Versionsalgorithmus ist transparent. Es ist sowohl eine simpke speicherung
* aller Versionen, als auch eine Speicherung eines Diff möglich. Abgeleitete Klassen könnten auch
* die alten Versionen extern ablegen etc. Zur Rückwärtskompatibiltät kann VersionedResource auch
* mit CompEx-gepackten Strings umgehen: Diese werden beim ersten Einlesen in VersionedResourcen
* umgewandelt.
*
* @author Gerry
*
*/
public class VersionedResource {
ArrayList<ResourceItem> items;
@SuppressWarnings("unchecked")
private VersionedResource(byte[] in){
items = new ArrayList<ResourceItem>();
if ((in == null) || (in.length == 0)) return;
try {
ByteArrayInputStream bais = new ByteArrayInputStream(in);
ObjectInputStream ois = new ObjectInputStream(bais);
items = (ArrayList<ResourceItem>) ois.readObject();
} catch (StreamCorruptedException se) {
update(new String(in), "(k)");
} catch (Exception ex) {
ExHandler.handle(ex);
}
}
/**
* Die Factory und einzige Möglichkeit, eine VersionedResource zu erstellen
*
* @param src
* mit serialize() erstellte frühere Repräsentation dieses Objekts, oder null, um
* eine neue VersionedResource zu erstellen.
* @return die VersionedResource.
*/
public static VersionedResource load(byte[] src){
byte[] exp = CompEx.expand(src);
return new VersionedResource(exp);
}
/**
* Eine neue Version des Dateninhalts einsetzen
*
* @param newValue
* der neue String
* @param remark
* Ein kurzer Beschreibungstext für diese Version
* @return false, wenn kein updatze erfolgte (z.B. weil die neue Version identisch mit der
* vorherigen war)
*/
public boolean update(String newValue, String remark){
if ((!items.isEmpty()) && getHead().equals(newValue)) {
return false;
}
return items.add(new ResourceItem(ResourceItem.REPLACE, newValue, remark));
}
/**
* Die neueste Version des Dateninhalts auslesen
*/
public String getHead(){
if (items.isEmpty()) {
return null;
}
return items.get(items.size() - 1).data;
}
/**
* Versionsnummer der neuesten Version auslesen
*/
public int getHeadVersion(){
return items.size() - 1;
}
/**
* Eine bestimmte Version des Dateninhalts auslesen
*
* @param v
* die gewünschte Versionsnummer
* @return der Dateninhalt in der gewünschten Version oder Null, wenn die gewünschte Version
* nicht existiert. Der zurückgelieferte Text enthält einen einzeiligen Header, der die
* Versionsmummer, Zeit/Datum der Erstellung und den Anmerkungstext enthält.
*/
public ResourceItem getVersion(int v){
if (v < 0 || v >= items.size()) {
return null;
}
return items.get(v);
}
/**
* Eine kompaktes Speicherbares Abbild dieser VersionedResource erstellen. Dieses enthält alle
* Versionen in komprimierter Form.
*/
public byte[] serialize(){
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(items);
return CompEx.Compress(baos.toByteArray(), CompEx.ZIP);
} catch (Exception ex) {
ExHandler.handle(ex);
return null;
}
}
/**
* Alle Einträge ausser dem Neuesten entfernen
*/
public void purge(){
if (items.size() > 0) {
ResourceItem head = items.get(items.size() - 1);
items.clear();
items.add(head);
}
}
public static class ResourceItem implements Serializable {
private static final long serialVersionUID = -7214215925169803335L;
static final int REPLACE = 0;
static final int DIFF1 = 1;
int mode;
public long timestamp;
public String remark;
public String data;
ResourceItem(int mode, String data, String remark){
this.mode = mode;
this.data = data;
this.remark = remark;
timestamp = System.currentTimeMillis();
}
public String getLabel(){
StringBuilder sb = new StringBuilder();
sb.append(new TimeTool(timestamp).toString(TimeTool.FULL_GER)).append(" - ")
.append(remark);
return sb.toString();
}
}
}