You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
479 lines
16 KiB
479 lines
16 KiB
package adecWatt.model;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.File;
|
|
import java.io.FileFilter;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Enumeration;
|
|
import java.util.HashSet;
|
|
import java.util.Hashtable;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.TreeMap;
|
|
import java.util.TreeSet;
|
|
import java.util.zip.ZipEntry;
|
|
import java.util.zip.ZipInputStream;
|
|
import java.util.zip.ZipOutputStream;
|
|
import javax.xml.parsers.DocumentBuilder;
|
|
import javax.xml.parsers.DocumentBuilderFactory;
|
|
import javax.xml.transform.OutputKeys;
|
|
import javax.xml.transform.Result;
|
|
import javax.xml.transform.Source;
|
|
import javax.xml.transform.Transformer;
|
|
import javax.xml.transform.TransformerException;
|
|
import javax.xml.transform.TransformerFactory;
|
|
import javax.xml.transform.dom.DOMSource;
|
|
import javax.xml.transform.stream.StreamResult;
|
|
import org.w3c.dom.Document;
|
|
|
|
import misc.Config;
|
|
import misc.Log;
|
|
import misc.Util;
|
|
import static misc.Config.FS;
|
|
|
|
import adecWatt.control.AdecWattManager;
|
|
import adecWatt.model.unit.Building;
|
|
import adecWatt.model.xml.XmlUnit;
|
|
|
|
public class PermanentDB {
|
|
|
|
// ========================================
|
|
static public final File dataDir = Config.findDataDir ();
|
|
static public enum UnitLocation { Server, Local, Zip };
|
|
static public final String localToken = "local";
|
|
static public final String serverToken = "server";
|
|
static public final String cacheToken = "cache";
|
|
static public final List<String> localRemoteDir = Arrays.asList (localToken, serverToken);
|
|
static public final String lptExtention = "lpt";
|
|
static public final String lpzExtention = "lpz";
|
|
static public final String backExtention = "back";
|
|
static public final String[] exportExtention = { lpzExtention };
|
|
|
|
// ========================================
|
|
private AdecWatt adecWatt;
|
|
private ImageDB iconDB;
|
|
private ImageDB imageDB;
|
|
private String powerPlugId, powerSocketId;
|
|
|
|
public String getPowerPlugId () { return powerPlugId; }
|
|
public String getPowerSocketId () { return powerSocketId; }
|
|
|
|
public ArrayList<Building> getAllBuildings () {
|
|
ArrayList<Building> result = new ArrayList<Building> ();
|
|
for (Enumeration<?> enumUnitNode = getRootByName (Prop.PropBuilding).getUnitNode ().breadthFirstEnumeration ();
|
|
enumUnitNode.hasMoreElements();
|
|
) {
|
|
Building building = (Building) ((UnitNode<?>) enumUnitNode.nextElement ()).getUnit ();
|
|
if (building.isUncompleted (null))
|
|
continue;
|
|
result.add (building);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public PermanentDB (AdecWatt adecWatt) {
|
|
this.adecWatt = adecWatt;
|
|
iconDB = adecWatt.getIconDB ();
|
|
imageDB = adecWatt.getImageDB ();
|
|
}
|
|
|
|
// ========================================
|
|
// Unit
|
|
// ========================================
|
|
HashSet<Unit<?>> allUnit = new HashSet<Unit<?>> ();
|
|
Hashtable<String, Unit<?>> idUnit = new Hashtable<String, Unit<?>> ();
|
|
Hashtable<String, Unit<?>> namedRoots = new Hashtable<String, Unit<?>> ();
|
|
|
|
public boolean isReferedUnit (String unitId) { return idUnit.containsKey (unitId); }
|
|
public Unit<?> getUnitById (String unitId) { return idUnit.get (unitId); }
|
|
public Unit<?> getRootByName (String unitName) { return namedRoots.get (unitName); }
|
|
public Set<String> getReferedIds () { return idUnit.keySet (); }
|
|
|
|
public boolean isModifiedUnit () {
|
|
for (Unit<?> unit : allUnit)
|
|
if (unit.story.isModified ())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// ========================================
|
|
public void reload () {
|
|
powerSocketId = powerPlugId = null;
|
|
allUnit.clear ();
|
|
idUnit.clear ();
|
|
namedRoots.clear ();
|
|
for (String srcDir : localRemoteDir)
|
|
for (File file : getAllXmlFiles (srcDir))
|
|
try {
|
|
if (file.length () == 0)
|
|
continue;
|
|
Log.writeLog ("PermanentDB", "load "+srcDir+"/"+file.getName ());
|
|
FileInputStream fileInputStream = new FileInputStream (file);
|
|
Unit<?> unit = Unit.getInstanceFromStream (adecWatt, fileInputStream, file,
|
|
serverToken.equals (srcDir) ? UnitLocation.Server : UnitLocation.Local);
|
|
fileInputStream.close ();
|
|
if (isReferedUnit (unit.getId ())) {
|
|
System.err.println (unit.getName ()+" already recorded : skip "+file);
|
|
// ignore
|
|
continue;
|
|
}
|
|
add (unit);
|
|
} catch (Exception e) {
|
|
System.err.println ("XXX: "+file+" error: "+e);
|
|
e.printStackTrace ();
|
|
}
|
|
for (Unit<?> unit : allUnit)
|
|
unit.updateXmlParent ();
|
|
}
|
|
|
|
public void newNamePlan (TreeMap<String, String> iconMap, TreeMap<String, String> imageMap) {
|
|
HashSet<Editable<?, ?, ?, ?>> visited = new HashSet<Editable<?, ?, ?, ?>> ();
|
|
for (Unit<?> unit : allUnit)
|
|
unit.newNamePlan (visited, iconMap, imageMap);
|
|
}
|
|
|
|
public void add (Unit<?> unit) {
|
|
String unitId = unit.getId ();
|
|
try {
|
|
allUnit.remove (idUnit.get (unitId));
|
|
} catch (Exception e) {
|
|
}
|
|
allUnit.add (unit);
|
|
idUnit.put (unitId, unit);
|
|
adecWatt.getUser ().updateDataId (unitId);
|
|
if ("powerPlug".equals (unit.getName ()))
|
|
powerPlugId = unitId;
|
|
if ("powerSocket".equals (unit.getName ()))
|
|
powerSocketId = unitId;
|
|
unit.enableStory ();
|
|
}
|
|
public void forget (Unit<?> unit) {
|
|
adecWatt.broadcastDisplay (AdecWattManager.actionClose, unit);
|
|
idUnit.remove (unit.getId ());
|
|
allUnit.remove (unit);
|
|
unit.disableStory ();
|
|
// XXX et si "powerPlug" ou "powerSocket" ?
|
|
}
|
|
public Unit<?> reload (Unit<?> unit) {
|
|
for (String srcDir : localRemoteDir) {
|
|
try {
|
|
File file = getXmlFile (new File (dataDir, srcDir), unit.getFileName ());
|
|
FileInputStream fileInputStream = new FileInputStream (file);
|
|
Unit<?> newUnit = Unit.getInstanceFromStream (adecWatt, fileInputStream, file,
|
|
serverToken.equals (srcDir) ? UnitLocation.Server : UnitLocation.Local);
|
|
fileInputStream.close ();
|
|
return newUnit;
|
|
} catch (Exception e) {
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
public void remove (Unit<?> unit) {
|
|
if (unit.file != null)
|
|
Util.backup (unit.file, Util.getExtention (unit.file), backExtention);
|
|
forget (unit);
|
|
}
|
|
public void renameVisitor (HashSet<Unit<?>> units) {
|
|
TreeMap<String, String> translateMap = new TreeMap<String, String> ();
|
|
String pattern = String.format ("%03d-", User.visitorId);
|
|
User user = adecWatt.getUser ();
|
|
for (Unit<?> unit : units) {
|
|
String unitId = unit.getId ();
|
|
if (!unitId.startsWith (pattern))
|
|
continue;
|
|
translateMap.put (unitId, user.getDataId ());
|
|
}
|
|
if (translateMap.size () < 1)
|
|
return;
|
|
for (String unitId : translateMap.keySet ()) {
|
|
Unit<?> unit = idUnit.get (unitId);
|
|
if (unit.file != null)
|
|
Util.backup (unit.file, Util.getExtention (unit.file), backExtention);
|
|
idUnit.remove (unitId);
|
|
String newUnitId = translateMap.get (unitId);
|
|
unit.changeId (newUnitId);
|
|
idUnit.put (newUnitId, unit);
|
|
}
|
|
for (Unit<?> unit : allUnit)
|
|
if (unit.renameUnits (translateMap))
|
|
// YYY voir save ?
|
|
unit.story.markNotSaved ();
|
|
}
|
|
public void promote (HashSet<Unit<?>> units) {
|
|
if (units.size () == 0)
|
|
return;
|
|
for (Unit<?> unit : units)
|
|
unit.promote ();
|
|
adecWatt.broadcastUpdate (AdecWatt.BroadcastUnitRoots);
|
|
}
|
|
public void renameImages (TreeMap<String, String> translateMap) {
|
|
for (Unit<?> unit : allUnit)
|
|
if (unit.renameImages (translateMap))
|
|
// YYY voir save ?
|
|
unit.story.markNotSaved ();
|
|
}
|
|
|
|
// ========================================
|
|
static public final File getXmlFile (String name) {
|
|
for (String srcDir : localRemoteDir)
|
|
try {
|
|
File file = getXmlFile (new File (dataDir, srcDir), name);
|
|
if (file != null)
|
|
return file;
|
|
} catch (Exception e) {
|
|
}
|
|
return null;
|
|
}
|
|
|
|
static public final File getXmlFile (File dir, String name) {
|
|
File test = new File (dir, name);
|
|
if (test.exists ())
|
|
return test;
|
|
for (File subDir : getSubDirs (dir)) {
|
|
test = getXmlFile (subDir, name);
|
|
if (test != null)
|
|
return test;
|
|
|
|
}
|
|
return null;
|
|
}
|
|
|
|
static public final File[] getXmlFiles (File dir) {
|
|
return dir.listFiles (new FileFilter () {
|
|
public boolean accept (File file) {
|
|
return file.isFile () && !file.isHidden () &&
|
|
lptExtention.equals (Util.getExtention (file));
|
|
}
|
|
});
|
|
}
|
|
static public final File[] getSubDirs (File dir) {
|
|
return dir.listFiles (new FileFilter () {
|
|
public boolean accept (File file) {
|
|
return file.isDirectory () && ! file.isHidden ();
|
|
}
|
|
});
|
|
}
|
|
public boolean isFileNameExists (String baseName) {
|
|
for (String srcDir : localRemoteDir)
|
|
try {
|
|
if (isFileExists (new File (dataDir, srcDir), baseName))
|
|
return true;
|
|
} catch (Exception e) {
|
|
}
|
|
return false;
|
|
}
|
|
public boolean isFileExists (File dir, String baseName) {
|
|
for (File file : getXmlFiles (dir)) {
|
|
String fileName = file.getName ();
|
|
if (fileName.startsWith (baseName) &&
|
|
lptExtention.equals (fileName.substring (1+baseName.length ())))
|
|
return true;
|
|
}
|
|
for (File subDir : getSubDirs (dir))
|
|
if (isFileExists (subDir, baseName))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// ========================================
|
|
static public ArrayList<File> getAllXmlFiles (String srcDir) {
|
|
ArrayList<File> result = new ArrayList<File> ();
|
|
try {
|
|
getAllXmlFiles (new File (dataDir, srcDir), result);
|
|
} catch (Exception e) {
|
|
}
|
|
return result;
|
|
}
|
|
static public void getAllXmlFiles (File dir, ArrayList<File> result) {
|
|
for (File file : getXmlFiles (dir))
|
|
result.add (file);
|
|
for (File subDir : getSubDirs (dir))
|
|
getAllXmlFiles (subDir, result);
|
|
}
|
|
|
|
// ========================================
|
|
static public File getInputFile (String name) {
|
|
for (String srcDir : localRemoteDir) {
|
|
File file = new File (dataDir, srcDir+FS+name);
|
|
if (file.exists () && file.isFile ())
|
|
return file;
|
|
}
|
|
throw new IllegalArgumentException ("Can't find input "+name+"!");
|
|
}
|
|
|
|
// ========================================
|
|
static public File getLocalFile (String name) {
|
|
File file = (new File (dataDir, localToken+FS+name));
|
|
file.getParentFile ().mkdirs ();
|
|
return file;
|
|
}
|
|
static public File getRemoteFile (String name) {
|
|
File file = (new File (dataDir, serverToken+FS+name));
|
|
file.getParentFile ().mkdirs ();
|
|
return file;
|
|
}
|
|
|
|
// ========================================
|
|
static public XmlUnit readXmlUnit (InputStream stream) {
|
|
try {
|
|
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance ().newDocumentBuilder ();
|
|
Document document = documentBuilder.parse (stream);
|
|
document.normalizeDocument ();
|
|
return new XmlUnit (document.getFirstChild ());
|
|
} catch (Exception e) {
|
|
Log.keepLastException ("PermanentDB::readDocument", e);
|
|
throw new IllegalArgumentException ("Not XML file input.");
|
|
}
|
|
}
|
|
|
|
// ========================================
|
|
static public Document newDocument () {
|
|
try {
|
|
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance ().newDocumentBuilder ();
|
|
Document document = documentBuilder.newDocument ();
|
|
document.setXmlStandalone (true);
|
|
return document;
|
|
} catch (Exception e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// ========================================
|
|
static public void writeUnit (Unit<?> unit, File file) {
|
|
try {
|
|
FileOutputStream fileOutputStream = new FileOutputStream (file);
|
|
writeUnit (unit, fileOutputStream);
|
|
fileOutputStream.close ();
|
|
} catch (Exception e) {
|
|
Log.keepLastException ("PermanentDB::writeDocument", e);
|
|
}
|
|
}
|
|
|
|
static public void writeUnit (Unit<?> unit, OutputStream stream)
|
|
throws IOException, TransformerException {
|
|
Document document = newDocument ();
|
|
unit.getXml (document, document);
|
|
Source source = new DOMSource (document);
|
|
Result result = new StreamResult (stream);
|
|
Transformer xformer = TransformerFactory.newInstance ().newTransformer ();
|
|
xformer.setOutputProperty (OutputKeys.INDENT, "yes");
|
|
xformer.setOutputProperty ("{http://xml.apache.org/xslt}indent-amount", "2");
|
|
xformer.transform (source, result);
|
|
stream.flush ();
|
|
}
|
|
|
|
public void addUnitZip (ZipOutputStream out, Unit<?> unit)
|
|
throws IOException, TransformerException {
|
|
if (unit == null)
|
|
return;
|
|
ZipEntry ze = new ZipEntry (unit.getSaveDir ()+"/"+unit.getFileName ());
|
|
out.putNextEntry (ze);
|
|
ByteArrayOutputStream stream = new ByteArrayOutputStream ();
|
|
writeUnit (unit, stream);
|
|
out.write (stream.toByteArray ());
|
|
out.closeEntry();
|
|
out.flush ();
|
|
}
|
|
|
|
public File getLastExport () { return Config.getFile ("LastExport"); }
|
|
|
|
public File checkExportExtention (File file) {
|
|
if (Util.getExtention (file) != null)
|
|
return file;
|
|
return new File (file.getParentFile (), Util.changeExtention (file.getName (), lpzExtention));
|
|
}
|
|
|
|
public void exportFile (Unit<?> unit, File file) {
|
|
if (file == null)
|
|
return;
|
|
try {
|
|
file = checkExportExtention (file);
|
|
HashSet<Unit<?>> unitLinks = new HashSet<Unit<?>> ();
|
|
TreeSet<String> iconsLinks = new TreeSet<String> ();
|
|
TreeSet<String> imagesLinks = new TreeSet<String> ();
|
|
unitLinks.add (unit);
|
|
unit.getLocalLink (new HashSet<Editable<?, ?, ?, ?>> (), unitLinks, iconsLinks, imagesLinks);
|
|
FileOutputStream fileOutputStream = new FileOutputStream (file);
|
|
ZipOutputStream out = new ZipOutputStream (fileOutputStream);
|
|
for (Unit<?> unit2 : unitLinks)
|
|
addUnitZip (out, unit2);
|
|
// XXX prendre aussi les étiquettes dans icon/"user".lpi filté avec "^imageName^:.*" dans iconsLinks
|
|
for (String iconName : iconsLinks)
|
|
iconDB.addImageZip (out, iconName);
|
|
// XXX prendre aussi les étiquettes dans image/"user".lpi filté avec "^imageName^:.*" dans imagesLinks
|
|
for (String imageName : imagesLinks)
|
|
imageDB.addImageZip (out, imageName);
|
|
out.close();
|
|
fileOutputStream.close ();
|
|
Config.setFile ("LastExport", file);
|
|
} catch (Exception e) {
|
|
e.printStackTrace ();
|
|
}
|
|
}
|
|
|
|
public void importFile (File file) {
|
|
if (file == null)
|
|
return;
|
|
try {
|
|
file = checkExportExtention (file);
|
|
ArrayList<Unit<?>> newUnit = new ArrayList<Unit<?>> ();
|
|
byte[] tmp = new byte[1024*1024];
|
|
FileInputStream fileInputStream = new FileInputStream (file);
|
|
ZipInputStream in = new ZipInputStream (fileInputStream);
|
|
for (;;) {
|
|
ZipEntry ze = in.getNextEntry ();
|
|
if (ze == null)
|
|
break;
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream ();
|
|
for (;;) {
|
|
int nb = in.read (tmp, 0, tmp.length);
|
|
if (nb < 0)
|
|
break;
|
|
out.write (tmp, 0, nb);
|
|
}
|
|
out.flush ();
|
|
in.closeEntry ();
|
|
String[] path = ze.getName ().split ("/");
|
|
String dirName = path[0];
|
|
String fileName = path [1];
|
|
String fileExtention = Util.getExtention (fileName);
|
|
ByteArrayInputStream dataIn = new ByteArrayInputStream (out.toByteArray ());
|
|
if (!iconDB.importFile (dirName, fileName, dataIn) &&
|
|
!imageDB.importFile (dirName, fileName, dataIn)) {
|
|
if (lptExtention.equals (fileExtention))
|
|
newUnit.add (Unit.getInstanceFromStream (adecWatt, dataIn, null, UnitLocation.Zip));
|
|
else
|
|
System.err.println ("XXX pb: "+fileName);
|
|
}
|
|
}
|
|
fileInputStream.close ();
|
|
for (Unit<?> unit : newUnit) {
|
|
String unitId = unit.getId ();
|
|
if (isReferedUnit (unitId)) {
|
|
Unit<?> oldUnit = idUnit.get (unitId);
|
|
forget (oldUnit);
|
|
oldUnit.replace (unit);
|
|
continue;
|
|
}
|
|
add (unit);
|
|
}
|
|
for (Unit<?> unit : newUnit) {
|
|
unit.updateXmlParent ();
|
|
unit.story.markNotSaved ();
|
|
}
|
|
adecWatt.broadcastUpdate (AdecWatt.BroadcastUnitRoots);
|
|
Config.setFile ("LastExport", file);
|
|
} catch (Exception e) {
|
|
e.printStackTrace ();
|
|
}
|
|
}
|
|
|
|
// ========================================
|
|
}
|
|
|