package com.aionemu.packetsamurai.logrepo; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.Collection; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javolution.util.FastMap; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.xml.sax.SAXException; import com.aionemu.packetsamurai.PacketSamurai; import com.aionemu.packetsamurai.gui.Main; import com.aionemu.packetsamurai.gui.logrepo.LogFilesTab; /** * * @author Gilles Duboscq * */ public class LogRepository { private static String REPOSITORY_FILE = "logrepository.xml"; private File _localLogsDir; private Map<String, LogFile> _localLogs = new FastMap<String, LogFile>(); private Map<String, LogFile> _remoteLogs = new FastMap<String, LogFile>(); private int _lastId; private static class SingletonHolder { private final static LogRepository singleton = new LogRepository(); } public static LogRepository getInstance() { return SingletonHolder.singleton; } private LogRepository() { _localLogsDir = new File("./logs"); this.loadFromDatabase(); } private void loadFromDatabase() { Document doc; File file = new File(REPOSITORY_FILE); Node root = null; if (file.exists()) { try { FileInputStream fis = new FileInputStream(file); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false); factory.setIgnoringComments(true); DocumentBuilder docBuilder = factory.newDocumentBuilder(); doc = docBuilder.parse(fis); root = doc.getDocumentElement(); fis.close(); } catch (IOException e) { e.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } if (root != null) { for (Node n = root.getFirstChild(); n != null; n = n.getNextSibling()) { if (n.getNodeName().equalsIgnoreCase("local")) { this.parseLocalLogs(n); } else if (n.getNodeName().equalsIgnoreCase("remote")) { this.parseRemoteLogs(n); } } } } } @SuppressWarnings("unused") private void loadFromDisk() { this.refreshLocalLogs(); } private void parseLocalLogs(Node node) { NamedNodeMap attributes; int id; @SuppressWarnings("unused") long filesize; String uploader, filename; boolean isRemote; for (Node n = node.getFirstChild(); n != null; n = n.getNextSibling()) { if (n.getNodeName().equalsIgnoreCase("log")) { attributes = n.getAttributes(); filename = attributes.getNamedItem("filename").getNodeValue(); filesize = Long.parseLong(attributes.getNamedItem("filesize").getNodeValue()); isRemote = Boolean.parseBoolean( attributes.getNamedItem("isRemote").getNodeValue()); File file = new File(this.getLogsDir()+"/"+filename); LogFile logFile = new LogFile(file, isRemote); if (file.exists()) { if (isRemote) { id = Integer.parseInt(attributes.getNamedItem("id").getNodeValue()); uploader = attributes.getNamedItem("uploader").getNodeValue(); logFile.setRemoteUploader(uploader); logFile.setRemoteId(id); } logFile.setComments(attributes.getNamedItem("comments").getNodeValue()); this.addLocalLog(logFile); } } } } private void parseRemoteLogs(Node node) { NamedNodeMap attributes; int id; long filesize; String uploader, filename, protocol; for (Node n = node.getFirstChild(); n != null; n = n.getNextSibling()) { if (n.getNodeName().equalsIgnoreCase("log")) { attributes = n.getAttributes(); id = Integer.parseInt(attributes.getNamedItem("id").getNodeValue()); filename = attributes.getNamedItem("filename").getNodeValue(); filesize = Long.parseLong(attributes.getNamedItem("filesize").getNodeValue()); uploader = attributes.getNamedItem("uploader").getNodeValue(); LogFile logFile = new LogFile(filename, filesize, false, true); logFile.setRemoteUploader(uploader); logFile.setRemoteId(id); logFile.setComments(attributes.getNamedItem("comments").getNodeValue()); if (attributes.getNamedItem("protocol") != null) { protocol = attributes.getNamedItem("protocol").getNodeValue(); logFile.setRemoteProtocolName(protocol); // discard logs from old logger version that didnt saved the protocol (they will get refreshed from remote repo) this.addRemoteLog(logFile); } } } } public File getLogsDir() { return _localLogsDir; } public void refreshLocalLogs() { if (!_localLogsDir.isDirectory()) throw new IllegalStateException("The local logs dir must be a directory"); int size = _localLogs.size(); for (File log : _localLogsDir.listFiles(new LogFileFilter())) { if (!_localLogs.containsKey(log.getName())) { try { LogFile logFile = new LogFile(log,false); logFile.loadHeaders(); logFile.checkRemote(); this.addLocalLog(logFile); } catch(Exception e) { e.printStackTrace(); } } } if (_localLogs.size() > size) { this.runSaveDatabase(); } } public void refreshRemoteLogs() { int size = _remoteLogs.size(); RemoteLogRepositoryBackend.getInstance().updateRemoteLogsList(this.getLastId()+1); if (_remoteLogs.size() > size) { this.runSaveDatabase(); } } public void addLocalLog(LogFile logFile) { _localLogs.put(logFile.getName(), logFile); if (_remoteLogs.containsKey(logFile.getName())) { if (!_remoteLogs.get(logFile.getName()).isRemote()) { throw new IllegalStateException("This log was suposed to be remote: "+logFile.getName()); } _remoteLogs.remove(logFile.getName()); } this.compareAndSet(logFile.getRemoteId()); } public void addRemoteLog(LogFile logFile) { if (_localLogs.containsKey(logFile.getName())) { LogFile localLog = _localLogs.get(logFile.getName()); localLog.setRemote(true); this.updateLogInfo(logFile, localLog); } else { if (!_remoteLogs.containsKey(logFile.getName())) { LogFilesTab filesTab = ((Main)PacketSamurai.getUserInterface()).getLogRepoTab().getLogFilesTab(); filesTab.addLogFile(logFile); } else { LogFile localLog = _remoteLogs.get(logFile.getName()); this.updateLogInfo(logFile, localLog); } _remoteLogs.put(logFile.getName(), logFile); } this.compareAndSet(logFile.getRemoteId()); } public void updateLogInfo(LogFile srcLogFile, LogFile dstLogFile) { dstLogFile.setRemoteUploader(srcLogFile.getRemoteUploader()); dstLogFile.setComments(srcLogFile.getComments()); dstLogFile.setRemoteAnalyserBits(srcLogFile.getAnalyserBitSet()); dstLogFile.setRemoteId(srcLogFile.getRemoteId()); dstLogFile.setUploadedTime(srcLogFile.getUploadedTime()); } public Collection<LogFile> getLocalLogs() { return _localLogs.values(); } public Collection<LogFile> getRemoteLogs() { return _remoteLogs.values(); } private synchronized void compareAndSet(int id) { if (_lastId < id) { _lastId = id; } } public synchronized int getLastId() { return _lastId; } private class LogFileFilter implements FilenameFilter { public boolean accept(File arg0, String name) { if (name.endsWith(".cap") || name.endsWith(".pcap")) return true; return false; } } public void runSaveDatabase() { Thread save = new Thread ( new Runnable() { public void run() { LogRepository.this.saveDatabase(); } } ); save.start(); } private synchronized void saveDatabase() { try { TransformerFactory transformFac = TransformerFactory.newInstance(); //trans.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2"); transformFac.setAttribute("indent-number", 4); Transformer trans = transformFac.newTransformer(); trans.setOutputProperty(OutputKeys.INDENT, "yes"); // Fill Xml elements DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(true); factory.setIgnoringComments(true); DocumentBuilder docBuilder = factory.newDocumentBuilder(); Document doc = docBuilder.newDocument(); //DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //Document doc = docBuilder.newDocument(); /*OutputFormat of = new OutputFormat("XML","UTF-8",true); of.setIndent(1); of.setIndenting(true); of.setLineWidth(0);*/ Element root = doc.createElement("repository"); Element local = doc.createElement("local"); doc.appendChild(root); root.appendChild(local); Element log; for (LogFile logFile : this.getLocalLogs()) { log = doc.createElement("log"); log.setAttribute("filename",logFile.getName()); log.setAttribute("filesize",Long.toString(logFile.getSize())); log.setAttribute("isRemote",Boolean.toString(logFile.isRemote())); log.setAttribute("comments",logFile.getComments()); log.setAttribute("protocol",logFile.getProtocolName()); if (logFile.isRemote()) { log.setAttribute("uploader",logFile.getRemoteUploader()); log.setAttribute("id",Integer.toString(logFile.getRemoteId())); } local.appendChild(log); } Element remote = doc.createElement("remote"); root.appendChild(remote); for (LogFile logFile : this.getRemoteLogs()) { log = doc.createElement("log"); log.setAttribute("filename",logFile.getName()); log.setAttribute("filesize",Long.toString(logFile.getSize())); log.setAttribute("comments",logFile.getComments()); log.setAttribute("protocol",logFile.getProtocolName()); if (logFile.isRemote()) { log.setAttribute("uploader",logFile.getRemoteUploader()); log.setAttribute("id",Integer.toString(logFile.getRemoteId())); } remote.appendChild(log); } File file = new File(REPOSITORY_FILE); if (!file.exists()) { file.createNewFile(); } FileOutputStream fos = new FileOutputStream(file); DOMSource domSource = new DOMSource(doc); StreamResult output = new StreamResult(new OutputStreamWriter(fos, "UTF-8"));; trans.transform(domSource, output); fos.close(); } catch (Exception e) { e.printStackTrace(); } } }