Logiciel de gestion de plan de feu pour les troupes de théâtre amateur.
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

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 ();
}
}
// ========================================
}