001/*
002 * #%L
003 * Netarchivesuite - heritrix 3 monitor
004 * %%
005 * Copyright (C) 2005 - 2018 The Royal Danish Library, 
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023
024package dk.netarkivet.heritrix3.monitor.resources;
025
026import java.io.IOException;
027import java.util.ArrayList;
028import java.util.HashMap;
029import java.util.Iterator;
030import java.util.List;
031import java.util.Locale;
032import java.util.Map;
033
034import javax.servlet.ServletContext;
035import javax.servlet.ServletOutputStream;
036import javax.servlet.http.HttpServletRequest;
037import javax.servlet.http.HttpServletResponse;
038
039import com.antiaction.common.filter.Caching;
040import com.antiaction.common.templateengine.TemplateBuilderFactory;
041
042import dk.netarkivet.common.utils.Settings;
043import dk.netarkivet.harvester.HarvesterSettings;
044import dk.netarkivet.harvester.datamodel.HarvestChannel;
045import dk.netarkivet.heritrix3.monitor.Heritrix3JobMonitor;
046import dk.netarkivet.heritrix3.monitor.Heritrix3JobMonitorThread;
047import dk.netarkivet.heritrix3.monitor.HistoryServlet;
048import dk.netarkivet.heritrix3.monitor.NASEnvironment;
049import dk.netarkivet.heritrix3.monitor.NASUser;
050import dk.netarkivet.heritrix3.monitor.ResourceAbstract;
051import dk.netarkivet.heritrix3.monitor.ResourceManagerAbstract;
052import dk.netarkivet.heritrix3.monitor.HttpLocaleHandler.HttpLocale;
053
054public class IndexResource implements ResourceAbstract {
055
056    private NASEnvironment environment;
057
058    protected int R_INDEX = -1;
059
060    @Override
061    public void resources_init(NASEnvironment environment) {
062        this.environment = environment;
063    }
064
065    @Override
066    public void resources_add(ResourceManagerAbstract resourceManager) {
067        R_INDEX = resourceManager.resource_add(this, "/", false);
068    }
069
070    @Override
071    public void resource_service(ServletContext servletContext, NASUser nas_user, HttpServletRequest req, HttpServletResponse resp, HttpLocale httpLocale, int resource_id, List<Integer> numerics, String pathInfo) throws IOException {
072        if (NASEnvironment.contextPath == null) {
073            NASEnvironment.contextPath = req.getContextPath();
074        }
075        if (NASEnvironment.servicePath == null) {
076            NASEnvironment.servicePath = req.getContextPath() + req.getServletPath() + "/";
077        }
078        String method = req.getMethod().toUpperCase();
079        if (resource_id == R_INDEX) {
080            if ("GET".equals(method)) {
081                index(req, resp, httpLocale, numerics);
082            }
083        }
084    }
085
086    public static class HarvestChannelStructure {
087        public HarvestChannel hc;
088        public List<Heritrix3JobMonitor> h3JobList = new ArrayList<Heritrix3JobMonitor>();
089        public HarvestChannelStructure(HarvestChannel hc) {
090            this.hc = hc;
091        }
092    }
093
094    public void index(HttpServletRequest req, HttpServletResponse resp, HttpLocale httpLocale, List<Integer> numerics) throws IOException {
095        Locale locale = httpLocale.locale;
096        resp.setContentType("text/html; charset=UTF-8");
097        ServletOutputStream out = resp.getOutputStream();
098        Caching.caching_disable_headers(resp);
099
100        TemplateBuilderFactory<MasterTemplateBuilder> masterTplBuilderFactory = TemplateBuilderFactory.getInstance(environment.templateMaster, "master.tpl", "UTF-8", MasterTemplateBuilder.class);
101        MasterTemplateBuilder masterTplBuilder = masterTplBuilderFactory.getTemplateBuilder();
102
103        StringBuilder sb = new StringBuilder();
104
105        List<Heritrix3JobMonitor> h3JobsList = environment.h3JobMonitorThread.getRunningH3Jobs();
106        Heritrix3JobMonitor h3Job;
107
108        // Restart H3 job monitor thread.
109        String action = req.getParameter("action");
110        if (action != null && action.length() > 0) {
111            if ("restart".equalsIgnoreCase(action)) {
112                if (environment.h3JobMonitorThread.thread != null) {
113                    synchronized (environment.h3JobMonitorThread.thread) {
114                        if (!environment.h3JobMonitorThread.thread.isAlive()) {
115                            // The h3JobMonitorThread is dead. Restart it.
116                            Heritrix3JobMonitorThread newH3JobMonitor = new Heritrix3JobMonitorThread(environment);
117                            try {
118                                newH3JobMonitor.init();
119                                newH3JobMonitor.start();
120                            }
121                            catch (Throwable t) {
122                                t.printStackTrace();
123                            }
124                            environment.h3JobMonitorThread = newH3JobMonitor; 
125                        }
126                    }
127                }
128            }
129        }
130
131        sb.append("<a href=\"");
132        sb.append(NASEnvironment.servicePath);
133        sb.append("config/");
134        sb.append("\" class=\"btn btn-default\">");
135        sb.append(environment.I18N.getString(locale, "configure"));
136        sb.append("</a>");
137        sb.append("<br />\n");
138        sb.append("<br />\n");
139
140        // Check if H3 job monitor thread is still running.
141        if (environment.h3JobMonitorThread.thread != null) {
142            synchronized (environment.h3JobMonitorThread.thread) {
143                if (!environment.h3JobMonitorThread.thread.isAlive()) {
144                    sb.append("The H3 job monitor thread is not running anymore. ");
145                    sb.append("<a href=\"?action=restart");
146                    sb.append("\"");
147                    sb.append(" class=\"btn btn-default\">");
148                    sb.append("Restart");
149                    sb.append("</a>");
150                    sb.append("<br />\n");
151                    sb.append("<pre>");
152                    sb.append("Stacktrace[]:");
153                    HistoryServlet.throwable_stacktrace_dump(environment.h3JobMonitorThread.throwable, sb);
154                    sb.append("</pre>");
155                    sb.append("<br />\n");
156                    sb.append("<br />\n");
157                }
158            }
159        }
160
161        List<HarvestChannelStructure> hcList = new ArrayList<HarvestChannelStructure>();
162        Map<String, HarvestChannelStructure> hcMap = new HashMap<String, HarvestChannelStructure>();
163
164        Iterator<HarvestChannel> hcIter = Heritrix3JobMonitorThread.harvestChannelDAO.getAll(true);
165        HarvestChannel hc;
166        HarvestChannelStructure hcs;
167        while (hcIter.hasNext()) {
168            hc = hcIter.next();
169            hcs = new HarvestChannelStructure(hc);
170            hcList.add(hcs);
171            hcMap.put(hc.getName(), hcs);
172        }
173
174        Iterator<Heritrix3JobMonitor> j3JobIter = h3JobsList.iterator();
175        String channelStr;
176        while (j3JobIter.hasNext()) {
177            h3Job = j3JobIter.next();
178            if (h3Job.job != null) {
179                channelStr = h3Job.job.getChannel();
180                if (channelStr != null) {
181                    hcs = hcMap.get(channelStr);
182                    hcs.h3JobList.add(h3Job);
183                }
184            }
185        }
186
187        for (int i=0; i<hcList.size(); ++i) {
188            hcs = hcList.get(i);
189            sb.append("<h5>");
190            sb.append(hcs.hc.getName());
191            if (hcs.hc.isDefault()) {
192                sb.append("*");
193            }
194            sb.append("&nbsp;");
195            sb.append("(");
196            sb.append(environment.I18N.getString(locale, "harvest.channel.type"));
197            sb.append(": ");
198            if (hcs.hc.isSnapshot()) {
199                sb.append(environment.I18N.getString(locale, "harvest.channel.type.broad"));
200            } else {
201                sb.append(environment.I18N.getString(locale, "harvest.channel.type.focused"));
202            }
203            sb.append(")");
204            sb.append("</h5>\n");
205            if (hcs.h3JobList.size() > 0) {
206                for (int j=0; j<hcs.h3JobList.size(); ++j) {
207                    h3Job = hcs.h3JobList.get(j);
208                    if (j > 0) {
209                        sb.append("&nbsp;");
210                    }
211                    sb.append("<a href=\"");
212                    sb.append(NASEnvironment.servicePath);
213                    sb.append("job/");
214                    sb.append(h3Job.jobId);
215                    sb.append("/");
216                    sb.append("\" class=\"btn btn-default\">");
217                    sb.append("Job ");
218                    sb.append(h3Job.jobId);
219                    long lines = (h3Job.idxFile.length() / 8) - 1;
220                    if (lines > 0) {
221                        sb.append(" (");
222                        sb.append(lines);
223                        sb.append(")");
224                    }
225                    sb.append("</a>\n");
226                }
227            } else {
228                sb.append("<p>");
229                sb.append(environment.I18N.getString(locale, "running.jobs.monitor.not.on.this.channel"));
230                sb.append("</p>\n");
231            }
232        }
233
234        StringBuilder menuSb = masterTplBuilder.buildMenu(new StringBuilder(), req, locale, null);
235        //String url = req.getPathInfo();
236        //HTMLUtils.generateNavigationTree(menuSb, url, locale);
237
238        masterTplBuilder.insertContent("H3 Remote Access", menuSb.toString(), httpLocale.generateLanguageLinks(),
239                        environment.I18N.getString(locale, "pagetitle;h3.remote.access"), sb.toString(),
240                        "<meta http-equiv=\"refresh\" content=\""+Settings.get(HarvesterSettings.HARVEST_MONITOR_REFRESH_INTERVAL)+"\"/>\n").write(out);
241
242        out.flush();
243        out.close();
244    }
245
246}