package org.korsakow.services; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.nio.channels.FileChannel; import java.util.Date; import java.util.List; import java.util.Vector; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPathExpressionException; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.multipart.FilePart; import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; import org.apache.commons.httpclient.methods.multipart.Part; import org.apache.commons.httpclient.methods.multipart.StringPart; import org.apache.commons.httpclient.params.HttpMethodParams; import org.dsrg.soenea.service.Registry; import org.korsakow.domain.k3.importer.K3ImportException; import org.korsakow.ide.Application; import org.korsakow.ide.Build; import org.korsakow.ide.DataRegistry; import org.korsakow.ide.XPathHelper; import org.korsakow.ide.lang.LanguageBundle; import org.korsakow.ide.util.DomUtil; import org.korsakow.services.export.ExportException; import org.w3c.dom.Document; import org.xml.sax.SAXException; public class ErrorMailer { /** * * TODO: Stu: Currently, we arent grabbing the particulars of a broken video because I don't want to take care of file sizes now * * @param title * @param message * @param details * @throws IOException */ public static boolean sendError(String title, String message, Throwable details) throws Exception{ if (!Application.getInstance().showOKCancelDialog(LanguageBundle.getString("general.errormailer_confirm.title"), LanguageBundle.getString("general.errormailer_confirm.message"))) return false; File logFile = new File(Application.getLogfilename()); File projectFile = DataRegistry.getFile(); File saveDir = logFile.getParentFile(); File dumpDir = new File(saveDir, "MyBugReport"); dumpDir.mkdir(); File myProject = new File(dumpDir, "MyProject"); myProject.mkdir(); //Start dumping the thigns we always want: copy(logFile, new File(dumpDir, "Korsakow.log")); if(projectFile != null)copy(projectFile, new File(myProject, "Korsakow.krw")); File myExport = null; if(isExportException(details) != null) { myExport = new File(dumpDir, "MyExport"); myExport.mkdir(); copy(new File(isExportException(details).getProjectFile(), "project.xml"), new File(myExport, "project.xml")); } File myImport = null; if(isImportException(details) != null) { myImport = new File(dumpDir, "MyImport"); myImport.mkdir(); if(isImportException(details).getDatabaseFile() != null && isImportException(details).getDatabaseFile().exists()) { copy(isImportException(details).getDatabaseFile(), new File(myImport, "database.txt")); } if(isImportException(details).getInterfaceFile() != null && isImportException(details).getInterfaceFile().exists()) { copy(isImportException(details).getInterfaceFile(), new File(myImport, "interfaces.txt")); } } zipDirectory(dumpDir, new File(saveDir, "MyBugReport.zip")); // Level oldLEvel = Logger.getRootLogger().getLevel(); // //Disable logging while sending a message // Logger.getRootLogger().setLevel(Level.OFF); try { long time = System.currentTimeMillis(); String uuid = Application.getUUID(); String mailSubject = String.format("R%s; %s : %s", Build.getRelease(), Application.getUUID(), title); String mailContent = String.format("Release: %s\tVersion: %s\nFrom: %s\nTimestamp: %d\nDate: %s\nMessage: %s\n", Build.getRelease(), Build.getVersion(), uuid, time, new Date(time).toGMTString(), message); postErrorLog(mailSubject, mailContent, new File(saveDir, "MyBugReport.zip")); } finally { // Logger.getRootLogger().setLevel(oldLEvel); } if(myImport != null) { if(new File(myImport, "database.txt").exists())new File(myImport, "database.txt").delete(); if(new File(myImport, "interfaces.txt").exists())new File(myImport, "interfaces.txt").delete(); myImport.delete(); } if(myExport != null) { if(new File(myExport, "project.xml").exists())new File(myExport, "project.xml").delete(); myExport.delete(); } if(new File(myProject, "Korsakow.krw").exists())new File(myProject, "Korsakow.krw").delete(); if(new File(dumpDir, "Korsakow.log").exists())new File(dumpDir, "Korsakow.log").delete(); new File(saveDir, "MyBugReport.zip").delete(); myProject.delete(); dumpDir.delete(); return true; } public static ExportException isExportException(Throwable details) { if(details instanceof ExportException) return (ExportException)details; if(details.getCause() != null) return isExportException(details.getCause()); return null; } public static K3ImportException isImportException(Throwable details) { if(details instanceof K3ImportException) return (K3ImportException)details; if(details.getCause() != null) return isImportException(details.getCause()); return null; } /** * From: * http://www.exampledepot.com/egs/java.nio/File2File.html * * @param src * @param dst * @throws IOException */ public static void copy(File src, File dst) throws IOException { // Create channel on the source FileChannel srcChannel = new FileInputStream(src.getCanonicalFile()).getChannel(); // Create channel on the destination FileChannel dstChannel = new FileOutputStream(dst.getCanonicalFile()).getChannel(); // Copy file contents from source to destination dstChannel.transferFrom(srcChannel, 0, srcChannel.size()); // Close the channels srcChannel.close(); dstChannel.close(); } /** * Grabbed from: * http://www.java2s.com/Code/Java/File-Input-Output/CompressfilesusingtheJavaZIPAPI.htm * * with moderate changes (liek recursive processing) */ /** Zip the contents of the directory, and save it in the zipfile */ public static void zipDirectory(File d, File zipfile) throws IOException, IllegalArgumentException { // Check that the directory is a directory, and get its contents String base = d.getCanonicalPath(); if (!d.isDirectory()) throw new IllegalArgumentException("Not a directory: " + d.getCanonicalPath()); File[] entries = d.listFiles(); byte[] buffer = new byte[4096]; // Create a buffer for copying int bytesRead; ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipfile)); zipDir(d, base, entries, buffer, out); out.close(); } private static void zipDir(File d, String base, File[] entries, byte[] buffer, ZipOutputStream out) throws FileNotFoundException, IOException { int bytesRead; for (File f: entries) { if (f.isDirectory()) { zipDir(d, base, f.listFiles(), buffer, out); continue; } FileInputStream in = new FileInputStream(f); // Stream to read file ZipEntry entry = new ZipEntry(f.getPath().substring(base.length()).replace('\\', '/')); // Make a ZipEntry out.putNextEntry(entry); // Store entry while ((bytesRead = in.read(buffer)) != -1) out.write(buffer, 0, bytesRead); in.close(); } } public static void postErrorLog(String title, String message, File zip) throws Exception { HttpClient client = new HttpClient(); URL url = new URL(Registry.getProperty("errorLogURL")); PostMethod filePost = new PostMethod(url.toString()); List<Part> parts = new Vector<Part>(); parts.add(new StringPart(Registry.getProperty("errorLogTitleField"), title)); parts.add(new StringPart(Registry.getProperty("errorLogMessageField"), message)); parts.add(new FilePart(Registry.getProperty("errorLogZipField"), zip)); filePost.getParams().setBooleanParameter(HttpMethodParams.USE_EXPECT_CONTINUE, true); filePost.setRequestEntity(new MultipartRequestEntity(parts.toArray(new Part[] {}), filePost.getParams())); postRequest(client, filePost); } public static void postRequest(HttpClient client, PostMethod method) throws ErrorMailerException { try { client.executeMethod(method); // we ignore the http status as its not a reliable way to check return value; instead just try to read the response String response = method.getResponseBodyAsString(); Document document = DomUtil.parseXMLString(response); int statusCode = XPathHelper.xpathAsInt(document, "/response/status/code"); String message = XPathHelper.xpathAsString(document, "response/status/message"); if (statusCode != 0) { throw new ErrorMailerException(message); } } catch (HttpException e) { throw new ErrorMailerException(e); } catch (IOException e) { throw new ErrorMailerException(e); } catch (SAXException e) { throw new ErrorMailerException(e); } catch (ParserConfigurationException e) { throw new ErrorMailerException(e); } catch (XPathExpressionException e) { throw new ErrorMailerException(e); } } }