/* ** This file is part of Filius, a network construction and simulation software. ** ** Originally created at the University of Siegen, Institute "Didactics of ** Informatics and E-Learning" by a students' project group: ** members (2006-2007): ** André Asschoff, Johannes Bade, Carsten Dittich, Thomas Gerding, ** Nadja Haßler, Ernst Johannes Klebert, Michell Weyer ** supervisors: ** Stefan Freischlad (maintainer until 2009), Peer Stechert ** Project is maintained since 2010 by Christian Eibl <filius@c.fameibl.de> ** and Stefan Freischlad ** Filius is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 2 of the License, or ** (at your option) version 3. ** ** Filius is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied ** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ** PURPOSE. See the GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with Filius. If not, see <http://www.gnu.org/licenses/>. */ package filius.rahmenprogramm; import java.beans.ExceptionListener; import java.beans.XMLDecoder; import java.beans.XMLEncoder; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.io.Serializable; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.ListIterator; import java.util.Observable; import java.util.StringTokenizer; import java.util.Vector; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; import javax.swing.ImageIcon; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import filius.exception.VerbindungsException; import filius.gui.GUIContainer; import filius.gui.GUIErrorHandler; import filius.gui.JMainFrame; import filius.gui.netzwerksicht.GUIKabelItem; import filius.gui.netzwerksicht.GUIKnotenItem; import filius.gui.netzwerksicht.GUISidebar; import filius.gui.netzwerksicht.JSidebarButton; import filius.hardware.Kabel; import filius.hardware.NetzwerkInterface; import filius.hardware.Port; import filius.hardware.knoten.Knoten; import filius.hardware.knoten.Modem; import filius.hardware.knoten.Rechner; import filius.hardware.knoten.Switch; import filius.hardware.knoten.Vermittlungsrechner; import filius.software.system.Betriebssystem; import filius.software.system.SystemSoftware; import filius.software.system.VermittlungsrechnerBetriebssystem; import filius.Main; public class SzenarioVerwaltung extends Observable implements I18n { private boolean geaendert = false; private String pfad = null; private static SzenarioVerwaltung verwaltung = null; private SzenarioVerwaltung() { } public static SzenarioVerwaltung getInstance() { Main.debug.println("INVOKED (static) filius.rahmenprogramm.SzenarioVerwaltung, getInstance()"); if (verwaltung == null) { verwaltung = new SzenarioVerwaltung(); } return verwaltung; } public void reset() { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+", reset()"); pfad = null; geaendert = false; setChanged(); notifyObservers(); } public boolean speichern(LinkedList hardwareItems, LinkedList kabelItems) { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+", speichern("+hardwareItems+","+kabelItems+")"); if (pfad != null) return speichern(pfad, hardwareItems, kabelItems); else return speichern(Information.getInformation().getArbeitsbereichPfad()+"projekt.fls", hardwareItems, kabelItems); } public void laden(LinkedList hardwareItems, LinkedList kabelItems) { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+", laden("+hardwareItems+","+kabelItems+")"); try { if (pfad != null) laden(pfad, hardwareItems, kabelItems); else laden(Information.getInformation().getArbeitsbereichPfad()+"projekt.fls", hardwareItems, kabelItems); } catch (FileNotFoundException e) { e.printStackTrace(Main.debug); } } public void setzeGeaendert() { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+", setzeGeaendert()"); geaendert = true; this.setChanged(); this.notifyObservers(); } public boolean istGeaendert() { return geaendert; } public String holePfad() { return pfad; } public void setzePfad(String pfad) { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+", setzePfad("+pfad+")"); this.pfad = pfad; this.setChanged(); this.notifyObservers(); } /** * Speichern: * - der Netzwerkknoten (inkl. Betriebssystem, Anwendungen - * auch eigene/erweiterte - und Konfigurationen) * - der Verbindungen * - der Quelldateien und des Bytecodes von selbst erstellten Anwendungen * * Loesungsstrategie: * - generell einen eigenen ClassLoader verwenden * - XML-Datei fuer Objekte und Dateien aus dem Ordner Anwendungen in einem * leeren temporaeren Ordner speichern und daraus ein neues ZIP-Archiv * erstellen, dass an beliebigem Ort gespeichert werden kann */ public boolean speichern(String datei, LinkedList hardwareItems, LinkedList kabelItems) { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+", speichern("+datei+","+hardwareItems+","+kabelItems+")"); String tmpDir; boolean erfolg = true; tmpDir = Information.getInformation().getTempPfad()+"projekt"+System.getProperty("file.separator"); (new File(tmpDir)).mkdirs(); if (!kopiereVerzeichnis(Information.getInformation().getAnwendungenPfad(), tmpDir+"anwendungen")) { Main.debug.println("ERROR ("+this.hashCode()+"): Speicherung der eigenen Anwendungen fehlgeschlagen!"); erfolg = false; } if (!netzwerkSpeichern(tmpDir+"konfiguration.xml", hardwareItems, kabelItems)) { Main.debug.println("ERROR ("+this.hashCode()+"): Speicherung des Netzwerks fehlgeschlagen!"); erfolg = false; } if (!erzeugeZipArchiv(tmpDir, datei)) { Main.debug.println("ERROR ("+this.hashCode()+"): Speicherung der Projektdatei fehlgeschlagen!"); erfolg = false; } if (erfolg) { pfad = datei; geaendert = false; this.setChanged(); this.notifyObservers(); } loescheDateien(tmpDir); return erfolg; } private static boolean netzwerkSpeichern(String datei, LinkedList hardwareItems, LinkedList kabelItems) { Main.debug.println("INVOKED (static) filius.rahmenprogramm.SzenarioVerwaltung, netzwerkSpeichern("+datei+","+hardwareItems+","+kabelItems+")"); XMLEncoder mx = null; FileOutputStream fos = null; if (Thread.currentThread().getContextClassLoader() != FiliusClassLoader .getInstance(Thread.currentThread().getContextClassLoader())) Thread.currentThread().setContextClassLoader( FiliusClassLoader.getInstance(Thread.currentThread() .getContextClassLoader())); try { fos = new FileOutputStream(datei); mx = new XMLEncoder(new BufferedOutputStream(fos)); mx.setExceptionListener(new ExceptionListener() { public void exceptionThrown(Exception arg0) { arg0.printStackTrace(Main.debug); } }); mx.writeObject(new String("Filius version: "+filius.rahmenprogramm.Information.getVersion())); mx.writeObject(hardwareItems); mx.writeObject(kabelItems); return true; } catch (java.lang.RuntimeException e) { Main.debug.println("EXCEPTION: java.lang.RuntimeException raised; Java internal problem, not Filius related!"); return false; } catch (FileNotFoundException e2) { e2.printStackTrace(Main.debug); return false; } catch (Exception e) { return false; } finally { if (mx != null) mx.close(); if (fos != null) { try { fos.close(); } catch (IOException e) { } } } } public boolean laden(String datei, LinkedList hardwareItems, LinkedList kabelItems) throws FileNotFoundException { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+", laden("+datei+","+hardwareItems+","+kabelItems+")"); boolean erfolg = true; String tmpDir; //Main.debug.println("SzenarioVerwaltung: Laden des Projekts aus Datei "+datei); tmpDir = Information.getInformation().getTempPfad(); loescheDateien(tmpDir+"projekt"); if (erfolg && !loescheVerzeichnisInhalt(Information.getInformation().getAnwendungenPfad())) { Main.debug.println("ERROR ("+this.hashCode()+"): Loeschen vorhandener Anwendungen fehlgeschlagen"); } if (!entpackeZipArchiv(datei, tmpDir)) { Main.debug.println("ERROR ("+this.hashCode()+"): Entpacken des Zip-Archivs fehlgeschlagen"); erfolg = false; } if (erfolg && !kopiereVerzeichnis(tmpDir+"projekt/anwendungen", Information.getInformation().getAnwendungenPfad())) { Main.debug.println("ERROR ("+this.hashCode()+"): Kopieren der Anwendungen fehlgeschlagen"); } if (erfolg && !netzwerkLaden(tmpDir+"projekt/konfiguration.xml", hardwareItems, kabelItems)) { Main.debug.println("ERROR ("+this.hashCode()+"): Laden der Netzwerkkonfiguration fehlgeschlagen"); erfolg = false; } if (erfolg) { pfad = datei; geaendert = false; this.setChanged(); this.notifyObservers(); } return erfolg; } /** * Lädt ein gespeichertes Netzwerk aus der Datei save.xml * * @author Johannes Bade & Thomas Gerding * @param filepath * @param filename * @throws FileNotFoundException */ private static boolean netzwerkLaden(String datei, LinkedList hardwareItems, LinkedList kabelItems) throws FileNotFoundException { Main.debug.println("INVOKED (static) filius.rahmenprogramm.SzenarioVerwaltung, netzwerkLaden("+datei+","+hardwareItems+","+kabelItems+")"); XMLDecoder xmldec; LinkedList tempList = null; Object tmpObject = null; ListIterator it; //Main.debug.println("SzenarioVerwaltung: Laden aus Datei "+datei); if (Thread.currentThread().getContextClassLoader() != FiliusClassLoader .getInstance(Thread.currentThread().getContextClassLoader())) Thread.currentThread().setContextClassLoader( FiliusClassLoader.getInstance(Thread.currentThread() .getContextClassLoader())); try { xmldec = new XMLDecoder(new BufferedInputStream( new FileInputStream(datei))); xmldec.setExceptionListener(new ExceptionListener() { public void exceptionThrown(Exception arg0) { arg0.printStackTrace(Main.debug); } }); Information.getInformation().reset(); tmpObject = xmldec.readObject(); // in newer versions of Filius the version information is put into the saved file as well // WARNING: former versions expect LinkedList as first element in the saved file! if(tmpObject instanceof String) { String versionInfo = (String) tmpObject; Main.debug.println("File saved by Filius in version '"+versionInfo.substring(versionInfo.indexOf(":")+2)+"'"); if(versionInfo.substring(versionInfo.indexOf(":")+2).compareTo(filius.rahmenprogramm.Information.getVersion()) < 0) { Main.debug.println("WARNING: current Filius version is newer ("+filius.rahmenprogramm.Information.getVersion()+") than version of scenario file, such that certain elements might not be rendered correctly any more!"); } else if(versionInfo.substring(versionInfo.indexOf(":")+2).compareTo(filius.rahmenprogramm.Information.getVersion()) > 0) { Main.debug.println("WARNING: current Filius version is older ("+filius.rahmenprogramm.Information.getVersion()+") than version of scenario file, such that certain elements might not be rendered correctly!"); } else { Main.debug.println("\t...good, current version of Filius is equal to version of scenario file"); } tmpObject = null; } else { Main.debug.println("WARNING: Version information of Filius scenario file could not be determined!"); Main.debug.println("WARNING: This usually means, the scenario file was created with Filius before version 1.3.0."); Main.debug.println("WARNING: Certain elements might not be rendered correctly any more!"); } if(tmpObject == null) tempList = (LinkedList) xmldec.readObject(); else tempList = (LinkedList) tmpObject; it = tempList.listIterator(); hardwareItems.clear(); while (it.hasNext()) { GUIKnotenItem tmpNode= (GUIKnotenItem) it.next(); tmpNode.getImageLabel().setHardwareTyp(tmpNode.getKnoten().holeHardwareTyp()); hardwareItems.add(tmpNode); } tempList = (LinkedList) xmldec.readObject(); it = tempList.listIterator(); kabelItems.clear(); while (it.hasNext()) { GUIKabelItem cable = (GUIKabelItem) it.next(); // Main.debug.println("DEBUG laden, ziel1: (" // + cable.getKabelpanel().getZiel1().getImageLabel().getX() // + "/" // + cable.getKabelpanel().getZiel1().getImageLabel().getY() // + ") [W=" // + cable.getKabelpanel().getZiel1().getImageLabel().getWidth() // + "; H=" // + cable.getKabelpanel().getZiel1().getImageLabel().getHeight() // + "]"); // Main.debug.println("DEBUG laden, ziel2: (" // + cable.getKabelpanel().getZiel2().getImageLabel().getX() // + "/" // + cable.getKabelpanel().getZiel2().getImageLabel().getY() // + ") [W=" // + cable.getKabelpanel().getZiel2().getImageLabel().getWidth() // + "; H=" // + cable.getKabelpanel().getZiel2().getImageLabel().getHeight() // + "]"); kabelItems.add(cable); } return true; } catch (FileNotFoundException e) { GUIErrorHandler.getGUIErrorHandler().DisplayError( messages.getString("rp_szenarioverwaltung_msg5")); e.printStackTrace(Main.debug); return false; } } public static boolean erzeugeZipArchiv(String datenOrdner, String archivDatei) { Main.debug.println("INVOKED (static) filius.rahmenprogramm.SzenarioVerwaltung, erzeugeZipArchiv("+datenOrdner+","+archivDatei+")"); FileOutputStream out; ZipOutputStream zipOut; File zipDatei; File ordner; zipDatei = new File(archivDatei); new File(zipDatei.getParent()).mkdirs(); ordner = new File(datenOrdner); if (!ordner.exists()) return false; try { zipDatei.createNewFile(); } catch (IOException e) { e.printStackTrace(Main.debug); return false; } try { out = new FileOutputStream(zipDatei); zipOut = new ZipOutputStream(out); schreibeZipDatei(zipOut, ordner.getName()+"/", ordner.getAbsolutePath()); try { zipOut.close(); out.close(); } catch (IOException e) { e.printStackTrace(Main.debug); return false; } } catch (FileNotFoundException e) { e.printStackTrace(Main.debug); return false; } return true; } private static boolean schreibeZipDatei(ZipOutputStream out, String relPfad, String datei) { Main.debug.println("INVOKED (static) filius.rahmenprogramm.SzenarioVerwaltung, schreibeZipDatei("+out+","+relPfad+","+datei+")"); File path; boolean result = true; path = new File(datei); if (path.isFile()) { return schreibeZipEntry(out, relPfad, datei); } for (File file : path.listFiles()) { if (file.isDirectory()) { result = schreibeZipDatei(out, relPfad + file.getName()+"/", file .getAbsolutePath() + "/"); } else { result = schreibeZipEntry(out, relPfad+file.getName(), file.getAbsolutePath()); } if (!result) return result; } return result; } private static boolean schreibeZipEntry(ZipOutputStream out, String relPfad, String datei) { Main.debug.println("INVOKED (static) filius.rahmenprogramm.SzenarioVerwaltung, schreibeZipEntry("+out+","+relPfad+","+datei+")"); ZipEntry zipEntry; byte[] buffer = new byte[0xFFFF]; FileInputStream fis; File quelldatei; quelldatei = new File(datei); if (!quelldatei.exists()) return false; zipEntry = new ZipEntry(relPfad); try { out.putNextEntry(zipEntry); fis = new FileInputStream(quelldatei); for (int len; (len = fis.read(buffer)) != -1;) out.write(buffer, 0, len); out.closeEntry(); } catch (Exception e) { Main.debug.println("ERROR (static): Datei "+datei+" konnte nicht zu zip-Archiv hinzugefuegt werden."); e.printStackTrace(Main.debug); return false; } return true; } public static boolean entpackeZipArchiv(String archivDatei, String zielOrdner) { Main.debug.println("INVOKED (static) filius.rahmenprogramm.SzenarioVerwaltung, entpackeZipArchiv("+archivDatei+","+zielOrdner+")"); ZipFile zf; File file; InputStream is; BufferedInputStream bis; FileOutputStream fos; BufferedOutputStream bos; file = new File(archivDatei); if (!file.exists()) { Main.debug.println("ERROR (static): " + archivDatei + " existiert nicht. Entpacken ist fehlgeschlagen!"); return false; } file = new File(zielOrdner); if (!file.exists()) { file.mkdirs(); } try { zf = new ZipFile(archivDatei); for (Enumeration<? extends ZipEntry> e = zf.entries(); e .hasMoreElements();) { ZipEntry target = e.nextElement(); file = new File(zielOrdner + target.getName()); if (target.isDirectory()) file.mkdirs(); else { is = zf.getInputStream(target); bis = new BufferedInputStream(is); new File(file.getParent()).mkdirs(); fos = new FileOutputStream(file); bos = new BufferedOutputStream(fos); final int EOF = -1; for (int c; (c = bis.read()) != EOF;) bos.write((byte) c); bos.close(); fos.close(); is.close(); bis.close(); } } zf.close(); } catch (FileNotFoundException e) { Main.debug.println("EXCEPTION (static): zipfile not found"); return false; } catch (ZipException e) { Main.debug.println("EXCEPTION (static): zip error..."); return false; } catch (IOException e) { Main.debug.println("EXCEPTION (static): IO error..."); return false; } return true; } public static boolean loescheVerzeichnisInhalt(String verzeichnis) { // Main.debug.println("INVOKED (static) filius.rahmenprogramm.SzenarioVerwaltung, loescheVerzeichnisInhalt("+verzeichnis+")"); File path; File file; File[] fileListe; path = new File(verzeichnis); if (path.exists()) { fileListe = path.listFiles(); for (int i = 0; i < fileListe.length; i++) { file = fileListe[i]; if (file.isDirectory()) { if (!loescheDateien(file.getAbsolutePath())) { Main.debug.println("ERROR (static): Ordner " + file.getAbsolutePath() + " konnte nicht geloescht werden."); return false; } } else if (!file.delete()) { Main.debug.println("ERROR (static): Datei " + file.getAbsolutePath() + " konnte nicht geloescht werden."); return false; } else { } } } return true; } public static boolean loescheDateien(String datei) { Main.debug.println("INVOKED (static) filius.rahmenprogramm.SzenarioVerwaltung, loescheDateien("+datei+")"); File path; path = new File(datei); if (!loescheVerzeichnisInhalt(datei)) return false; if (path.delete()) { return true; } else { return false; } } public static boolean kopiereVerzeichnis(String quelle, String ziel) { Main.debug.println("INVOKED (static) filius.rahmenprogramm.SzenarioVerwaltung, kopiereVerzeichnis("+quelle+","+ziel+")"); File quellOrdner, zielOrdner, tmp; quellOrdner = new File(quelle); zielOrdner = new File(ziel); if (!quellOrdner.exists()) return false; if (!zielOrdner.exists()) zielOrdner.mkdirs(); for (File file : quellOrdner.listFiles()) { if (file.isDirectory()) { tmp = new File(zielOrdner.getAbsolutePath() + "/" + file.getName()); kopiereVerzeichnis(file.getAbsolutePath(), tmp .getAbsolutePath()); } else kopiereDatei(file.getAbsolutePath(), zielOrdner .getAbsolutePath() + "/" + file.getName()); } return true; } public static boolean saveStream(InputStream source, String zieldatei) { Main.debug.println("INVOKED (static) filius.rahmenprogramm.SzenarioVerwaltung, saveStream("+source+","+zieldatei+")"); File destfile; FileOutputStream fos = null; byte[] buffer; boolean result = true; destfile = new File(zieldatei); if (source==null || destfile.exists()) result = false; else { try { fos = new FileOutputStream(destfile); buffer = new byte[0xFFFF]; for (int len; (len = source.read(buffer)) != -1;) fos.write(buffer, 0, len); } catch (IOException e) { e.printStackTrace(Main.debug); result = false; } finally { if (fos != null) try { fos.close(); } catch (IOException e) { } } } return result; } public static boolean kopiereDatei(String quelldatei, String zieldatei) { Main.debug.println("INVOKED (static) filius.rahmenprogramm.SzenarioVerwaltung, kopiereDatei("+quelldatei+","+zieldatei+")"); File srcfile, destfile; FileInputStream fis = null; FileOutputStream fos = null; byte[] buffer; boolean result = true; srcfile = new File(quelldatei); destfile = new File(zieldatei); if (!srcfile.exists() || destfile.exists()) result = false; else { try { fis = new FileInputStream(srcfile); fos = new FileOutputStream(destfile); buffer = new byte[0xFFFF]; for (int len; (len = fis.read(buffer)) != -1;) fos.write(buffer, 0, len); } catch (IOException e) { e.printStackTrace(Main.debug); result = false; } finally { if (fis != null) try { fis.close(); } catch (IOException e) { } if (fos != null) try { fos.close(); } catch (IOException e) { } } } return result; } }