Search in sources :

Example 1 with NewsManager

use of net.i2p.router.news.NewsManager in project i2p.i2p by i2p.

the class RouterConsoleRunner method startConsole.

/**
 *  http://irc.codehaus.org/display/JETTY/Porting+to+jetty6
 *
 *<pre>
 *	Server
 *		HandlerCollection
 *			HostCheckHandler (extends GzipHandler)
 *				ContextHandlerCollection
 *					LocaleWebAppHandler (routerconsole)
 *						SessionHandler
 *						SecurityHandler
 *						ServletHandler
 *							servlets...
 *					WebAppContext (i2psnark)
 *					WebAppContext (i2ptunnel)
 *					WebAppContext (imagegen)
 *					WebAppContext (susidns)
 *					WebAppContext (susimail)
 *					WebAppContext (for each plugin with a .war)
 *			DefaultHandler
 *			RequestLogHandler (opt)
 *</pre>
 *
 *  Porting to Jetty 9:
 *
 *  http://dev.eclipse.org/mhonarc/lists/jetty-dev/msg01952.html
 *  You are missing a few facts about Jetty 9.1 ...
 *  First, there are no longer any blocking connectors.
 *  Its all async / nio connectors now. (mainly because that's the direction that the servlet api 3.1 is taking)
 *
 *  Next, there is only 1 connector.   The ServerConnector.
 *  However, it takes 1 or more ConnectionFactory implementations to know how to handle the incoming connection.
 *  We have factories for HTTP (0.9 thru 1.1), SPDY, SSL-http, and SSL-npn so far.
 *  This list of factories will expand as the future of connectivity to web servers is ever growing (think HTTP/2)
 *
 *  Use the embedded examples for help understanding this.
 *  http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java?id=jetty-9.1.0.RC0
 */
