/** * MailArchiver is an application that provides services for storing and managing e-mail messages through a Web Services SOAP interface. * Copyright (C) 2012 Marcio Andre Scholl Levien and Fernando Alberto Reuter Wendt and Jose Ronaldo Nogueira Fonseca Junior * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ /******************************************************************************\ * * This product was developed by * * SERVIÇO FEDERAL DE PROCESSAMENTO DE DADOS (SERPRO), * * a government company established under Brazilian law (5.615/70), * at Department of Development of Porto Alegre. * \******************************************************************************/ package serpro.mailarchiver; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.util.Map; import java.util.TreeMap; import org.apache.log4j.ConsoleAppender; import org.apache.log4j.Level; import org.apache.log4j.PatternLayout; import org.apache.log4j.net.SocketAppender; import org.apache.log4j.rolling.RollingFileAppender; import org.apache.log4j.rolling.TimeBasedRollingPolicy; import org.springframework.beans.factory.access.BeanFactoryLocator; import org.springframework.beans.factory.access.BeanFactoryReference; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.access.ContextSingletonBeanFactoryLocator; import org.springframework.web.context.request.RequestScope; import org.springframework.web.context.request.SessionScope; import com.google.common.base.Supplier; import de.schlichtherle.truezip.file.TArchiveDetector; import de.schlichtherle.truezip.file.TFile; import de.schlichtherle.truezip.fs.archive.tar.TarBZip2Driver; import de.schlichtherle.truezip.fs.archive.tar.TarDriver; import de.schlichtherle.truezip.fs.archive.tar.TarGZipDriver; import de.schlichtherle.truezip.fs.archive.zip.JarDriver; import de.schlichtherle.truezip.fs.archive.zip.ZipDriver; import de.schlichtherle.truezip.socket.sl.IOPoolLocator; import serpro.mailarchiver.domain.metaarchive.*; import serpro.mailarchiver.util.Environment; import serpro.mailarchiver.util.Logger; import serpro.mailarchiver.util.UserAppConfig; import serpro.mailarchiver.util.jdo.MetadataDumper; import serpro.mailarchiver.util.jdo.PersistenceManagerFactory; public class Main { private static final Logger log = Logger.getLocalLogger(); UserAppConfig userAppConfig; public static void main(String[] args) { try { new Main().run(); } catch(Exception ex) { log.fatal(ex, "Falha catastrófica"); } } private void run() throws Exception { setupLog(); logSystemProperties(); logSystemEnvironment(); logInternetAddresses(); logUserAppConfig(); TFile.setDefaultArchiveDetector(new TArchiveDetector(TArchiveDetector.NULL, new Object[][] { { "zip", new ZipDriver(IOPoolLocator.SINGLETON)}, { "jar", new JarDriver(IOPoolLocator.SINGLETON)}, { "tar", new TarDriver(IOPoolLocator.SINGLETON) }, { "tgz|tar.gz", new TarGZipDriver(IOPoolLocator.SINGLETON) }, { "tbz|tb2|tar.bz2", new TarBZip2Driver(IOPoolLocator.SINGLETON) }, })); final Path archiveDir = userAppConfig.SERVER.getArchiveDir(); if(Files.notExists(archiveDir)) { Files.createDirectories(archiveDir); } final Path mailDir = archiveDir.resolve("mail"); if(Files.notExists(mailDir)) { Files.createDirectories(mailDir); } final Path tempDir = archiveDir.resolve("temp"); if(Files.notExists(tempDir)) { Files.createDirectories(tempDir); } else { Files.walkFileTree(tempDir, new FileVisitor() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Files.delete(file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { log.error(exc, "temp delete failed: %s", file.toString()); return FileVisitResult.TERMINATE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { if(dir != tempDir) { Files.delete(dir); } return FileVisitResult.CONTINUE; } }); } final Path indexDir = archiveDir.resolve("index"); if(Files.notExists(indexDir)) { Files.createDirectories(indexDir); } final Path dbFile = archiveDir.resolve("metaarchive.h2.db"); if(Files.notExists(dbFile)) { InputStream is = getClass().getResourceAsStream("/serpro/mailarchiver/resources/empty_metaarchive.h2.db"); Files.copy(is, dbFile); } ConfigurableApplicationContext context = getGlobalContext(); PersistenceManagerFactory pmf = context.getBean("pmf", PersistenceManagerFactory.class); logJdoMetadata(pmf); MailArchiver mailArchiver = context.getBean("mailArchiver", MailArchiver.class); mailArchiver.init(); } private ConfigurableApplicationContext getGlobalContext() { BeanFactoryLocator bfloc = ContextSingletonBeanFactoryLocator.getInstance( "classpath:/serpro/mailarchiver/config/beanRefContext.xml"); BeanFactoryReference bfref = bfloc.useBeanFactory("global.context"); ConfigurableApplicationContext context = (ConfigurableApplicationContext) bfref.getFactory(); context.registerShutdownHook(); ConfigurableBeanFactory bf = (ConfigurableBeanFactory)context.getAutowireCapableBeanFactory(); bf.registerScope("session", new SessionScope()); bf.registerScope("request", new RequestScope()); return context; } private void setupLog() { userAppConfig = UserAppConfig.getInstance(); Exception ex1 = null, ex2 = null; try { userAppConfig.load(); } catch(Exception ex) { ex1 = ex; } for(Map.Entry logger : userAppConfig.LOG.getLoggers().entrySet()) { if(logger.getKey().equalsIgnoreCase("root")) { Logger.getRootLogger().setLevel(Level.toLevel(logger.getValue().toUpperCase())); } else { Logger.getLogger(logger.getKey()).setLevel(Level.toLevel(logger.getValue().toUpperCase())); } } PatternLayout layout = new PatternLayout(userAppConfig.LOG.getLayout()); ConsoleAppender consoleAppender = new ConsoleAppender(layout); consoleAppender.setThreshold(Level.ERROR); Logger.getRootLogger().addAppender(consoleAppender); try { Path logPath = userAppConfig.LOG.getFile(); System.out.println("logPath: " + logPath); TimeBasedRollingPolicy rollingPolicy = new TimeBasedRollingPolicy(); rollingPolicy.setFileNamePattern(logPath.toString()); rollingPolicy.activateOptions(); RollingFileAppender rollingFileAppender = new RollingFileAppender(); rollingFileAppender.setEncoding("UTF-8"); rollingFileAppender.setLayout(layout); rollingFileAppender.setRollingPolicy(rollingPolicy); rollingFileAppender.activateOptions(); Logger.getRootLogger().addAppender(rollingFileAppender); } catch(Exception ex) { ex2 = ex; } String socketHost = userAppConfig.LOG.getSocketHost(); if(!socketHost.isEmpty()) { SocketAppender socketAppender = new SocketAppender(socketHost, userAppConfig.LOG.getSocketPort()); socketAppender.setLocationInfo(true); Logger.getRootLogger().addAppender(socketAppender); } log.info("Log configurado"); if(ex1 != null) { log.error(ex1, "log setup"); } if(ex2 != null) { log.error(ex2, "log setup"); } } private void logSystemProperties() { StringBuilder sb = new StringBuilder(); sb.append("System properties\n\n"); for(Map.Entry entry : new TreeMap(System.getProperties()).entrySet()) { sb.append(entry.getKey()).append(": ").append(entry.getValue()).append("\n"); } log.info(sb.toString()); } private void logSystemEnvironment() { StringBuilder sb = new StringBuilder(); sb.append("System environment\n\n"); for(Map.Entry entry : new TreeMap(System.getenv()).entrySet()) { sb.append(entry.getKey()).append(": ").append(entry.getValue()).append("\n"); } log.info(sb.toString()); } private void logInternetAddresses() { StringBuilder sb = new StringBuilder(); sb.append("Internet addresses\n\n"); for(InetAddress address : Environment.getInstance().getInternetAddresses()) { sb.append("\t--------\n"); sb.append("\tHostAddress: ").append(address.getHostAddress()).append("\n"); sb.append("\tHostName: ").append(address.getHostName()).append("\n"); sb.append("\tCanonicalHostName: ").append(address.getCanonicalHostName()).append("\n"); } log.info(sb.toString()); } private void logUserAppConfig() { if(userAppConfig.getConfigIniPath() == null) { log.fatal("Configuration file 'config.ini' not found. Exiting now!"); System.exit(1); } else { log.info("Configuration settings read from:\n" + userAppConfig.getConfigIniPath().toAbsolutePath()); } StringBuilder sb = new StringBuilder(); sb.append("User application configuration\n\n"); sb.append("Server.port: ") .append(userAppConfig.SERVER.getPort()).append("\n") .append("Server.confidentialPort: ") .append(userAppConfig.SERVER.getConfidentialPort()).append("\n") .append("Server.archiveDir: ") .append(userAppConfig.SERVER.getArchiveDir()).append("\n") .append("MetaArchive.tcpPort: ") .append(userAppConfig.META_ARCHIVE.getTcpPort()).append("\n") .append("MetaArchive.tcpAllowOthers: ") .append(userAppConfig.META_ARCHIVE.getTcpAllowOthers()).append("\n") .append("MetaArchive.webPort: ") .append(userAppConfig.META_ARCHIVE.getWebPort()).append("\n") .append("MetaArchive.webAllowOthers: ") .append(userAppConfig.META_ARCHIVE.getWebAllowOthers()).append("\n") .append("Log.file: ") .append(userAppConfig.LOG.getFile()).append("\n") .append("Log.layout: ") .append(userAppConfig.LOG.getLayout()).append("\n") .append("Log.socketHost: ") .append(userAppConfig.LOG.getSocketHost()).append("\n") .append("Log.socketPort: ") .append(userAppConfig.LOG.getSocketPort()).append("\n") .append("Loggers\n"); for(Map.Entry logger : new TreeMap(userAppConfig.LOG.getLoggers()).entrySet()) { sb.append(" ").append(logger.getKey()).append(": ").append(logger.getValue()).append("\n"); } log.info(sb.toString()); } private void logJdoMetadata(PersistenceManagerFactory pmf) { logJdoMetadata(Setting.class, pmf); logJdoMetadata(Address.class, pmf); logJdoMetadata(FieldAddress.class, pmf); logJdoMetadata(AddressListField_Address.class, pmf); logJdoMetadata(AddressListField_Mailbox.class, pmf); logJdoMetadata(MailboxListField_Mailbox.class, pmf); logJdoMetadata(MailboxField_Mailbox.class, pmf); logJdoMetadata(AddressListField_Group_Mailbox.class, pmf); logJdoMetadata(AddressListField_Group.class, pmf); logJdoMetadata(Field.class, pmf); logJdoMetadata(UnstructuredField.class, pmf); logJdoMetadata(ContentTypeField.class, pmf); logJdoMetadata(ContentDispositionField.class, pmf); logJdoMetadata(DateTimeField.class, pmf); logJdoMetadata(AddressListField.class, pmf); logJdoMetadata(MailboxListField.class, pmf); logJdoMetadata(MailboxField.class, pmf); logJdoMetadata(Body.class, pmf); logJdoMetadata(Entity.class, pmf); logJdoMetadata(BodyEntity.class, pmf); logJdoMetadata(Message.class, pmf); logJdoMetadata(BodyPart.class, pmf); logJdoMetadata(EmbeddedMessage.class, pmf); logJdoMetadata(SingleBody.class, pmf); logJdoMetadata(TextBody.class, pmf); logJdoMetadata(BinaryBody.class, pmf); logJdoMetadata(Multipart.class, pmf); logJdoMetadata(MessageBody.class, pmf); logJdoMetadata(Folder.class, pmf); } private void logJdoMetadata(final Class clazz, final PersistenceManagerFactory pmf) { log.debug("%s JDO METADATA\n\n%s", new Supplier() { @Override public Object[] get() { return new Object[] { clazz.getName(), MetadataDumper.dump(clazz, pmf) }; } }); } }