001/**
002 * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
003 *
004 * This file is part of Dicoogle/dicoogle.
005 *
006 * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * Dicoogle/dicoogle is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package pt.ua.dicoogle.server.web.servlets;
020
021import java.io.File;
022import java.io.FileFilter;
023import java.io.IOException;
024import java.net.URI;
025import java.util.List;
026import java.util.Map;
027import java.util.HashMap;
028import java.util.Enumeration;
029import javax.servlet.http.HttpServlet;
030import javax.servlet.http.HttpServletRequest;
031import javax.servlet.http.HttpServletResponse;
032import javax.servlet.ServletOutputStream;
033
034import pt.ua.dicoogle.sdk.datastructs.Report;
035import pt.ua.dicoogle.sdk.settings.types.ServerDirectoryPath;
036import pt.ua.dicoogle.sdk.task.Task;
037import pt.ua.dicoogle.server.web.management.Services;
038import pt.ua.dicoogle.server.web.auth.Session;
039import static org.apache.commons.lang3.StringEscapeUtils.escapeHtml4;
040import pt.ua.dicoogle.plugins.PluginController;
041import pt.ua.dicoogle.server.web.management.Dicoogle;
042
043/**
044 * Provides indexing start and stop requests (scan path). Also handles requests
045 * for both indexing progress/status and server path contents.
046 * 
047 * @author António Novo <antonio.novo@ua.pt>
048 */
049@Deprecated
050public class IndexerServlet extends HttpServlet {
051
052        /**
053         * 
054         */
055        private static final long serialVersionUID = 1L;
056
057        public static final String PARAM_ACTION = "action";
058
059        public static final String ACTION_START_INDEXING = "start";
060        public static final String ACTION_STOP_INDEXING = "stop";
061        public static final String ACTION_GET_STATUS = "status";
062        public static final String ACTION_SET_INDEXING_PATH = "setpath";
063        public static final String ACTION_SET_ADVANCED_SETTINGS = "setadvancedsettings";
064        public static final String ACTION_GET_PATH_CONTENTS = "pathcontents";
065        public static final String ACTION_PARAM_PATH = "path";
066
067        /*
068         * Action codes for internal use.
069         */
070        private static final int ACTION_CODE_INVALID = 0;
071        private static final int ACTION_CODE_START_INDEXING = 1;
072        private static final int ACTION_CODE_STOP_INDEXING = 2;
073        private static final int ACTION_CODE_GET_STATUS = 3;
074        private static final int ACTION_CODE_SET_INDEXING_PATH = 4;
075        private static final int ACTION_CODE_SET_ADVANCED_SETTINGS = 5;
076        private static final int ACTION_CODE_GET_PATH_CONTENTS = 6;
077
078        /**
079         * A file filter to allow the listing of directories only.
080         */
081        private static FileFilter onlyDirectories = new FileFilter() {
082                @Override
083                public boolean accept(File pathname) {
084                        return pathname.isDirectory();
085                }
086        };
087
088        private List<Task<Report>> ongoingTasks;
089
090        public IndexerServlet() {
091                this.ongoingTasks = null;
092        }
093
094        /**
095         * Returns a XML document in String form containing the list of child
096         * directories of the specified path.
097         * 
098         * @param path
099         *            the path of the directory to retrieve the child directories
100         *            of.
101         * @return a XML document in String form containing the list of child
102         *         directories of the specified path.
103         */
104        public static String getPathContents(String path) {
105                File dir = null;
106                if (path != null)
107                        dir = new File(path);
108
109                // check if the specified path is a valid one, if not revert to "roots"
110                if ((path == null) || path.trim().isEmpty() || (dir == null)
111                                || (!dir.exists()) || (!dir.isDirectory()))
112                        path = "";
113                else
114                        path = dir.getAbsolutePath();
115
116                // guarantee that the parent path is always a valid one (never null)
117                String parentPath = "";
118                File[] childs = null;
119                if (path.isEmpty()) {
120                        // return "roots"
121                        childs = File.listRoots();
122                } else {
123                        if (dir.getParent() != null) {
124                                File parent = new File(dir.getParent());
125                                parentPath = parent.getAbsolutePath();
126                        }
127                        // list the dir children
128                        childs = dir.listFiles(onlyDirectories);
129                }
130
131                // create the XML string builder and open the xml document
132                StringBuilder xml = new StringBuilder(
133                                "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
134                xml.append("<contents path=\"");
135                xml.append(escapeHtml4(path));
136                xml.append("\" parent=\"");
137                xml.append(escapeHtml4(parentPath));
138                xml.append("\">");
139
140                // loop through all the cildren and add their path name to the XML tree
141                if (childs != null) {
142                        for (File child : childs) {
143                                String cName = child.getName();
144                                String cPath = child.getAbsolutePath();
145                                if ((cName == null) || cName.isEmpty())
146                                        cName = cPath;
147
148                                xml.append("<directory name=\"");
149                                xml.append(escapeHtml4(cName));
150                                xml.append("\" path=\"");
151                                xml.append(escapeHtml4(cPath));
152                                xml.append("\" />");
153                        }
154                }
155
156                // close the document
157                xml.append("</contents>");
158
159                // return the formed XML string
160                return xml.toString();
161        }
162
163        /**
164         * Returns a XML document in String form containing the status of the
165         * indexing.
166         * 
167         * @return a XML document in String form containing the status of the
168         *         indexing. TODO: fix
169         */
170        public String getIndexingStatus() {
171                boolean isIndexing = false;
172                int percentCompleted = 0;
173
174                if (this.ongoingTasks != null) {
175                        System.out.println("### Status ###");
176                        System.out.println("### Number of Tasks : "
177                                        + this.ongoingTasks.size());
178                        float tempProgess = 0;
179                        for (Task<Report> task : this.ongoingTasks) {
180                                if (!task.isDone())
181                                        isIndexing = true;
182                                System.out.println("##### $ Progress: " + task.getProgress());
183                                System.out.println("##### $ Completed: " + task.isDone());
184                                tempProgess += task.getProgress();
185                        }
186                        percentCompleted = (int) (tempProgess / this.ongoingTasks.size() * 100);
187                        if (isIndexing == false)
188                                this.ongoingTasks = null;
189                }
190
191                // create the XML string builder and open the xml document
192                StringBuilder xml = new StringBuilder(
193                                "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
194                xml.append("<status running=\"");
195                xml.append(Boolean.toString(isIndexing));
196                xml.append("\">");
197
198                // add percentage information
199                xml.append("<percent completed=\"");
200                xml.append(percentCompleted);
201                xml.append("\" />");
202
203                // close the document
204                xml.append("</status>");
205
206                // return the formed XML string
207                return xml.toString();
208        }
209
210        /**
211         * Writes the specified XML document in String form to a HttpServletResponse
212         * object.
213         * 
214         * @param xml
215         *            a XML document in String form.
216         * @param response
217         *            a HttpServletResponse.
218         * @throws IOException
219         *             if a error has occurred while writing the response.
220         */
221        private static void writeXMLToResponse(String xml,
222                        HttpServletResponse response, boolean allowCache)
223                        throws IOException {
224                // get the returned xml as a UTF-8 byte array
225                byte[] data = xml.getBytes("UTF-8");
226                if (data == null) {
227                        response.sendError(500,
228                                        "Could generate the resulting XML document!");
229                        return;
230                }
231
232                if (!allowCache) {
233                        response.addHeader("Cache-Control", "no-cache, must-revalidate");
234                        response.addHeader("Pragma", "no-cache");
235                }
236
237                response.setContentType("application/xml"); // set the appropriate type
238                                                                                                        // for the XML file
239                response.setContentLength(data.length); // set the document size
240                // response.setCharacterEncoding("UTF-8"); // set the apropriate
241                // encoding type
242
243                // write the XML data to the response output
244                ServletOutputStream out = response.getOutputStream();
245                out.write(data);
246                out.close();
247        }
248
249        @Override
250        protected void doGet(HttpServletRequest request,
251                        HttpServletResponse response) throws IOException {
252                // TODO validate user session credentials
253
254                // get which action to take
255                String actionStr = request.getParameter(PARAM_ACTION);
256
257                // translate each action string to a action identification
258                int action = ACTION_CODE_INVALID;
259                if (actionStr != null) {
260                        if (actionStr.equalsIgnoreCase(ACTION_START_INDEXING))
261                                action = ACTION_CODE_START_INDEXING;
262                        else if (actionStr.equalsIgnoreCase(ACTION_STOP_INDEXING))
263                                action = ACTION_CODE_STOP_INDEXING;
264                        else if (actionStr.equalsIgnoreCase(ACTION_GET_STATUS))
265                                action = ACTION_CODE_GET_STATUS;
266                        else if (actionStr.equalsIgnoreCase(ACTION_SET_INDEXING_PATH))
267                                action = ACTION_CODE_SET_INDEXING_PATH;
268                        else if (actionStr.equalsIgnoreCase(ACTION_SET_ADVANCED_SETTINGS))
269                                action = ACTION_CODE_SET_ADVANCED_SETTINGS;
270                        else if (actionStr.equalsIgnoreCase(ACTION_GET_PATH_CONTENTS))
271                                action = ACTION_CODE_GET_PATH_CONTENTS;
272                }
273
274                // response to each action accordingly
275                // fix this!
276                switch (action) {
277                case ACTION_CODE_START_INDEXING:
278                        System.err.println("Started Indexing!!");
279
280                        Dicoogle dic = Dicoogle.getInstance();
281
282                        ServerDirectoryPath thepath = (ServerDirectoryPath) dic
283                                        .getIndexingSettings().get(
284                                                        "Dicoogle Directory Monitorization");
285
286                        System.out.println("Indexing Home: " + thepath.getPath());
287                        File f = new File(thepath.getPath());
288                        URI uri = f.toURI();
289
290                        if (uri != null) {
291                                System.out.println("URI: " + uri.toString());
292                                List<Task<Report>> report = PluginController.getInstance().index(uri);
293                                System.out.println("Report Length: " + report.size());
294                                if (this.ongoingTasks == null)
295                                        this.ongoingTasks = report;
296                                else
297                                        System.out.println("More than one task in queue");
298                        } else
299                                System.out.println("Faulty");
300                        // send the client back the to previous page
301                        response.sendRedirect(Session.getLastVisitedURL(request));
302                        break;
303
304                case ACTION_CODE_STOP_INDEXING:
305                        // idx.stopIndexing();
306                        // send the client back the to previous page
307
308                        // Cancelling all Tasks
309                        if (this.ongoingTasks != null) {
310                                for (Task<Report> t : this.ongoingTasks)
311                                        t.cancel(true);
312                        }
313
314                        response.sendRedirect(Session.getLastVisitedURL(request));
315                        break;
316
317                case ACTION_CODE_GET_STATUS:
318                        // get the XML document containing contents of the requested
319                        // directory path
320                        writeXMLToResponse(getIndexingStatus(), response, false);
321                        break;
322
323                case ACTION_CODE_SET_INDEXING_PATH:
324                        String path = request.getParameter(ACTION_PARAM_PATH);
325                        if ((path == null) || (path.isEmpty())) {
326                                response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE,
327                                                "Invalid path parameter specified!");
328                                return;
329                        }
330
331                        // send the client back the to previous page
332                        response.sendRedirect(Session.getLastVisitedURL(request));
333                        break;
334
335                case ACTION_CODE_SET_ADVANCED_SETTINGS:
336                        HashMap<String, String[]> advSettings = new HashMap<String, String[]>();
337
338                        // get all the settings and their values
339                        Enumeration<String> params = request.getParameterNames();
340                        while (params.hasMoreElements()) {
341                                String name = params.nextElement();
342                                // ignore the main params (the ones that go us here)
343                                if (name.equalsIgnoreCase(PARAM_ACTION))
344                                        continue;
345                                String[] value = request.getParameterValues(name);
346                                advSettings.put(name, value);
347                        }
348
349                        // HashMap<String, Object> settings = idx.getSettings();
350                        // Services svcs = Services.getInstance();
351                        // svcs.processAdvancedSettings(settings, advSettings);
352
353                        // try to apply the settings
354                        /*
355                         * if (idx.trySettings(settings)){ idx.setSettings(settings);
356                         * svcs.saveSettings(); // send the client back the to previous page
357                         * response.sendRedirect(Session.getLastVisitedURL(request)); } else
358                         */
359                        response.sendError(HttpServletResponse.SC_BAD_REQUEST,
360                                        "Invalid parameters!");
361                        break;
362
363                case ACTION_CODE_GET_PATH_CONTENTS:
364                        path = request.getParameter(ACTION_PARAM_PATH);
365
366                        // get the XML document containing contents of the requested
367                        // directory path
368                        writeXMLToResponse(getPathContents(path), response, false);
369                        break;
370
371                default:
372                        response.sendError(HttpServletResponse.SC_BAD_REQUEST,
373                                        "Invalid action!");
374                        return;
375                }
376        }
377
378        /**
379         * Based on the request, returns a String containing a form with all the
380         * settings inputs boxes. These boxes are rendered/specified in accordance
381         * with the each setting value type reported by the plugin/service.
382         * 
383         * @param request
384         *            the servlet request object.
385         * @param brokerURL
386         *            the URL of the broker that will apply the settings after
387         *            receiving this forms post.
388         * @param elementID
389         *            the ID of this HTML form, can be null.
390         * @return a String containing the HTML structure for the form with all the
391         *         plugin advanced setting.
392         */
393        public static String getHTMLServiceAdvancedSettingsForm(
394                        HttpServletRequest request, String brokerURL, String elementID)
395                        throws IOException {
396                String result = "";
397
398                if ((elementID == null) || elementID.trim().isEmpty())
399                        result += "<form ";
400                else
401                        result += "<form id=\"" + elementID + "\" ";
402                result += "action=\"" + brokerURL + "\" method=\"get\">";
403
404                result += "<input type=\"hidden\" name=\"" + PARAM_ACTION
405                                + "\" value=\"" + ACTION_SET_ADVANCED_SETTINGS + "\" />";
406
407                result += "<table class=\"table table-hover\"><tbody>";
408
409                // HashMap<String, Object> settings = idx.getSettings();
410                // HashMap<String, String> settingsHelp = idx.getSettingsHelp();
411
412                HashMap<String, Object> settings = new HashMap<>();
413                HashMap<String, String> settingsHelp = new HashMap<>();
414
415                Services svcs = Services.getInstance();
416
417                // create a table row for each setting (includes name, value/type and
418                // help, if available)
419                for (Map.Entry<String, Object> setting : settings.entrySet()) {
420                        String key = setting.getKey();
421                        Object value = setting.getValue();
422                        String help = settingsHelp.get(key);
423
424                        result += svcs.getHTMLAdvancedSettingsFormRow(key, value, help);
425                }
426
427                result += "</tbody></table><br />";
428                result += "<input type=\"submit\" value=\"Apply Settings\" class=\"btn btn-primary\"/>";
429                result += "</form>";
430
431                return result;
432        }
433
434        @Override
435        protected void doPost(HttpServletRequest request,
436                        HttpServletResponse response) throws IOException {
437                doGet(request, response);
438        }
439}