public void startConsole() {
    File workDir = new SecureDirectory(_context.getTempDir(), "jetty-work");
    boolean workDirRemoved = FileUtil.rmdir(workDir, false);
    if (!workDirRemoved)
        System.err.println("ERROR: Unable to remove Jetty temporary work directory");
    boolean workDirCreated = workDir.mkdirs();
    if (!workDirCreated)
        System.err.println("ERROR: Unable to create Jetty temporary work directory");
    // so Jetty can find WebAppConfiguration
    System.setProperty("jetty.class.path", _context.getBaseDir() + "/lib/routerconsole.jar");
    // FIXME
    // http://dev.eclipse.org/mhonarc/lists/jetty-users/msg03487.html
    // _server.setGracefulShutdown(1000);
    // In Jetty 6, QTP was not concurrent, so we switched to
    // ThreadPoolExecutor with a fixed-size queue, a set maxThreads,
    // and a RejectedExecutionPolicy of CallerRuns.
    // Unfortunately, CallerRuns causes lockups in Jetty NIO (ticket #1395)
    // In addition, no flavor of TPE gives us what QTP does:
    // - TPE direct handoff (which we were using) never queues.
    // This doesn't provide any burst management when maxThreads is reached.
    // CallerRuns was an attempt to work around that.
    // - TPE unbounded queue does not adjust the number of threads.
    // This doesn't provide automatic resource management.
    // - TPE bounded queue does not add threads until the queue is full.
    // This doesn't provide good responsiveness to even small bursts.
    // QTP adds threads as soon as the queue is non-empty.
    // QTP as of Jetty 7 uses concurrent.
    // QTP unbounded queue is the default in Jetty.
    // So switch back to QTP with a bounded queue.
    // 
    // ref:
    // http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html
    // https://wiki.eclipse.org/Jetty/Howto/High_Load
    // 
    // try {
    // ThreadPool ctp = new CustomThreadPoolExecutor();
    // // Gone in Jetty 7
    // //ctp.prestartAllCoreThreads();
    // _server.setThreadPool(ctp);
    // } catch (Throwable t) {
    // class not found...
    // System.out.println("INFO: Jetty concurrent ThreadPool unavailable, using QueuedThreadPool");
    LinkedBlockingQueue<Runnable> lbq = new LinkedBlockingQueue<Runnable>(4 * MAX_THREADS);
    // min and max threads will be reset below
    QueuedThreadPool qtp = new QueuedThreadPool(MAX_THREADS, MIN_THREADS, MAX_IDLE_TIME, lbq);
    qtp.setName(THREAD_NAME);
    qtp.setDaemon(true);
    _server = new Server(qtp);
    // }
    HandlerCollection hColl = new HandlerCollection();
    ContextHandlerCollection chColl = new ContextHandlerCollection();
    HostCheckHandler chCollWrapper = new HostCheckHandler(_context);
    chCollWrapper.setHandler(chColl);
    // gone in Jetty 7
    // _server.addHandler(hColl);
    _server.setHandler(hColl);
    hColl.addHandler(chCollWrapper);
    hColl.addHandler(new DefaultHandler());
    String log = _context.getProperty("routerconsole.log");
    if (log != null) {
        File logFile = new File(log);
        if (!logFile.isAbsolute())
            logFile = new File(_context.getLogDir(), "logs/" + log);
        try {
            RequestLogHandler rhl = new RequestLogHandler();
            rhl.setRequestLog(new NCSARequestLog(logFile.getAbsolutePath()));
            hColl.addHandler(rhl);
        } catch (Exception ioe) {
            System.err.println("ERROR: Unable to create Jetty log: " + ioe);
        }
    }
    boolean rewrite = false;
    Properties props = webAppProperties();
    if (props.isEmpty()) {
        props.setProperty(PREFIX + ROUTERCONSOLE + ENABLED, "true");
        rewrite = true;
    }
    // Get an absolute path with a trailing slash for the webapps dir
    // We assume relative to the base install dir for backward compatibility
    File app = new File(_webAppsDir);
    if (!app.isAbsolute()) {
        app = new File(_context.getBaseDir(), _webAppsDir);
        try {
            _webAppsDir = app.getCanonicalPath();
        } catch (IOException ioe) {
        }
    }
    if (!_webAppsDir.endsWith("/"))
        _webAppsDir += '/';
    Set<String> listenHosts = new HashSet<String>(8);
    HandlerWrapper rootWebApp = null;
    ServletHandler rootServletHandler = null;
    List<Connector> connectors = new ArrayList<Connector>(4);
    try {
        int boundAddresses = 0;
        SortedSet<String> addresses = Addresses.getAllAddresses();
        boolean hasIPV4 = addresses.contains("0.0.0.0");
        boolean hasIPV6 = addresses.contains("0:0:0:0:0:0:0:0");
        // add standard listeners
        int lport = 0;
        if (_listenPort != null) {
            try {
                lport = Integer.parseInt(_listenPort);
            } catch (NumberFormatException nfe) {
            }
            if (lport <= 0)
                System.err.println("Bad routerconsole port " + _listenPort);
        }
        if (lport > 0) {
            List<String> hosts = new ArrayList<String>(2);
            StringTokenizer tok = new StringTokenizer(_listenHost, " ,");
            while (tok.hasMoreTokens()) {
                String host = tok.nextToken().trim();
                try {
                    // connectors are bad
                    if ((!hasIPV6) && Addresses.isIPv6Address(host))
                        throw new IOException("IPv6 addresses unsupported");
                    if ((!hasIPV4) && Addresses.isIPv4Address(host))
                        throw new IOException("IPv4 addresses unsupported");
                    ServerSocket testSock = null;
                    try {
                        // On Windows, this was passing and Jetty was still failing,
                        // possibly due to %scope_id ???
                        // https://issues.apache.org/jira/browse/ZOOKEEPER-667
                        // so do exactly what Jetty does in SelectChannelConnector.open()
                        testSock = new ServerSocket();
                        InetSocketAddress isa = new InetSocketAddress(host, 0);
                        testSock.bind(isa);
                    } finally {
                        if (testSock != null)
                            try {
                                testSock.close();
                            } catch (IOException ioe) {
                            }
                    }
                    HttpConfiguration httpConfig = new HttpConfiguration();
                    // number of acceptors, (default) number of selectors
                    ServerConnector lsnr = new ServerConnector(_server, 1, 0, new HttpConnectionFactory(httpConfig));
                    // lsnr.setUseDirectBuffers(false);  // default true seems to be leaky
                    lsnr.setHost(host);
                    lsnr.setPort(lport);
                    // default 10 sec
                    lsnr.setIdleTimeout(90 * 1000);
                    // all with same name will use the same thread pool
                    lsnr.setName("ConsoleSocket");
                    // _server.addConnector(lsnr);
                    connectors.add(lsnr);
                    boundAddresses++;
                    hosts.add(host);
                } catch (Exception ioe) {
                    System.err.println("Unable to bind routerconsole to " + host + " port " + _listenPort + ": " + ioe);
                    System.err.println("You may ignore this warning if the console is still available at http://localhost:" + _listenPort);
                }
            }
            if (hosts.isEmpty()) {
                _context.portMapper().register(PortMapper.SVC_CONSOLE, lport);
            } else {
                // put IPv4 first
                Collections.sort(hosts, new HostComparator());
                _context.portMapper().register(PortMapper.SVC_CONSOLE, hosts.get(0), lport);
                // note that we could still fail in connector.start() below
                listenHosts.addAll(hosts);
            }
        }
        // add SSL listeners
        int sslPort = 0;
        if (_sslListenPort != null) {
            try {
                sslPort = Integer.parseInt(_sslListenPort);
            } catch (NumberFormatException nfe) {
            }
            if (sslPort <= 0)
                System.err.println("Bad routerconsole SSL port " + _sslListenPort);
        }
        if (sslPort > 0) {
            File keyStore = new File(_context.getConfigDir(), "keystore/console.ks");
            // Put the list of hosts together early, so we can put it in the selfsigned cert.
            StringTokenizer tok = new StringTokenizer(_sslListenHost, " ,");
            Set<String> altNames = new HashSet<String>(4);
            while (tok.hasMoreTokens()) {
                String s = tok.nextToken().trim();
                if (!s.equals("0.0.0.0") && !s.equals("::") && !s.equals("0:0:0:0:0:0:0:0"))
                    altNames.add(s);
            }
            String allowed = _context.getProperty(PROP_ALLOWED_HOSTS);
            if (allowed != null) {
                tok = new StringTokenizer(allowed, " ,");
                while (tok.hasMoreTokens()) {
                    altNames.add(tok.nextToken().trim());
                }
            }
            if (verifyKeyStore(keyStore, altNames)) {
                // the keystore path and password
                SslContextFactory sslFactory = new SslContextFactory(keyStore.getAbsolutePath());
                sslFactory.setKeyStorePassword(_context.getProperty(PROP_KEYSTORE_PASSWORD, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD));
                // the X.509 cert password (if not present, verifyKeyStore() returned false)
                sslFactory.setKeyManagerPassword(_context.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
                sslFactory.addExcludeProtocols(I2PSSLSocketFactory.EXCLUDE_PROTOCOLS.toArray(new String[I2PSSLSocketFactory.EXCLUDE_PROTOCOLS.size()]));
                sslFactory.addExcludeCipherSuites(I2PSSLSocketFactory.EXCLUDE_CIPHERS.toArray(new String[I2PSSLSocketFactory.EXCLUDE_CIPHERS.size()]));
                List<String> hosts = new ArrayList<String>(2);
                tok = new StringTokenizer(_sslListenHost, " ,");
                while (tok.hasMoreTokens()) {
                    String host = tok.nextToken().trim();
                    // doing it this way means we don't have to escape an IPv6 host with []
                    try {
                        // connectors are bad
                        if ((!hasIPV6) && Addresses.isIPv6Address(host))
                            throw new IOException("IPv6 addresses unsupported");
                        if ((!hasIPV4) && Addresses.isIPv4Address(host))
                            throw new IOException("IPv4 addresses unsupported");
                        ServerSocket testSock = null;
                        try {
                            // see comments above
                            testSock = new ServerSocket();
                            InetSocketAddress isa = new InetSocketAddress(host, 0);
                            testSock.bind(isa);
                        } finally {
                            if (testSock != null)
                                try {
                                    testSock.close();
                                } catch (IOException ioe) {
                                }
                        }
                        HttpConfiguration httpConfig = new HttpConfiguration();
                        httpConfig.setSecureScheme("https");
                        httpConfig.setSecurePort(sslPort);
                        httpConfig.addCustomizer(new SecureRequestCustomizer());
                        // number of acceptors, (default) number of selectors
                        ServerConnector ssll = new ServerConnector(_server, 1, 0, new SslConnectionFactory(sslFactory, "http/1.1"), new HttpConnectionFactory(httpConfig));
                        // sssll.setUseDirectBuffers(false);  // default true seems to be leaky
                        ssll.setHost(host);
                        ssll.setPort(sslPort);
                        // default 10 sec
                        ssll.setIdleTimeout(90 * 1000);
                        // all with same name will use the same thread pool
                        ssll.setName("ConsoleSocket");
                        // _server.addConnector(ssll);
                        connectors.add(ssll);
                        boundAddresses++;
                        hosts.add(host);
                    } catch (Exception e) {
                        System.err.println("Unable to bind routerconsole to " + host + " port " + sslPort + " for SSL: " + e);
                        if (SystemVersion.isGNU())
                            System.err.println("Probably because GNU classpath does not support Sun keystores");
                        System.err.println("You may ignore this warning if the console is still available at https://localhost:" + sslPort);
                    }
                }
                if (hosts.isEmpty()) {
                    _context.portMapper().register(PortMapper.SVC_HTTPS_CONSOLE, sslPort);
                } else {
                    // put IPv4 first
                    Collections.sort(hosts, new HostComparator());
                    _context.portMapper().register(PortMapper.SVC_HTTPS_CONSOLE, hosts.get(0), sslPort);
                    // note that we could still fail in connector.start() below
                    listenHosts.addAll(hosts);
                }
            } else {
                System.err.println("Unable to create or access keystore for SSL: " + keyStore.getAbsolutePath());
            }
        }
        if (boundAddresses <= 0) {
            System.err.println("Unable to bind routerconsole to any address on port " + _listenPort + (sslPort > 0 ? (" or SSL port " + sslPort) : ""));
            return;
        }
        // Each address spawns a Connector and an Acceptor thread
        // If the min is less than this, we have no thread for the handlers or the expiration thread.
        qtp.setMinThreads(MIN_THREADS + (2 * boundAddresses));
        qtp.setMaxThreads(MAX_THREADS + (2 * boundAddresses));
        File tmpdir = new SecureDirectory(workDir, ROUTERCONSOLE + "-" + (_listenPort != null ? _listenPort : _sslListenPort));
        tmpdir.mkdir();
        rootServletHandler = new ServletHandler();
        rootWebApp = new LocaleWebAppHandler(_context, "/", _webAppsDir + ROUTERCONSOLE + ".war", tmpdir, rootServletHandler);
        try {
            // Not sure who is supposed to call this, but unless we do,
            // all the jsps die NPE, because JspFactory.getDefaultContext() returns null.
            // We probably have to do this because we don't bundle the Jetty annotations jar and scanner.
            // This is only with Tomcat 8, not with the Jetty (Eclipse) jsp impl.
            // Got a clue from this ancient post for Tomcat 6:
            // https://bz.apache.org/bugzilla/show_bug.cgi?id=39804
            // see also apps/jetty/build.xml
            Class.forName("org.eclipse.jetty.apache.jsp.JettyJasperInitializer");
        } catch (ClassNotFoundException cnfe) {
            System.err.println("Warning: JettyJasperInitializer not found");
        }
        WebAppContext wac = (WebAppContext) (rootWebApp.getHandler());
        initialize(_context, wac);
        WebAppStarter.setWebAppConfiguration(wac);
        chColl.addHandler(rootWebApp);
    } catch (Exception ioe) {
        ioe.printStackTrace();
    }
    // fix up the allowed hosts set (see HostCheckHandler)
    if (listenHosts.contains("0.0.0.0") || listenHosts.contains("::") || listenHosts.contains("0:0:0:0:0:0:0:0")) {
        // empty set says all are valid
        listenHosts.clear();
    } else {
        listenHosts.add("localhost");
        listenHosts.add("127.0.0.1");
        listenHosts.add("::1");
        listenHosts.add("0:0:0:0:0:0:0:1");
        String allowed = _context.getProperty(PROP_ALLOWED_HOSTS);
        if (allowed != null) {
            StringTokenizer tok = new StringTokenizer(allowed, " ,");
            while (tok.hasMoreTokens()) {
                listenHosts.add(tok.nextToken());
            }
        }
    }
    chCollWrapper.setListenHosts(listenHosts);
    // https://bugs.eclipse.org/bugs/show_bug.cgi?id=364936
    // WARN:oejw.WebAppContext:Failed startup of context o.e.j.w.WebAppContext{/,jar:file:/.../webapps/routerconsole.war!/},/.../webapps/routerconsole.war
    // java.lang.IllegalStateException: zip file closed
    Resource.setDefaultUseCaches(false);
    try {
        // start does a mapContexts()
        _server.start();
    } catch (Throwable me) {
        // NoClassFoundDefError from a webapp is a throwable, not an exception
        System.err.println("Error starting the Router Console server: " + me);
        me.printStackTrace();
    }
    if (_server.isRunning()) {
        // Add and start the connectors one-by-one
        boolean error = false;
        for (Connector conn : connectors) {
            try {
                _server.addConnector(conn);
                // start after adding so it gets the right thread pool
                conn.start();
            } catch (Throwable me) {
                try {
                    _server.removeConnector(conn);
                } catch (Throwable t) {
                    t.printStackTrace();
                }
                System.err.println("WARNING: Error starting " + conn + ": " + me);
                me.printStackTrace();
                error = true;
            }
        }
        if (error) {
            String port = (_listenPort != null) ? _listenPort : ((_sslListenPort != null) ? _sslListenPort : Integer.toString(DEFAULT_LISTEN_PORT));
            System.err.println("WARNING: Error starting one or more listeners of the Router Console server.\n" + "If your console is still accessible at http://127.0.0.1:" + port + "/,\n" + "this may be a problem only with binding to the IPV6 address ::1.\n" + "If so, you may ignore this error, or remove the\n" + "\"::1,\" in the \"clientApp.0.args\" line of the clients.config file.");
        }
    }
    // Start all the other webapps after the server is up,
    // so things start faster.
    // Jetty 6 starts the connector before the router console is ready
    // This also prevents one webapp from breaking the whole thing
    List<String> notStarted = new ArrayList<String>();
    if (_server.isRunning()) {
        File dir = new File(_webAppsDir);
        File[] files = dir.listFiles(WAR_FILTER);
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                String appName = files[i].getName();
                appName = appName.substring(0, appName.lastIndexOf(".war"));
                String enabled = props.getProperty(PREFIX + appName + ENABLED);
                if (appName.equals("addressbook")) {
                    // addressbook.war is now empty, thread is started by SusiDNS
                    if (enabled != null) {
                        props.remove(PREFIX + "addressbook" + ENABLED);
                        rewrite = true;
                    }
                } else if (!"false".equals(enabled)) {
                    try {
                        String path = files[i].getCanonicalPath();
                        WebAppStarter.startWebApp(_context, chColl, appName, path);
                        if (enabled == null) {
                            // do this so configclients.jsp knows about all apps from reading the config
                            props.setProperty(PREFIX + appName + ENABLED, "true");
                            rewrite = true;
                        }
                    } catch (Throwable t) {
                        System.err.println("ERROR: Failed to start " + appName + ' ' + t);
                        t.printStackTrace();
                        notStarted.add(appName);
                    }
                } else {
                    notStarted.add(appName);
                }
            }
            changeState(RUNNING);
            if (_mgr != null)
                _mgr.register(this);
        }
    } else {
        System.err.println("ERROR: Router console did not start, not starting webapps");
        changeState(START_FAILED);
    }
    if (rewrite)
        storeWebAppProperties(_context, props);
    if (rootServletHandler != null && notStarted.size() > 0) {
        // map each not-started webapp to the error page
        ServletHolder noWebApp = rootServletHandler.getServlet("net.i2p.router.web.jsp.nowebapp_jsp");
        for (int i = 0; i < notStarted.size(); i++) {
            // we want a new handler for each one since if the webapp is started we remove the handler???
            try {
                if (noWebApp != null) {
                    String path = '/' + notStarted.get(i);
                    // LocaleWebAppsHandler adds a .jsp
                    rootServletHandler.addServletWithMapping(noWebApp, path + ".jsp");
                    rootServletHandler.addServletWithMapping(noWebApp, path + "/*");
                } else {
                    System.err.println("Can't find nowebapp.jsp?");
                }
            } catch (Throwable me) {
                System.err.println(me);
                me.printStackTrace();
            }
        }
    }
    Thread t = new I2PAppThread(new StatSummarizer(), "StatSummarizer", true);
    t.setPriority(Thread.NORM_PRIORITY - 1);
    t.start();
    ConsoleUpdateManager um = new ConsoleUpdateManager(_context, _mgr, null);
    um.start();
    NewsManager nm = new NewsManager(_context, _mgr, null);
    nm.startup();
    if (PluginStarter.pluginsEnabled(_context)) {
        t = new I2PAppThread(new PluginStarter(_context), "PluginStarter", true);
        t.setPriority(Thread.NORM_PRIORITY - 1);
        t.start();
    }
    // RouterAppManager registers its own hook
    if (_mgr == null)
        _context.addShutdownTask(new ServerShutdown());
    ConfigServiceHandler.registerSignalHandler(_context);
}
Also used : Server(org.eclipse.jetty.server.Server) InetSocketAddress(java.net.InetSocketAddress) ArrayList(java.util.ArrayList) ContextHandlerCollection(org.eclipse.jetty.server.handler.ContextHandlerCollection) HttpConfiguration(org.eclipse.jetty.server.HttpConfiguration) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) ServerConnector(org.eclipse.jetty.server.ServerConnector) WebAppContext(org.eclipse.jetty.webapp.WebAppContext) NewsManager(net.i2p.router.news.NewsManager) HashSet(java.util.HashSet) File(java.io.File) AbstractConnector(org.eclipse.jetty.server.AbstractConnector) ServerConnector(org.eclipse.jetty.server.ServerConnector) Connector(org.eclipse.jetty.server.Connector) ServletHandler(org.eclipse.jetty.servlet.ServletHandler) ServletHolder(org.eclipse.jetty.servlet.ServletHolder) Properties(java.util.Properties) SslConnectionFactory(org.eclipse.jetty.server.SslConnectionFactory) HandlerWrapper(org.eclipse.jetty.server.handler.HandlerWrapper) I2PAppThread(net.i2p.util.I2PAppThread) SslContextFactory(org.eclipse.jetty.util.ssl.SslContextFactory) QueuedThreadPool(org.eclipse.jetty.util.thread.QueuedThreadPool) RequestLogHandler(org.eclipse.jetty.server.handler.RequestLogHandler) NCSARequestLog(org.eclipse.jetty.server.NCSARequestLog) ContextHandlerCollection(org.eclipse.jetty.server.handler.ContextHandlerCollection) HandlerCollection(org.eclipse.jetty.server.handler.HandlerCollection) SecureRequestCustomizer(org.eclipse.jetty.server.SecureRequestCustomizer) HttpConnectionFactory(org.eclipse.jetty.server.HttpConnectionFactory) ServerSocket(java.net.ServerSocket) ConsoleUpdateManager(net.i2p.router.update.ConsoleUpdateManager) IOException(java.io.IOException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException) Constraint(org.eclipse.jetty.util.security.Constraint) DefaultHandler(org.eclipse.jetty.server.handler.DefaultHandler) I2PAppThread(net.i2p.util.I2PAppThread) StringTokenizer(java.util.StringTokenizer) SecureDirectory(net.i2p.util.SecureDirectory)

Example 2 with NewsManager

use of net.i2p.router.news.NewsManager in project i2p.i2p by i2p.

the class NewsFeedHelper method getEntries.

/**
 *  @param max less than or equal to zero means all
 *  @param ageLimit time before now, less than or equal to zero means all (after the first)
 *  @return non-null, "" if none
 */
static String getEntries(I2PAppContext ctx, int start, int max, long ageLimit) {
    if (max <= 0)
        max = Integer.MAX_VALUE;
    StringBuilder buf = new StringBuilder(512);
    List<NewsEntry> entries = Collections.emptyList();
    ClientAppManager cmgr = ctx.clientAppManager();
    if (cmgr != null) {
        NewsManager nmgr = (NewsManager) cmgr.getRegisteredApp(NewsManager.APP_NAME);
        if (nmgr != null) {
            entries = nmgr.getEntries();
            NewsEntry init = nmgr.getInitialNews();
            if (init != null) {
                // crude check to see if it's already in there
                if (entries.size() != 1 || !DataHelper.eq(entries.get(0).title, init.title))
                    if (entries.isEmpty())
                        // in case it was an emtpyList
                        entries = Collections.singletonList(init);
                    else
                        entries.add(init);
            }
        }
    }
    if (!entries.isEmpty()) {
        DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT);
        // the router sets the JVM time zone to UTC but saves the original here so we can get it
        fmt.setTimeZone(SystemVersion.getSystemTimeZone(ctx));
        int i = 0;
        for (NewsEntry entry : entries) {
            if (i < start)
                continue;
            if (i > start && entry.updated > 0 && ageLimit > 0 && entry.updated < ctx.clock().now() - ageLimit)
                break;
            buf.append("<div class=\"newsentry\"><h3>");
            if (entry.updated > 0) {
                Date date = new Date(entry.updated);
                buf.append("<span class=\"newsDate\">").append(fmt.format(date)).append("</span> ");
            }
            if (entry.link != null)
                buf.append("<a href=\"").append(DataHelper.escapeHTML(entry.link)).append("\">");
            buf.append(entry.title);
            if (entry.link != null)
                buf.append("</a>");
            if (entry.authorName != null) {
                // FIXME translate
                buf.append(" <span class=\"newsAuthor\" title=\"Post author\"><i>").append(DataHelper.escapeHTML(entry.authorName)).append("</i></span>\n");
            }
            buf.append("</h3>\n<div class=\"newscontent\">\n").append(entry.content).append("\n</div></div>\n");
            if (++i >= start + max)
                break;
        }
    }
    return buf.toString();
}
Also used : DateFormat(java.text.DateFormat) NewsManager(net.i2p.router.news.NewsManager) NewsEntry(net.i2p.router.news.NewsEntry) Date(java.util.Date) ClientAppManager(net.i2p.app.ClientAppManager)

Example 3 with NewsManager

use of net.i2p.router.news.NewsManager in project i2p.i2p by i2p.

the class NewsFetcher method processSU3.

/**
 *  Process the fetched su3 news file _tempFile.
 *  Handles 3 types of contained files: xml.gz (preferred), xml, and html (old format fake xml)
 *
 *  @return the temp file contining the HTML-format news.xml
 *  @since 0.9.17
 */
private File processSU3() throws IOException {
    SU3File su3 = new SU3File(_context, _tempFile);
    // real xml, maybe gz, maybe not
    File to1 = new File(_context.getTempDir(), "tmp-" + _context.random().nextInt() + ".xml");
    // real xml
    File to2 = new File(_context.getTempDir(), "tmp2-" + _context.random().nextInt() + ".xml");
    try {
        su3.verifyAndMigrate(to1);
        int type = su3.getFileType();
        if (su3.getContentType() != SU3File.CONTENT_NEWS)
            throw new IOException("bad content type: " + su3.getContentType());
        if (type == SU3File.TYPE_HTML)
            return to1;
        if (type != SU3File.TYPE_XML && type != SU3File.TYPE_XML_GZ)
            throw new IOException("bad file type: " + type);
        File xml;
        if (type == SU3File.TYPE_XML_GZ) {
            gunzip(to1, to2);
            xml = to2;
            to1.delete();
        } else {
            xml = to1;
        }
        NewsXMLParser parser = new NewsXMLParser(_context);
        Node root = parser.parse(xml);
        xml.delete();
        NewsMetadata data = parser.getMetadata();
        List<NewsEntry> entries = parser.getEntries();
        // add entries to the news manager
        ClientAppManager cmgr = _context.clientAppManager();
        if (cmgr != null) {
            NewsManager nmgr = (NewsManager) cmgr.getRegisteredApp(NewsManager.APP_NAME);
            if (nmgr != null) {
                nmgr.addEntries(entries);
                List<Node> nodes = NewsXMLParser.getNodes(root, "entry");
                nmgr.storeEntries(nodes);
            }
        }
        // Persist any new CRL entries
        List<CRLEntry> crlEntries = parser.getCRLEntries();
        if (crlEntries != null)
            persistCRLEntries(crlEntries);
        else
            _log.info("No CRL entries found in news feed");
        // Block any new blocklist entries
        BlocklistEntries ble = parser.getBlocklistEntries();
        if (ble != null && ble.isVerified())
            processBlocklistEntries(ble);
        else
            _log.info("No blocklist entries found in news feed");
        // store entries and metadata in old news.xml format
        String sudVersion = su3.getVersionString();
        String signingKeyName = su3.getSignerString();
        File to3 = new File(_context.getTempDir(), "tmp3-" + _context.random().nextInt() + ".xml");
        outputOldNewsXML(data, entries, sudVersion, signingKeyName, to3);
        return to3;
    } finally {
        to2.delete();
    }
}
Also used : NewsMetadata(net.i2p.router.news.NewsMetadata) Node(org.cybergarage.xml.Node) IOException(java.io.IOException) CRLEntry(net.i2p.router.news.CRLEntry) SU3File(net.i2p.crypto.SU3File) NewsEntry(net.i2p.router.news.NewsEntry) ClientAppManager(net.i2p.app.ClientAppManager) NewsXMLParser(net.i2p.router.news.NewsXMLParser) NewsManager(net.i2p.router.news.NewsManager) BlocklistEntries(net.i2p.router.news.BlocklistEntries) SU3File(net.i2p.crypto.SU3File) SecureFile(net.i2p.util.SecureFile) File(java.io.File)

Example 4 with NewsManager

use of net.i2p.router.news.NewsManager in project i2p.i2p by i2p.

the class SummaryBarRenderer method renderNewsHeadingsHTML.

/**
 * @since 0.9.1
 */
public String renderNewsHeadingsHTML() {
    if (_helper == null)
        return "";
    NewsHelper newshelper = _helper.getNewsHelper();
    if (newshelper == null || newshelper.shouldShowNews())
        return "";
    StringBuilder buf = new StringBuilder(512);
    String consoleNonce = CSSHelper.getNonce();
    if (consoleNonce != null) {
        // Set up title and pre-headings stuff.
        // buf.append("<h3><a href=\"/configupdate\">")
        buf.append("<h3><a href=\"/news\">").append(_t("News &amp; Updates")).append("</a></h3><hr class=\"b\"><div class=\"sb_newsheadings\">\n");
        // Get news content.
        List<NewsEntry> entries = Collections.emptyList();
        ClientAppManager cmgr = _context.clientAppManager();
        if (cmgr != null) {
            NewsManager nmgr = (NewsManager) cmgr.getRegisteredApp(NewsManager.APP_NAME);
            if (nmgr != null)
                entries = nmgr.getEntries();
        }
        if (!entries.isEmpty()) {
            buf.append("<table>\n");
            DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT);
            // the router sets the JVM time zone to UTC but saves the original here so we can get it
            fmt.setTimeZone(SystemVersion.getSystemTimeZone(_context));
            int i = 0;
            // show a min of 1, max of 3, none older than 60 days over min
            final int min = 1;
            final int max = 3;
            for (NewsEntry entry : entries) {
                if (i >= min && entry.updated > 0 && entry.updated < _context.clock().now() - 60 * 24 * 60 * 60 * 1000L)
                    break;
                buf.append("<tr><td><a href=\"/?news=1&amp;consoleNonce=").append(consoleNonce).append("\"");
                if (entry.updated > 0) {
                    Date date = new Date(entry.updated);
                    buf.append(" title=\"").append(_t("Published")).append(": ").append(fmt.format(date)).append("\"");
                }
                buf.append(">");
                buf.append(entry.title).append("</a></td></tr>\n");
                if (++i >= max)
                    break;
            }
            buf.append("</table>\n");
        } else {
            buf.append("<center><i>").append(_t("none")).append("</i></center>");
        }
        // Add post-headings stuff.
        // buf.append("<a href=\"/news\">")
        // .append(_t("Show all news"))
        // .append("</a>\n");
        buf.append("</div>\n");
    }
    return buf.toString();
}
Also used : NewsHelper(net.i2p.router.web.NewsHelper) DateFormat(java.text.DateFormat) NewsManager(net.i2p.router.news.NewsManager) NewsEntry(net.i2p.router.news.NewsEntry) Date(java.util.Date) ClientAppManager(net.i2p.app.ClientAppManager)

Aggregations

NewsManager (net.i2p.router.news.NewsManager)4 ClientAppManager (net.i2p.app.ClientAppManager)3 NewsEntry (net.i2p.router.news.NewsEntry)3 File (java.io.File)2 IOException (java.io.IOException)2 DateFormat (java.text.DateFormat)2 Date (java.util.Date)2 UnsupportedEncodingException (java.io.UnsupportedEncodingException)1 InetSocketAddress (java.net.InetSocketAddress)1 ServerSocket (java.net.ServerSocket)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 Properties (java.util.Properties)1 StringTokenizer (java.util.StringTokenizer)1 LinkedBlockingQueue (java.util.concurrent.LinkedBlockingQueue)1 SU3File (net.i2p.crypto.SU3File)1 BlocklistEntries (net.i2p.router.news.BlocklistEntries)1 CRLEntry (net.i2p.router.news.CRLEntry)1 NewsMetadata (net.i2p.router.news.NewsMetadata)1 NewsXMLParser (net.i2p.router.news.NewsXMLParser)1