From 8687ae0e8e7f6cf8028d542ea833d7bb691ad604 Mon Sep 17 00:00:00 2001 From: Michael Peter Christen Date: Mon, 9 Feb 2026 23:54:34 +0100 Subject: Renamed Table_API_p.html -> Automation_p.html --- htroot/Automation_p.html | 292 ++++++++++++++ htroot/CrawlProfileEditor_p.html | 2 +- htroot/CrawlStartSite.html | 2 +- htroot/IndexImportMediawiki_p.html | 2 +- htroot/Table_API_p.html | 293 -------------- htroot/env/templates/header.template | 2 +- locales/de.lng | 4 +- locales/es.lng | 2 +- locales/fr.lng | 4 +- locales/it.lng | 2 +- locales/ja.lng | 2 +- locales/master.lng.xlf | 4 +- locales/ru.lng | 4 +- locales/tr.lng | 4 +- locales/uk.lng | 4 +- locales/zh.lng | 4 +- source/net/yacy/htroot/Automation_p.java | 648 +++++++++++++++++++++++++++++++ source/net/yacy/htroot/Table_API_p.java | 648 ------------------------------- 18 files changed, 961 insertions(+), 962 deletions(-) create mode 100644 htroot/Automation_p.html delete mode 100644 htroot/Table_API_p.html create mode 100644 source/net/yacy/htroot/Automation_p.java delete mode 100644 source/net/yacy/htroot/Table_API_p.java diff --git a/htroot/Automation_p.html b/htroot/Automation_p.html new file mode 100644 index 000000000..75a39da25 --- /dev/null +++ b/htroot/Automation_p.html @@ -0,0 +1,292 @@ + + + + YaCy '#[clientname]#': Automation + + #%env/templates/metas.template%# + + + + + + +
+ #(inline)##%env/templates/header.template%# +

Process Automation

+

This table shows actions that had been issued on the YaCy interface. + These recorded actions can be used to repeat specific actions and to send them + to a scheduler for a periodic execution. +

::#(/inline)# + +
+API +The information that is presented on this page can also be retrieved as XML. +Click the API icon to see the XML. +To see a list of all APIs, please visit the API wiki page. +
+ + #(showtable)#:: +
+ +
+ Recorded Actions +
+ + #(navigation)# + :: + #(left)#no previous page::previous page#(/left)# + #[startRecord]#-#[to]# of #[of]# + #(right)#no next page::next page#(/right)# + + #(/navigation)# + + + + + + + + + +
+
+ + + + + + + + + + + + #(inline)#::#(/inline)# + + #{list}# + + + + + + + + + + + #(inline)#::#(/inline)# + + #{/list}# +
+ Type + #(sortedByType)#::#(/sortedByType)# + + Comment + #(sortedByComment)#::#(/sortedByComment)# + + Call Count + #(sortedByApiCallCount)#::#(/sortedByApiCallCount)# + + Recording Date + #(sortedByDateRecording)#::#(/sortedByDateRecording)# + + Last Exec Date + #(sortedByDateLastExec)#::#(/sortedByDateLastExec)# + + Next Exec Date + #(sortedByDateNextExec)#::#(/sortedByDateNextExec)# + #(hasEditableNextExecDate)#:: + #(/hasEditableNextExecDate)# + Event TriggerSchedulerURL
#[type]# + #(isCrawlerStart)#::

+ ::

+ + + + + #(/isCrawlerStart)#
#[comment]##[callcount]##[dateRecording]##[dateLastExec]##(editableDateNext)# #[dateNextExec]# + :: + #(dateFormatError)#::#(/dateFormatError)# + #(dateBeforeNowError)#::#(/dateBeforeNowError)# + #(/editableDateNext)# + + #(event)# + + :: + + +
+ + + +
+ #(/event)# +
+ #(scheduler)# + + :: + + +
+ + + +
+ #(/scheduler)# +
#[url]#
+
+
+ + + + +
+     +     +
+
+ + +
+ #(hasEditableNextExecDate)#:: +
+ +
+ #(/hasEditableNextExecDate)# + +
+ #(/showtable)# + #(showexec)#:: +
+
+ + + + + + + #{list}# + + + + + #{/list}# +
StatusURL
#[status]##[url]#
+
+
+ + #(/showexec)# + #(showschedulerhint)#:: + Scheduled actions are executed after the next execution date has arrived within a time frame of #[tfminutes]# minutes. + #(/showschedulerhint)# + #(inline)##%env/templates/footer.template%#::#(/inline)# +
+ + + diff --git a/htroot/CrawlProfileEditor_p.html b/htroot/CrawlProfileEditor_p.html index 970ca7a44..d40d16f35 100644 --- a/htroot/CrawlProfileEditor_p.html +++ b/htroot/CrawlProfileEditor_p.html @@ -12,7 +12,7 @@

Crawl Scheduler

Scheduled Crawls can be modified in this table

- +

Crawl Profile Editor

Crawl profiles hold information about a crawl process that is currently ongoing.

diff --git a/htroot/CrawlStartSite.html b/htroot/CrawlStartSite.html index eb09dd90a..01d28f85c 100644 --- a/htroot/CrawlStartSite.html +++ b/htroot/CrawlStartSite.html @@ -110,7 +110,7 @@
  • High Speed Crawling

    A 'shallow crawl' which is not limited to a single host (or site) can extend the pages per minute (ppm) rate to unlimited documents per minute when the number of target hosts is high. This can be done using the Expert Crawl Start servlet.
  • -
  • Scheduler Steering

    The scheduler on crawls can be changed or removed using the API Steering.
  • +
  • Scheduler Steering

    The scheduler on crawls can be changed or removed using Automation.
  • #%env/templates/footer.template%# diff --git a/htroot/IndexImportMediawiki_p.html b/htroot/IndexImportMediawiki_p.html index 5d3e5f92c..6c69354a7 100644 --- a/htroot/IndexImportMediawiki_p.html +++ b/htroot/IndexImportMediawiki_p.html @@ -54,7 +54,7 @@
    When checked, the dump file is imported only if its last modified date is unknown or is after the last import execution date on this same file - (see recorded API calls with the "dump" type). + (see Automation with the "dump" type).
    diff --git a/htroot/Table_API_p.html b/htroot/Table_API_p.html deleted file mode 100644 index e63c45ca0..000000000 --- a/htroot/Table_API_p.html +++ /dev/null @@ -1,293 +0,0 @@ - - - - YaCy '#[clientname]#': Peer Steering - - #%env/templates/metas.template%# - - - - - - -
    - #(inline)##%env/templates/header.template%# -

    Process Scheduler

    -

    This table shows actions that had been issued on the YaCy interface - to change the configuration or to request crawl actions. - These recorded actions can be used to repeat specific actions and to send them - to a scheduler for a periodic execution. -

    ::#(/inline)# - -
    -API -The information that is presented on this page can also be retrieved as XML. -Click the API icon to see the XML. -To see a list of all APIs, please visit the API wiki page. -
    - - #(showtable)#:: -
    - -
    - Recorded Actions -
    - - #(navigation)# - :: - #(left)#no previous page::previous page#(/left)# - #[startRecord]#-#[to]# of #[of]# - #(right)#no next page::next page#(/right)# - - #(/navigation)# - - - - - - - - - -
    -
    - - - - - - - - - - - - #(inline)#::#(/inline)# - - #{list}# - - - - - - - - - - - #(inline)#::#(/inline)# - - #{/list}# -
    - Type - #(sortedByType)#::#(/sortedByType)# - - Comment - #(sortedByComment)#::#(/sortedByComment)# - - Call Count - #(sortedByApiCallCount)#::#(/sortedByApiCallCount)# - - Recording Date - #(sortedByDateRecording)#::#(/sortedByDateRecording)# - - Last Exec Date - #(sortedByDateLastExec)#::#(/sortedByDateLastExec)# - - Next Exec Date - #(sortedByDateNextExec)#::#(/sortedByDateNextExec)# - #(hasEditableNextExecDate)#:: - #(/hasEditableNextExecDate)# - Event TriggerSchedulerURL
    #[type]# - #(isCrawlerStart)#::

    - ::

    - - - - - #(/isCrawlerStart)#
    #[comment]##[callcount]##[dateRecording]##[dateLastExec]##(editableDateNext)# #[dateNextExec]# - :: - #(dateFormatError)#::#(/dateFormatError)# - #(dateBeforeNowError)#::#(/dateBeforeNowError)# - #(/editableDateNext)# - - #(event)# - - :: - - -
    - - - -
    - #(/event)# -
    - #(scheduler)# - - :: - - -
    - - - -
    - #(/scheduler)# -
    #[url]#
    -
    -
    - - - - -
    -     -     -
    -
    - - -
    - #(hasEditableNextExecDate)#:: -
    - -
    - #(/hasEditableNextExecDate)# - -
    - #(/showtable)# - #(showexec)#:: -
    -
    - - - - - - - #{list}# - - - - - #{/list}# -
    StatusURL
    #[status]##[url]#
    -
    -
    - - #(/showexec)# - #(showschedulerhint)#:: - Scheduled actions are executed after the next execution date has arrived within a time frame of #[tfminutes]# minutes. - #(/showschedulerhint)# - #(inline)##%env/templates/footer.template%#::#(/inline)# -
    - - - diff --git a/htroot/env/templates/header.template b/htroot/env/templates/header.template index 360e94e52..be45a5ac2 100644 --- a/htroot/env/templates/header.template +++ b/htroot/env/templates/header.template @@ -213,8 +213,8 @@
  • Production

  • Crawler
  • AI Lab
  • +
  • Automation
  • YaCy Packs & Import/Export
  • -
  • Process Scheduler
  • Content Semantic
  • Target Analysis
  • diff --git a/locales/de.lng b/locales/de.lng index 054488687..41cc5965d 100644 --- a/locales/de.lng +++ b/locales/de.lng @@ -1387,7 +1387,7 @@ A 'shallow crawl' which is not limited to a single host (or site)==Ein 'oberflä can extend the pages per minute (ppm) rate to unlimited documents per minute when the number of target hosts is high.==kann die Anzahl der Seiten pro Minute (ppm) auf unendlich viele Dokumente pro Minute erweitern wenn die Anzahl der Ziel Hosts hoch ist. This can be done using the Expert Crawl Start servlet.==Das kann erreicht werden durch Verwendung des Crawl Start (Expert) Servlets. >Scheduler Steering<==>Geplante Steuerung< -The scheduler on crawls can be changed or removed using the API Steering.==Die geplante Ausführung von Crawls kann geändert oder entfernt werden mit der API Aktionen Steuerung. +The scheduler on crawls can be changed or removed using Automation.==Die geplante Ausführung von Crawls kann geändert oder entfernt werden mit Automatisierung. #----------------------------- #File: Help.html @@ -3248,7 +3248,7 @@ Hide surftips for users without autorization==Verberge Surftipps für Benutzer o Show surftips to everyone==Zeige Surftipps allen Benutzern #----------------------------- -#File: Table_API_p.html +#File: Automation_p.html #--------------------------- : Peer Steering==: Peer Steuerung The information that is presented on this page can also be retrieved as XML.==Die Informationen auf dieser Seite können auch im XML Format abgerufen werden. diff --git a/locales/es.lng b/locales/es.lng index 21bfe8083..19a8c521d 100644 --- a/locales/es.lng +++ b/locales/es.lng @@ -1217,7 +1217,7 @@ YaCy Supporters<==Soporte de YaCy< "authentication required"=="Se requiere autenticación" #----------------------------- -#File: Table_API_p.html +#File: Automation_p.html #--------------------------- >Process Scheduler<==>Procesador de procesos< "next page"=="página siguiente" diff --git a/locales/fr.lng b/locales/fr.lng index 65a70291c..ecfcbfa56 100644 --- a/locales/fr.lng +++ b/locales/fr.lng @@ -997,7 +997,7 @@ can extend the pages per minute (ppm) rate to unlimited documents per minute ==p when the number of target hosts is high.==lorsque le nombre d'hôtes ciblés est élevé. This can be done using the Expert Crawl Start servlet.==Cela peut être effectué au moyen de cette servlet: démarrer un balayage expert. >Scheduler Steering<==>Commande du planificateur< -The scheduler on crawls can be changed or removed using the API Steering==Le planificateur de balayage peut être modifié ou supprimé au moyen de la commande de l'API +The scheduler on crawls can be changed or removed using API Steering==Le planificateur de balayage peut être modifié ou supprimé au moyen de la commande de l'API #--------------------------- #File: IndexBrowser_p.html @@ -2332,7 +2332,7 @@ Hide surftips==Surftipps cachés "Please enter a comment to your link recommendation. (Your Vote is also considered without a comment.)"=="S'il vous plait, commentez votre recommandation de lien. (Votre avis sera accepté même sans commentaire.)" #----------------------------- -#File: Table_API_p.html +#File: Automation_p.html #--------------------------- : Peer Steering==: Peer Contrôle #Steering of API Actions<==Steuerung der API Aktionen< diff --git a/locales/it.lng b/locales/it.lng index 4f19e169a..96b4cee23 100644 --- a/locales/it.lng +++ b/locales/it.lng @@ -1196,7 +1196,7 @@ YaCy Supporters<==Sostenitori di YaCy< "authentication required"=="Autenticazione richiesta" #----------------------------- -#File: Table_API_p.html +#File: Automation_p.html #--------------------------- >Process Scheduler<==>Scheduler dei processi< "next page"=="pagina successiva" diff --git a/locales/ja.lng b/locales/ja.lng index 21b74e522..0333b6794 100644 --- a/locales/ja.lng +++ b/locales/ja.lng @@ -1257,7 +1257,7 @@ YaCy Supporters<==YaCy サポーター< Show surftips to everyone==サーフティップスを全員に見せる #----------------------------- -#File: Table_API_p.html +#File: Automation_p.html #--------------------------- : Peer Steering==: ピアのステアリング The information that is presented on this page can also be retrieved as XML.==このページに表示されている情報はXMLとして取得する事もできます. diff --git a/locales/master.lng.xlf b/locales/master.lng.xlf index 0e347ff73..9d4d6220c 100644 --- a/locales/master.lng.xlf +++ b/locales/master.lng.xlf @@ -3599,7 +3599,7 @@ >Scheduler Steering< - The scheduler on crawls can be changed or removed using the <a href="Table_API_p.html">API Steering</a>. + The scheduler on crawls can be changed or removed using <a href="Automation_p.html">Automation</a>. @@ -8651,7 +8651,7 @@ - + : Peer Steering diff --git a/locales/ru.lng b/locales/ru.lng index 9b782f49a..8ac6e452b 100644 --- a/locales/ru.lng +++ b/locales/ru.lng @@ -1506,7 +1506,7 @@ A 'shallow crawl' which is not limited to a single host (or site)=='Медлен can extend the pages per minute (ppm) rate to unlimited documents per minute when the number of target hosts is high.==скорость индексирования которого может быть увеличена на неограниченное, когда число удалённых хостов высока. This can be done using the Expert Crawl Start servlet.==Это можно сделать с помощью запуска расширенного индексирования. >Scheduler Steering<==>Управление планировщиком< -The scheduler on crawls can be changed or removed using the API Steering.==Расписание индексирования может быть изменено или удалено, используя управление API. +The scheduler on crawls can be changed or removed using API Steering.==Расписание индексирования может быть изменено или удалено, используя управление API. #----------------------------- #File: Help.html @@ -3398,7 +3398,7 @@ Hide surftips for users without autorization==Скрыть подсказки д Show surftips to everyone==Разрешить подсказки всем #----------------------------- -#File: Table_API_p.html +#File: Automation_p.html #--------------------------- : Peer Steering==: Управление узлом The information that is presented on this page can also be retrieved as XML.==Информация представленная на этой странице, также может быть получена в XML-формате. diff --git a/locales/tr.lng b/locales/tr.lng index b0a6d9619..bc2e26ab7 100644 --- a/locales/tr.lng +++ b/locales/tr.lng @@ -1395,7 +1395,7 @@ A 'shallow crawl' which is not limited to a single host (or site)==Bir 'yüzeyse can extend the pages per minute (ppm) rate to unlimited documents per minute when the number of target hosts is high.==hedef ana bilgisayar sayısı yüksek olduğunda dakikadaki sayfaları sınırsız belgeye kadar genişletebilir. This can be done using the Expert Crawl Start servlet.==Bu, Uzman Tarama Başlatma aracılığıyla yapılabilir. >Scheduler Steering<==>Zamanlayıcı Yönlendirmesi< -The scheduler on crawls can be changed or removed using the API Steering.==Zamanlamalı taramalardaki zamanlayıcı, API Yönlendirmesi kullanılarak değiştirilebilir veya kaldırılabilir. +The scheduler on crawls can be changed or removed using API Steering.==Zamanlamalı taramalardaki zamanlayıcı, API Yönlendirmesi kullanılarak değiştirilebilir veya kaldırılabilir. #----------------------------- #File: Help.html @@ -3258,7 +3258,7 @@ Hide surftips for users without autorization==Yetkisi olmayan kullanıcılar iç Show surftips to everyone==Herkese surf ipuçları göster #-----------------------------``` -#File: Table_API_p.html +#File: Automation_p.html #--------------------------- : Peer Steering==: Peer Yönlendirme The information that is presented on this page can also be retrieved as XML.==Bu sayfada sunulan bilgiler aynı zamanda XML formatında alınabilir. diff --git a/locales/uk.lng b/locales/uk.lng index b95079df5..55a4aa7bc 100644 --- a/locales/uk.lng +++ b/locales/uk.lng @@ -1258,7 +1258,7 @@ A 'shallow crawl' which is not limited to a single host (or site)=="Миттєв can extend the pages per minute (ppm) rate to unlimited documents per minute when the number of target hosts is high.==може розширити Сторіки За Хвилину (ppm) до нескінченної кількості документів за хвилину, коли кількість кінцевих хостів велика. This can be done using the Expert Crawl Start servlet.==Це може бути здійснене з допомогою сервлетів Сканування (Знавець). >Scheduler Steering<==>Плановий контроль< -The scheduler on crawls can be changed or removed using the API Steering.==Заплановане виконання сканування може бути змінене або видалене з API. +The scheduler on crawls can be changed or removed using Automation.==Заплановане виконання сканування може бути змінене або видалене з API. Start URL==Початкова URL Sitemap URL==Карта сайту #----------------------------- @@ -2977,7 +2977,7 @@ Hide surftips for users without autorization==Приховати поради д Show surftips to everyone==Показувати поради для всіх #----------------------------- -#File: Table_API_p.html +#File: Automation_p.html #--------------------------- : Peer Steering==: Керування вузлом Steering of API Actions<==Керування подіями API< diff --git a/locales/zh.lng b/locales/zh.lng index d85b84271..7f822c53b 100644 --- a/locales/zh.lng +++ b/locales/zh.lng @@ -1572,7 +1572,7 @@ A 'shallow crawl' which is not limited to a single host (or site)==当目标服 can extend the pages per minute (ppm) rate to unlimited documents per minute when the number of target hosts is high.==会将生产量上升到每分钟无限页面数(ppm)。 This can be done using the Expert Crawl Start servlet.==可在专家爬虫中开启。 >Scheduler Steering<==>调度器控制< -The scheduler on crawls can be changed or removed using the API Steering.==可以使用API控制改变或删除爬虫调度器。 +The scheduler on crawls can be changed or removed using Automation.==可以使用API控制改变或删除爬虫调度器。 #----------------------------- #File: DictionaryLoader_p.html @@ -3511,7 +3511,7 @@ Hide surftips for users without autorization==隐藏非认证用户的建议功 Show surftips to everyone==所有人均可使用建议 #----------------------------- -#File: Table_API_p.html +#File: Automation_p.html #--------------------------- : Peer Steering==: 节点控制 The information that is presented on this page can also be retrieved as XML.==The information that is presented on this page can also be retrieved as XML. diff --git a/source/net/yacy/htroot/Automation_p.java b/source/net/yacy/htroot/Automation_p.java new file mode 100644 index 000000000..ab6f5e85d --- /dev/null +++ b/source/net/yacy/htroot/Automation_p.java @@ -0,0 +1,648 @@ +// Automation_p.java +// ----------------------- +// (C) 2010 by Michael Peter Christen; mc@yacy.net +// first published 01.02.2010 in Frankfurt, Germany on http://yacy.net +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package net.yacy.htroot; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Pattern; + +import net.yacy.cora.date.AbstractFormatter; +import net.yacy.cora.date.GenericFormatter; +import net.yacy.cora.document.encoding.UTF8; +import net.yacy.cora.document.id.MultiProtocolURL; +import net.yacy.cora.protocol.Domains; +import net.yacy.cora.protocol.RequestHeader; +import net.yacy.cora.util.ConcurrentLog; +import net.yacy.cora.util.SpaceExceededException; +import net.yacy.data.TransactionManager; +import net.yacy.data.WorkTables; +import net.yacy.kelondro.blob.Tables; +import net.yacy.kelondro.blob.Tables.Row; +import net.yacy.kelondro.blob.Tables.SortDirection; +import net.yacy.search.Switchboard; +import net.yacy.search.SwitchboardConstants; +import net.yacy.search.query.QueryParams; +import net.yacy.server.serverObjects; +import net.yacy.server.serverSwitch; + +public class Automation_p { + + /** Default results page size */ + private static final int DEFAULT_MAX_RECORDS = 25; + + public static serverObjects respond(final RequestHeader header, final serverObjects post, final serverSwitch env) { + final Switchboard sb = (Switchboard) env; + final serverObjects prop = new serverObjects(); + + final DateFormat dateFormat = GenericFormatter.newSimpleDateFormat(); + + prop.put("showexec", 0); + prop.put("showtable", 0); + + int startRecord = 0; + int maximumRecords = DEFAULT_MAX_RECORDS; + Pattern query = QueryParams.catchall_pattern; + if (post != null && post.containsKey("startRecord")) { + startRecord = post.getInt("startRecord", 0); + } + if (post != null && post.containsKey("maximumRecords")) { + maximumRecords = post.getInt("maximumRecords", 0); + } + String queryParam = ""; + if (post != null && post.containsKey("query") && !post.get("query", "").isEmpty()) { + queryParam = post.get("query", ""); + query = Pattern.compile(".*" + queryParam + ".*"); + } + final boolean inline = (post != null && post.getBoolean("inline")); + + prop.put("inline", (inline) ? 1 : 0); + + Pattern typefilter = QueryParams.catchall_pattern; + if (post != null && post.containsKey("filter") && post.get("filter", "").length() > 0) { + typefilter = Pattern.compile(post.get("filter", ".*")); + } + + /* Applying JSON API convention for the sort parameter format (http://jsonapi.org/format/#fetching-sorting) */ + String sortParam = WorkTables.TABLE_API_COL_DATE_RECORDING; + if(post != null) { + sortParam = post.get("sort", WorkTables.TABLE_API_COL_DATE_RECORDING).trim(); + } + final SortDirection sortDir; + final String sortColumn; + if(sortParam.startsWith("-")) { + sortColumn = sortParam.substring(1); + sortDir = SortDirection.DESC; + } else { + sortColumn = sortParam; + sortDir = SortDirection.ASC; + } + + // process scheduler and event input actions + boolean scheduleeventaction = false; // flag if schedule info of row changes + String current_pk = ""; // pk of changed schedule data row + if (post != null && post.containsKey("scheduleeventaction")) { + scheduleeventaction = post.get("scheduleeventaction", "false").equalsIgnoreCase("true"); + prop.put("scheduleeventaction", "false"); + current_pk = post.get("current_pk", ""); + } + if (post != null && scheduleeventaction && !current_pk.isEmpty()) { + + /* Check this is a valid transaction */ + TransactionManager.checkPostTransaction(header, post); + + try { + final Tables.Row row = sb.tables.select(WorkTables.TABLE_API_NAME, current_pk.getBytes()); + if (row != null) { + String action; + + // events + if (post.containsKey("event_select_" + current_pk) && post.get("event_select_" + current_pk, "off").equals("on")) { + row.put(WorkTables.TABLE_API_COL_APICALL_EVENT_KIND, "regular"); + row.put(WorkTables.TABLE_API_COL_APICALL_EVENT_ACTION, "startup"); + } + + if (post.containsKey("event_kind_" + current_pk) ) { + if ("off".equals(action = post.get("event_kind_" + current_pk, "off"))) { + row.put(WorkTables.TABLE_API_COL_DATE_NEXT_EXEC, ""); + } + row.put(WorkTables.TABLE_API_COL_APICALL_EVENT_KIND, action); + } + + if (post.containsKey("event_action_" + current_pk) ) { + row.put(WorkTables.TABLE_API_COL_APICALL_EVENT_ACTION, post.get("event_action_" + current_pk, "startup")); + } + + // scheduler + if (post.containsKey("repeat_select_" + current_pk) && post.get("repeat_select_" + current_pk, "off").equals("on")) { + row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 7); + row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_UNIT, "days"); + } + + if (post.containsKey("repeat_time_" + current_pk) ) { + if ("off".equals(action = post.get("repeat_time_" + current_pk, "off"))) { + row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 0); + } else { + row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, Integer.parseInt(action)); + } + } + + if (post.containsKey("repeat_unit_" + current_pk) ) { + action = post.get("repeat_unit_" + current_pk, "seldays"); + final int time = row.get(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 1); + row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_UNIT, action.substring(3)); + if (action.equals("selminutes") && time > 0 && time < 10) { + row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 10); + } + if (action.equals("selminutes") && time > 59) { + row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 59); + } + if (action.equals("selhours") && time > 23) { + row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 23); + } + if (action.equals("seldays") && time > 30) { + row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 30); + } + } + + // switch scheduler off if event kind is 'regular' + final String kind = row.get(WorkTables.TABLE_API_COL_APICALL_EVENT_KIND, "off"); + if ("regular".equals(kind)) row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 0); + + WorkTables.calculateAPIScheduler(row, false); + sb.tables.update(WorkTables.TABLE_API_NAME, row); + } + } catch (final Throwable e) { ConcurrentLog.logException(e); } + } + + /* Edition of scheduled next execution dates */ + final Map invalidNextExecDateFormats = new HashMap<>(); + final Map nextExecDatesBeforeNow = new HashMap<>(); + if (post != null && post.containsKey("submitNextExecDates")) { + + /* Check this is a valid transaction */ + TransactionManager.checkPostTransaction(header, post); + + + final String dateNexExecPrefix = "date_next_exec_"; + final Date now = new Date(); + for (final Map.Entry entry : post.entrySet()) { + if (entry.getKey().startsWith(dateNexExecPrefix) && entry.getValue() != null) { + try { + final String rowPkStr = entry.getKey().substring(dateNexExecPrefix.length()); + final Tables.Row row = sb.tables.select(WorkTables.TABLE_API_NAME, + rowPkStr.getBytes(StandardCharsets.UTF_8)); + if(row != null) { + final int time = row.get(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 0); + final String dateNextExecStr = entry.getValue().trim(); + try { + final Date dateNextExec = dateFormat.parse(dateNextExecStr); + + if(time != 0) { // Check there is effectively a schedule period on this row + if(dateNextExec.before(now)) { + nextExecDatesBeforeNow.put(rowPkStr, dateNextExecStr); + } else { + row.put(WorkTables.TABLE_API_COL_DATE_NEXT_EXEC, dateNextExec); + + sb.tables.update(WorkTables.TABLE_API_NAME, row); + } + } + } catch (final ParseException e) { + invalidNextExecDateFormats.put(rowPkStr, dateNextExecStr); + } + + } + } catch (final IOException | SpaceExceededException e) { + ConcurrentLog.logException(e); + } + } + } + } + + if (post != null && !post.get("deleterows", "").isEmpty()) { + + /* Check this is a valid transaction */ + TransactionManager.checkPostTransaction(header, post); + + for (final Map.Entry entry : post.entrySet()) { + if (entry.getValue().startsWith("mark_")) { + try { + sb.tables.delete(WorkTables.TABLE_API_NAME, entry.getValue().substring(5).getBytes()); + } catch (final IOException e) { + ConcurrentLog.logException(e); + } + } + } + } + + if (post != null && !post.get("deleteold", "").isEmpty()) { + + /* Check this is a valid transaction */ + TransactionManager.checkPostTransaction(header, post); + + final int days = post.getInt("deleteoldtime", 365); + try { + final Iterator ri = sb.tables.iterator(WorkTables.TABLE_API_NAME); + Row row; + final Date now = new Date(); + final Date limit = new Date(now.getTime() - AbstractFormatter.dayMillis * days); + final List pkl = new ArrayList(); + while (ri.hasNext()) { + row = ri.next(); + final Date d = row.get(WorkTables.TABLE_API_COL_DATE_RECORDING, now); + if (d.before(limit)) { + pkl.add(row.getPK()); + } + } + for (final byte[] pk: pkl) { + sb.tables.delete(WorkTables.TABLE_API_NAME, pk); + } + + // store this call as api call; clean the call a bit before + final Iterator> ei = post.getSolrParams().getMap().entrySet().iterator(); + Entry entry; + while (ei.hasNext()) { + entry = ei.next(); + if (entry.getKey().startsWith("event_select")) { + ei.remove(); + } + if (entry.getKey().startsWith("repeat_select")) { + ei.remove(); + } + } + sb.tables.recordAPICall(post, "Automation_p.html", WorkTables.TABLE_API_TYPE_STEERING, "delete API calls older than " + days + " days"); + } catch (final IOException e) { + ConcurrentLog.logException(e); + } + } + + if (post != null && !post.get("execrows", "").isEmpty()) { + + /* Check this is a valid transaction */ + TransactionManager.checkPostTransaction(header, post); + + // create a time-ordered list of events to execute + final Set pks = new TreeSet(); + for (final Map.Entry entry : post.entrySet()) { + if (entry.getValue().startsWith("mark_")) { + pks.add(entry.getValue().substring(5)); + } + } + + // now call the api URLs and store the result status + final Map l = sb.tables.execAPICalls(Domains.LOCALHOST, sb.getLocalPort(), pks, sb.getConfig(SwitchboardConstants.ADMIN_ACCOUNT_USER_NAME, "admin"), sb.getConfig(SwitchboardConstants.ADMIN_ACCOUNT_B64MD5, "")); + + // construct result table + prop.put("showexec", l.isEmpty() ? 0 : 1); + + final Iterator> resultIterator = l.entrySet().iterator(); + Map.Entry record; + int count = 0; + boolean dark = true; + while (resultIterator.hasNext()) { + record = resultIterator.next(); + if (record == null) { + continue; + } + prop.put("showexec_list_" + count + "_dark", ((dark) ? 1 : 0)); + dark = !dark; + prop.put("showexec_list_" + count + "_status", record.getValue()); + prop.put("showexec_list_" + count + "_url", record.getKey()); + count++; + } + prop.put("showexec_list", count); + } + + // generate table + prop.put("showtable", 1); + prop.put("showtable_inline", inline ? 1 : 0); + + /* Acquire a transaction token for the next POST form submission */ + final String nextTransactionToken = TransactionManager.getTransactionToken(header); + prop.put(TransactionManager.TRANSACTION_TOKEN_PARAM, nextTransactionToken); + prop.put("showtable_" + TransactionManager.TRANSACTION_TOKEN_PARAM, nextTransactionToken); + + final Date now = new Date(); + + // insert rows + final List table = new ArrayList(maximumRecords); + int count = 0; + int tablesize = 0; + int filteredSize = 0; + try { + tablesize = sb.tables.size(WorkTables.TABLE_API_NAME); + final Iterator plainIterator = sb.tables.iterator(WorkTables.TABLE_API_NAME); + final Iterator mapIterator; + if(sortColumn.isEmpty()) { + mapIterator = plainIterator; + } else { + if (WorkTables.TABLE_API_COL_APICALL_COUNT.equals(sortColumn) + || WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME.equals(sortColumn)) { + mapIterator = Tables.orderByInt(plainIterator, sortColumn, 0, sortDir).iterator(); + } else if (WorkTables.TABLE_API_COL_DATE.equals(sortColumn) + || WorkTables.TABLE_API_COL_DATE_RECORDING.equals(sortColumn) + || WorkTables.TABLE_API_COL_DATE_LAST_EXEC.equals(sortColumn) + || WorkTables.TABLE_API_COL_DATE_NEXT_EXEC.equals(sortColumn)) { + mapIterator = Tables.orderByDate(plainIterator, sortColumn, now, sortDir).iterator(); + } else { + mapIterator = Tables.orderByString(plainIterator, sortColumn, "", sortDir).iterator(); + } + } + Tables.Row r; + boolean dark = true; + boolean scheduledactions = false; + int matchCount = 0; + byte[] typeb, commentb, urlb; + String type, comment, url; + final boolean hasFilter = typefilter != QueryParams.catchall_pattern + || query != QueryParams.catchall_pattern; + + // first prepare a list + while (mapIterator.hasNext()) { + r = mapIterator.next(); + if (r == null) { + continue; + } + typeb = r.get(WorkTables.TABLE_API_COL_TYPE); + if (typeb == null) { + continue; + } + type = UTF8.String(typeb); + if (!typefilter.matcher(type).matches()) { + continue; + } + commentb = r.get(WorkTables.TABLE_API_COL_COMMENT); + if (commentb == null) { + continue; + } + comment = UTF8.String(commentb); + urlb = r.get(WorkTables.TABLE_API_COL_URL); + if (urlb == null) { + continue; + } + url = UTF8.String(urlb); + if(inline) { + if (!query.matcher(comment).matches()) { + /* When inlined, the url is not displayed so we search only on the comment */ + continue; + } + } else if (!query.matcher(comment).matches() && !query.matcher(url).matches()) { + /* The entry is evicted when both url and comment do not match the query */ + continue; + } + if (matchCount >= startRecord && table.size() < maximumRecords) { + table.add(r); + } + matchCount++; + if (table.size() >= maximumRecords && !hasFilter) { + /* When a filter is defined, we must continue iterating over the table to get the total count of matching items */ + break; + } + } + if(hasFilter) { + filteredSize = matchCount; + } else { + filteredSize = tablesize; + } + + // then work on the list + for (final Tables.Row row : table) { + final String rowPKStr = UTF8.String(row.getPK()); + final Date date = row.containsKey(WorkTables.TABLE_API_COL_DATE) ? row.get(WorkTables.TABLE_API_COL_DATE, now) : null; + final Date date_recording = row.get(WorkTables.TABLE_API_COL_DATE_RECORDING, date); + final Date date_last_exec = row.get(WorkTables.TABLE_API_COL_DATE_LAST_EXEC, date); + final Date date_next_exec = row.get(WorkTables.TABLE_API_COL_DATE_NEXT_EXEC, (Date) null); + final int callcount = row.get(WorkTables.TABLE_API_COL_APICALL_COUNT, 1); + final int time = row.get(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 0); + prop.put("showtable_list_" + count + "_inline", inline ? 1 : 0); + prop.put("showtable_list_" + count + "_dark", dark ? 1 : 0); + dark = !dark; + prop.put("showtable_list_" + count + "_pk", UTF8.String(row.getPK())); + prop.put("showtable_list_" + count + "_count", count); + prop.put("showtable_list_" + count + "_callcount", callcount); + prop.put("showtable_list_" + count + "_dateRecording", date_recording == null ? "-" : dateFormat.format(date_recording)); + prop.put("showtable_list_" + count + "_dateLastExec", date_last_exec == null ? "-" : dateFormat.format(date_last_exec)); + + prop.put("showtable_list_" + count + "_editableDateNext", time != 0); + final String enteredDateBeforeNow = nextExecDatesBeforeNow.get(rowPKStr); + prop.put("showtable_list_" + count + "_editableDateNext_dateBeforeNowError", enteredDateBeforeNow != null); + if(enteredDateBeforeNow != null) { + prop.put("showtable_list_" + count + "_editableDateNext_dateBeforeNowError_invalidDate", enteredDateBeforeNow); + } + + final String invalidEnteredDate = invalidNextExecDateFormats.get(rowPKStr); + prop.put("showtable_list_" + count + "_editableDateNext_dateFormatError", invalidEnteredDate != null); + if(invalidEnteredDate != null) { + prop.put("showtable_list_" + count + "_editableDateNext_dateFormatError_invalidDate", invalidEnteredDate); + } + + prop.put("showtable_list_" + count + "_editableDateNext_dateLastExecPattern", GenericFormatter.PATTERN_SIMPLE_REGEX); + prop.put("showtable_list_" + count + "_editableDateNext_dateNextExec", date_next_exec == null ? "-" : dateFormat.format(date_next_exec)); + prop.put("showtable_list_" + count + "_editableDateNext_pk", rowPKStr); + + prop.put("showtable_list_" + count + "_type", row.get(WorkTables.TABLE_API_COL_TYPE)); + prop.putHTML("showtable_list_" + count + "_comment", row.get(WorkTables.TABLE_API_COL_COMMENT)); + // check type & action to link crawl start URLs back to CrawlStartExpert.html + if (prop.get("showtable_list_" + count + "_type", "").equals(WorkTables.TABLE_API_TYPE_CRAWLER) + && prop.get("showtable_list_" + count + "_comment", "").startsWith("crawl start for")) { + final String editUrl = UTF8.String(row.get(WorkTables.TABLE_API_COL_URL)).replace("Crawler_p", "CrawlStartExpert"); + if (editUrl.length() > 1000) { + final MultiProtocolURL u = new MultiProtocolURL("http://localhost:8090" + editUrl); + prop.put("showtable_list_" + count + "_isCrawlerStart", 2); + prop.put("showtable_list_" + count + "_isCrawlerStart_pk", rowPKStr); + prop.put("showtable_list_" + count + "_isCrawlerStart_servlet", "CrawlStartExpert.html"); + final Map attr = u.getAttributes(); + int ac = 0; + for (final Map.Entry entry: attr.entrySet()) { + prop.put("showtable_list_" + count + "_isCrawlerStart_attr_" + ac + "_key", entry.getKey()); + prop.put("showtable_list_" + count + "_isCrawlerStart_attr_" + ac + "_value", entry.getValue()); + ac++; + } + prop.put("showtable_list_" + count + "_isCrawlerStart_attr", ac); + } else { + // short calls + prop.put("showtable_list_" + count + "_isCrawlerStart", 1); + /* For better integration of YaCy peers behind a reverse proxy subfolder, + * ensure a path relative to this servlet (with no starting slash) is used for clone links. + * We keep the paths starting with a slash for other URL displays. */ + prop.put("showtable_list_" + count + "_isCrawlerStart_url", editUrl.startsWith("/") ? editUrl.substring(1, editUrl.length()) : editUrl); + } + } else { + prop.put("showtable_list_" + count + "_isCrawlerStart", 0); + } + prop.putHTML("showtable_list_" + count + "_inline_url", UTF8.String(row.get(WorkTables.TABLE_API_COL_URL))); + prop.put("showtable_list_" + count + "_scheduler_inline", inline ? "true" : "false"); + prop.put("showtable_list_" + count + "_scheduler_filter", typefilter.pattern()); + prop.put("showtable_list_" + count + "_scheduler_query", query.pattern()); + prop.put("showtable_list_" + count + "_scheduler_startRecord", startRecord); + prop.put("showtable_list_" + count + "_scheduler_maximumRecords", maximumRecords); + + // events + final String kind = row.get(WorkTables.TABLE_API_COL_APICALL_EVENT_KIND, "off"); + final String action = row.get(WorkTables.TABLE_API_COL_APICALL_EVENT_ACTION, "startup"); + prop.put("showtable_list_" + count + "_event_pk", rowPKStr); + final boolean schedulerDisabled = "regular".equals(kind); + if ("off".equals(kind)) { + prop.put("showtable_list_" + count + "_event", 0); + } else { + prop.put("showtable_list_" + count + "_event", 1); + prop.put("showtable_list_" + count + "_event_selectedoff", "off".equals(kind) ? 1 : 0); + prop.put("showtable_list_" + count + "_event_selectedonce", "once".equals(kind) ? 1 : 0); + prop.put("showtable_list_" + count + "_event_selectedregular", "regular".equals(kind) ? 1 : 0); + prop.put("showtable_list_" + count + "_event_selectedstartup", "startup".equals(action) ? 1 : 0); + for (int i = 0; i < 24; i++) { + String is = Integer.toString(i); + if (is.length() == 1) is = "0" + is; + is = is + "00"; + prop.put("showtable_list_" + count + "_event_selected" + is, is.equals(action) ? 1 : 0); + } + } + + // scheduler + final String unit = row.get(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_UNIT, "days"); + prop.put("showtable_list_" + count + "_selectedMinutes", unit.equals("minutes") ? 1 : 0); + prop.put("showtable_list_" + count + "_selectedHours", unit.equals("hours") ? 1 : 0); + prop.put("showtable_list_" + count + "_selectedDays", (unit.isEmpty() || unit.equals("days")) ? 1 : 0); + prop.put("showtable_list_" + count + "_scheduler_pk", rowPKStr); + prop.put("showtable_list_" + count + "_scheduler_disabled", schedulerDisabled ? 1 : 0); + prop.put("showtable_list_" + count + "_repeatTime", time); + if (time == 0) { + prop.put("showtable_list_" + count + "_scheduler", 0); + } else { + scheduledactions = true; + prop.put("showtable_list_" + count + "_scheduler", 1); + prop.put("showtable_list_" + count + "_scheduler_scale_" + 0 + "_time", "off"); + prop.put("showtable_list_" + count + "_scheduler_selectedMinutes", 0); + prop.put("showtable_list_" + count + "_scheduler_selectedHours", 0); + prop.put("showtable_list_" + count + "_scheduler_selectedDays", 0); + if (unit.equals("minutes")) { + for (int i = 1; i <= 5; i++) { + prop.put("showtable_list_" + count + "_scheduler_scale_" + i + "_time", i * 10); + prop.put("showtable_list_" + count + "_scheduler_scale_" + i + "_selected", 0); + } + prop.put("showtable_list_" + count + "_scheduler_scale_" + (time / 10) + "_selected", 1); + prop.put("showtable_list_" + count + "_scheduler_scale", 6); + prop.put("showtable_list_" + count + "_scheduler_selectedMinutes", 1); + } else if (unit.equals("hours")) { + for (int i = 1; i <= 23; i++) { + prop.put("showtable_list_" + count + "_scheduler_scale_" + i + "_time", i); + prop.put("showtable_list_" + count + "_scheduler_scale_" + i + "_selected", 0); + } + prop.put("showtable_list_" + count + "_scheduler_scale_" + time + "_selected", 1); + prop.put("showtable_list_" + count + "_scheduler_scale", 24); + prop.put("showtable_list_" + count + "_scheduler_selectedHours", 1); + } else { + for (int i = 1; i <= 30; i++) { + prop.put("showtable_list_" + count + "_scheduler_scale_" + i + "_time", i); + prop.put("showtable_list_" + count + "_scheduler_scale_" + i + "_selected", 0); + } + prop.put("showtable_list_" + count + "_scheduler_scale_" + time + "_selected", 1); + prop.put("showtable_list_" + count + "_scheduler_scale", 31); + prop.put("showtable_list_" + count + "_scheduler_selectedDays", 1); + } + + } + count++; + } + prop.put("showtable_hasEditableNextExecDate", scheduledactions); + if (scheduledactions) { + prop.put("showschedulerhint", 1); + prop.put("showschedulerhint_tfminutes", sb.getConfigLong(SwitchboardConstants.CLEANUP_BUSYSLEEP, 300000) / 60000); + } else { + prop.put("showschedulerhint", 0); + } + } catch (final IOException e) { + ConcurrentLog.logException(e); + } + prop.put("showtable_list", count); + prop.put("showtable_num", count); + + // write navigation details + prop.put("showtable_startRecord", startRecord); + prop.put("showtable_maximumRecords", maximumRecords); + prop.put("showtable_inline", (inline) ? 1 : 0); + prop.put("showtable_filter", typefilter.pattern()); + prop.put("showtable_query", queryParam); + prop.put("showtable_sort", sortParam); + + putTableSortProperties(prop, sortDir, sortColumn); + + if (filteredSize > maximumRecords) { + prop.put("showtable_navigation", 1); + prop.put("showtable_navigation_startRecord", startRecord); + prop.put("showtable_navigation_to", Math.min(filteredSize, startRecord + table.size())); + prop.put("showtable_navigation_of", filteredSize); + prop.put("showtable_navigation_left", startRecord == 0 ? 0 : 1); + prop.put("showtable_navigation_left_startRecord", Math.max(0, startRecord - maximumRecords)); + prop.put("showtable_navigation_left_maximumRecords", maximumRecords); + prop.put("showtable_navigation_left_inline", (inline) ? 1 : 0); + prop.put("showtable_navigation_left_filter", typefilter.pattern()); + prop.put("showtable_navigation_left_query", queryParam); + prop.put("showtable_navigation_left_sort", sortParam); + prop.put("showtable_navigation_left", startRecord == 0 ? 0 : 1); + prop.put("showtable_navigation_filter", typefilter.pattern()); + prop.put("showtable_navigation_right", startRecord + maximumRecords >= filteredSize ? 0 : 1); + prop.put("showtable_navigation_right_startRecord", startRecord + maximumRecords); + prop.put("showtable_navigation_right_maximumRecords", maximumRecords); + prop.put("showtable_navigation_right_inline", (inline) ? 1 : 0); + prop.put("showtable_navigation_right_filter", typefilter.pattern()); + prop.put("showtable_navigation_right_query", queryParam); + prop.put("showtable_navigation_right_sort", sortParam); + } else { + prop.put("showtable_navigation", 0); + } + + // return rewrite properties + return prop; + } + + /** + * Fill the serverObjects instance with table columns sort properties. + * + * @param prop + * the serverObjects instance to fill. Must not be null. + * @param sortDir + * the current sort direction + * @param sortColumn + * the current sort column + */ + private static void putTableSortProperties(final serverObjects prop, final SortDirection sortDir, + final String sortColumn) { + boolean sortedByAsc = WorkTables.TABLE_API_COL_TYPE.equals(sortColumn) && sortDir == SortDirection.ASC; + prop.put("showtable_sortedByType", WorkTables.TABLE_API_COL_TYPE.equals(sortColumn)); + prop.put("showtable_sortedByType_asc", sortedByAsc); + prop.put("showtable_nextSortTypeDesc", sortedByAsc); + + sortedByAsc = WorkTables.TABLE_API_COL_COMMENT.equals(sortColumn) && sortDir == SortDirection.ASC; + prop.put("showtable_sortedByComment", WorkTables.TABLE_API_COL_COMMENT.equals(sortColumn)); + prop.put("showtable_sortedByComment_asc", sortedByAsc); + prop.put("showtable_nextSortCommentDesc", sortedByAsc); + + sortedByAsc = WorkTables.TABLE_API_COL_APICALL_COUNT.equals(sortColumn) && sortDir == SortDirection.ASC; + prop.put("showtable_sortedByApiCallCount", WorkTables.TABLE_API_COL_APICALL_COUNT.equals(sortColumn)); + prop.put("showtable_sortedByApiCallCount_asc", sortedByAsc); + prop.put("showtable_nextSortApiCallCountDesc", sortedByAsc); + + sortedByAsc = WorkTables.TABLE_API_COL_DATE_RECORDING.equals(sortColumn) && sortDir == SortDirection.ASC; + prop.put("showtable_sortedByDateRecording", WorkTables.TABLE_API_COL_DATE_RECORDING.equals(sortColumn)); + prop.put("showtable_sortedByDateRecording_asc", sortedByAsc); + prop.put("showtable_nextSortDateRecordingDesc", sortedByAsc); + + sortedByAsc = WorkTables.TABLE_API_COL_DATE_LAST_EXEC.equals(sortColumn) && sortDir == SortDirection.ASC; + prop.put("showtable_sortedByDateLastExec", WorkTables.TABLE_API_COL_DATE_LAST_EXEC.equals(sortColumn)); + prop.put("showtable_sortedByDateLastExec_asc", sortedByAsc); + prop.put("showtable_nextSortDateLastExecDesc", sortedByAsc); + + sortedByAsc = WorkTables.TABLE_API_COL_DATE_NEXT_EXEC.equals(sortColumn) && sortDir == SortDirection.ASC; + prop.put("showtable_sortedByDateNextExec", WorkTables.TABLE_API_COL_DATE_NEXT_EXEC.equals(sortColumn)); + prop.put("showtable_sortedByDateNextExec_asc", sortedByAsc); + prop.put("showtable_nextSortDateNextExecDesc", sortedByAsc); + } +} diff --git a/source/net/yacy/htroot/Table_API_p.java b/source/net/yacy/htroot/Table_API_p.java deleted file mode 100644 index f8c7d1a13..000000000 --- a/source/net/yacy/htroot/Table_API_p.java +++ /dev/null @@ -1,648 +0,0 @@ -// Table_API_p.java -// ----------------------- -// (C) 2010 by Michael Peter Christen; mc@yacy.net -// first published 01.02.2010 in Frankfurt, Germany on http://yacy.net -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package net.yacy.htroot; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.ParseException; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.TreeSet; -import java.util.regex.Pattern; - -import net.yacy.cora.date.AbstractFormatter; -import net.yacy.cora.date.GenericFormatter; -import net.yacy.cora.document.encoding.UTF8; -import net.yacy.cora.document.id.MultiProtocolURL; -import net.yacy.cora.protocol.Domains; -import net.yacy.cora.protocol.RequestHeader; -import net.yacy.cora.util.ConcurrentLog; -import net.yacy.cora.util.SpaceExceededException; -import net.yacy.data.TransactionManager; -import net.yacy.data.WorkTables; -import net.yacy.kelondro.blob.Tables; -import net.yacy.kelondro.blob.Tables.Row; -import net.yacy.kelondro.blob.Tables.SortDirection; -import net.yacy.search.Switchboard; -import net.yacy.search.SwitchboardConstants; -import net.yacy.search.query.QueryParams; -import net.yacy.server.serverObjects; -import net.yacy.server.serverSwitch; - -public class Table_API_p { - - /** Default results page size */ - private static final int DEFAULT_MAX_RECORDS = 25; - - public static serverObjects respond(final RequestHeader header, final serverObjects post, final serverSwitch env) { - final Switchboard sb = (Switchboard) env; - final serverObjects prop = new serverObjects(); - - final DateFormat dateFormat = GenericFormatter.newSimpleDateFormat(); - - prop.put("showexec", 0); - prop.put("showtable", 0); - - int startRecord = 0; - int maximumRecords = DEFAULT_MAX_RECORDS; - Pattern query = QueryParams.catchall_pattern; - if (post != null && post.containsKey("startRecord")) { - startRecord = post.getInt("startRecord", 0); - } - if (post != null && post.containsKey("maximumRecords")) { - maximumRecords = post.getInt("maximumRecords", 0); - } - String queryParam = ""; - if (post != null && post.containsKey("query") && !post.get("query", "").isEmpty()) { - queryParam = post.get("query", ""); - query = Pattern.compile(".*" + queryParam + ".*"); - } - final boolean inline = (post != null && post.getBoolean("inline")); - - prop.put("inline", (inline) ? 1 : 0); - - Pattern typefilter = QueryParams.catchall_pattern; - if (post != null && post.containsKey("filter") && post.get("filter", "").length() > 0) { - typefilter = Pattern.compile(post.get("filter", ".*")); - } - - /* Applying JSON API convention for the sort parameter format (http://jsonapi.org/format/#fetching-sorting) */ - String sortParam = WorkTables.TABLE_API_COL_DATE_RECORDING; - if(post != null) { - sortParam = post.get("sort", WorkTables.TABLE_API_COL_DATE_RECORDING).trim(); - } - final SortDirection sortDir; - final String sortColumn; - if(sortParam.startsWith("-")) { - sortColumn = sortParam.substring(1); - sortDir = SortDirection.DESC; - } else { - sortColumn = sortParam; - sortDir = SortDirection.ASC; - } - - // process scheduler and event input actions - boolean scheduleeventaction = false; // flag if schedule info of row changes - String current_pk = ""; // pk of changed schedule data row - if (post != null && post.containsKey("scheduleeventaction")) { - scheduleeventaction = post.get("scheduleeventaction", "false").equalsIgnoreCase("true"); - prop.put("scheduleeventaction", "false"); - current_pk = post.get("current_pk", ""); - } - if (post != null && scheduleeventaction && !current_pk.isEmpty()) { - - /* Check this is a valid transaction */ - TransactionManager.checkPostTransaction(header, post); - - try { - final Tables.Row row = sb.tables.select(WorkTables.TABLE_API_NAME, current_pk.getBytes()); - if (row != null) { - String action; - - // events - if (post.containsKey("event_select_" + current_pk) && post.get("event_select_" + current_pk, "off").equals("on")) { - row.put(WorkTables.TABLE_API_COL_APICALL_EVENT_KIND, "regular"); - row.put(WorkTables.TABLE_API_COL_APICALL_EVENT_ACTION, "startup"); - } - - if (post.containsKey("event_kind_" + current_pk) ) { - if ("off".equals(action = post.get("event_kind_" + current_pk, "off"))) { - row.put(WorkTables.TABLE_API_COL_DATE_NEXT_EXEC, ""); - } - row.put(WorkTables.TABLE_API_COL_APICALL_EVENT_KIND, action); - } - - if (post.containsKey("event_action_" + current_pk) ) { - row.put(WorkTables.TABLE_API_COL_APICALL_EVENT_ACTION, post.get("event_action_" + current_pk, "startup")); - } - - // scheduler - if (post.containsKey("repeat_select_" + current_pk) && post.get("repeat_select_" + current_pk, "off").equals("on")) { - row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 7); - row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_UNIT, "days"); - } - - if (post.containsKey("repeat_time_" + current_pk) ) { - if ("off".equals(action = post.get("repeat_time_" + current_pk, "off"))) { - row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 0); - } else { - row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, Integer.parseInt(action)); - } - } - - if (post.containsKey("repeat_unit_" + current_pk) ) { - action = post.get("repeat_unit_" + current_pk, "seldays"); - final int time = row.get(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 1); - row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_UNIT, action.substring(3)); - if (action.equals("selminutes") && time > 0 && time < 10) { - row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 10); - } - if (action.equals("selminutes") && time > 59) { - row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 59); - } - if (action.equals("selhours") && time > 23) { - row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 23); - } - if (action.equals("seldays") && time > 30) { - row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 30); - } - } - - // switch scheduler off if event kind is 'regular' - final String kind = row.get(WorkTables.TABLE_API_COL_APICALL_EVENT_KIND, "off"); - if ("regular".equals(kind)) row.put(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 0); - - WorkTables.calculateAPIScheduler(row, false); - sb.tables.update(WorkTables.TABLE_API_NAME, row); - } - } catch (final Throwable e) { ConcurrentLog.logException(e); } - } - - /* Edition of scheduled next execution dates */ - final Map invalidNextExecDateFormats = new HashMap<>(); - final Map nextExecDatesBeforeNow = new HashMap<>(); - if (post != null && post.containsKey("submitNextExecDates")) { - - /* Check this is a valid transaction */ - TransactionManager.checkPostTransaction(header, post); - - - final String dateNexExecPrefix = "date_next_exec_"; - final Date now = new Date(); - for (final Map.Entry entry : post.entrySet()) { - if (entry.getKey().startsWith(dateNexExecPrefix) && entry.getValue() != null) { - try { - final String rowPkStr = entry.getKey().substring(dateNexExecPrefix.length()); - final Tables.Row row = sb.tables.select(WorkTables.TABLE_API_NAME, - rowPkStr.getBytes(StandardCharsets.UTF_8)); - if(row != null) { - final int time = row.get(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 0); - final String dateNextExecStr = entry.getValue().trim(); - try { - final Date dateNextExec = dateFormat.parse(dateNextExecStr); - - if(time != 0) { // Check there is effectively a schedule period on this row - if(dateNextExec.before(now)) { - nextExecDatesBeforeNow.put(rowPkStr, dateNextExecStr); - } else { - row.put(WorkTables.TABLE_API_COL_DATE_NEXT_EXEC, dateNextExec); - - sb.tables.update(WorkTables.TABLE_API_NAME, row); - } - } - } catch (final ParseException e) { - invalidNextExecDateFormats.put(rowPkStr, dateNextExecStr); - } - - } - } catch (final IOException | SpaceExceededException e) { - ConcurrentLog.logException(e); - } - } - } - } - - if (post != null && !post.get("deleterows", "").isEmpty()) { - - /* Check this is a valid transaction */ - TransactionManager.checkPostTransaction(header, post); - - for (final Map.Entry entry : post.entrySet()) { - if (entry.getValue().startsWith("mark_")) { - try { - sb.tables.delete(WorkTables.TABLE_API_NAME, entry.getValue().substring(5).getBytes()); - } catch (final IOException e) { - ConcurrentLog.logException(e); - } - } - } - } - - if (post != null && !post.get("deleteold", "").isEmpty()) { - - /* Check this is a valid transaction */ - TransactionManager.checkPostTransaction(header, post); - - final int days = post.getInt("deleteoldtime", 365); - try { - final Iterator ri = sb.tables.iterator(WorkTables.TABLE_API_NAME); - Row row; - final Date now = new Date(); - final Date limit = new Date(now.getTime() - AbstractFormatter.dayMillis * days); - final List pkl = new ArrayList(); - while (ri.hasNext()) { - row = ri.next(); - final Date d = row.get(WorkTables.TABLE_API_COL_DATE_RECORDING, now); - if (d.before(limit)) { - pkl.add(row.getPK()); - } - } - for (final byte[] pk: pkl) { - sb.tables.delete(WorkTables.TABLE_API_NAME, pk); - } - - // store this call as api call; clean the call a bit before - final Iterator> ei = post.getSolrParams().getMap().entrySet().iterator(); - Entry entry; - while (ei.hasNext()) { - entry = ei.next(); - if (entry.getKey().startsWith("event_select")) { - ei.remove(); - } - if (entry.getKey().startsWith("repeat_select")) { - ei.remove(); - } - } - sb.tables.recordAPICall(post, "Table_API_p.html", WorkTables.TABLE_API_TYPE_STEERING, "delete API calls older than " + days + " days"); - } catch (final IOException e) { - ConcurrentLog.logException(e); - } - } - - if (post != null && !post.get("execrows", "").isEmpty()) { - - /* Check this is a valid transaction */ - TransactionManager.checkPostTransaction(header, post); - - // create a time-ordered list of events to execute - final Set pks = new TreeSet(); - for (final Map.Entry entry : post.entrySet()) { - if (entry.getValue().startsWith("mark_")) { - pks.add(entry.getValue().substring(5)); - } - } - - // now call the api URLs and store the result status - final Map l = sb.tables.execAPICalls(Domains.LOCALHOST, sb.getLocalPort(), pks, sb.getConfig(SwitchboardConstants.ADMIN_ACCOUNT_USER_NAME, "admin"), sb.getConfig(SwitchboardConstants.ADMIN_ACCOUNT_B64MD5, "")); - - // construct result table - prop.put("showexec", l.isEmpty() ? 0 : 1); - - final Iterator> resultIterator = l.entrySet().iterator(); - Map.Entry record; - int count = 0; - boolean dark = true; - while (resultIterator.hasNext()) { - record = resultIterator.next(); - if (record == null) { - continue; - } - prop.put("showexec_list_" + count + "_dark", ((dark) ? 1 : 0)); - dark = !dark; - prop.put("showexec_list_" + count + "_status", record.getValue()); - prop.put("showexec_list_" + count + "_url", record.getKey()); - count++; - } - prop.put("showexec_list", count); - } - - // generate table - prop.put("showtable", 1); - prop.put("showtable_inline", inline ? 1 : 0); - - /* Acquire a transaction token for the next POST form submission */ - final String nextTransactionToken = TransactionManager.getTransactionToken(header); - prop.put(TransactionManager.TRANSACTION_TOKEN_PARAM, nextTransactionToken); - prop.put("showtable_" + TransactionManager.TRANSACTION_TOKEN_PARAM, nextTransactionToken); - - final Date now = new Date(); - - // insert rows - final List table = new ArrayList(maximumRecords); - int count = 0; - int tablesize = 0; - int filteredSize = 0; - try { - tablesize = sb.tables.size(WorkTables.TABLE_API_NAME); - final Iterator plainIterator = sb.tables.iterator(WorkTables.TABLE_API_NAME); - final Iterator mapIterator; - if(sortColumn.isEmpty()) { - mapIterator = plainIterator; - } else { - if (WorkTables.TABLE_API_COL_APICALL_COUNT.equals(sortColumn) - || WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME.equals(sortColumn)) { - mapIterator = Tables.orderByInt(plainIterator, sortColumn, 0, sortDir).iterator(); - } else if (WorkTables.TABLE_API_COL_DATE.equals(sortColumn) - || WorkTables.TABLE_API_COL_DATE_RECORDING.equals(sortColumn) - || WorkTables.TABLE_API_COL_DATE_LAST_EXEC.equals(sortColumn) - || WorkTables.TABLE_API_COL_DATE_NEXT_EXEC.equals(sortColumn)) { - mapIterator = Tables.orderByDate(plainIterator, sortColumn, now, sortDir).iterator(); - } else { - mapIterator = Tables.orderByString(plainIterator, sortColumn, "", sortDir).iterator(); - } - } - Tables.Row r; - boolean dark = true; - boolean scheduledactions = false; - int matchCount = 0; - byte[] typeb, commentb, urlb; - String type, comment, url; - final boolean hasFilter = typefilter != QueryParams.catchall_pattern - || query != QueryParams.catchall_pattern; - - // first prepare a list - while (mapIterator.hasNext()) { - r = mapIterator.next(); - if (r == null) { - continue; - } - typeb = r.get(WorkTables.TABLE_API_COL_TYPE); - if (typeb == null) { - continue; - } - type = UTF8.String(typeb); - if (!typefilter.matcher(type).matches()) { - continue; - } - commentb = r.get(WorkTables.TABLE_API_COL_COMMENT); - if (commentb == null) { - continue; - } - comment = UTF8.String(commentb); - urlb = r.get(WorkTables.TABLE_API_COL_URL); - if (urlb == null) { - continue; - } - url = UTF8.String(urlb); - if(inline) { - if (!query.matcher(comment).matches()) { - /* When inlined, the url is not displayed so we search only on the comment */ - continue; - } - } else if (!query.matcher(comment).matches() && !query.matcher(url).matches()) { - /* The entry is evicted when both url and comment do not match the query */ - continue; - } - if (matchCount >= startRecord && table.size() < maximumRecords) { - table.add(r); - } - matchCount++; - if (table.size() >= maximumRecords && !hasFilter) { - /* When a filter is defined, we must continue iterating over the table to get the total count of matching items */ - break; - } - } - if(hasFilter) { - filteredSize = matchCount; - } else { - filteredSize = tablesize; - } - - // then work on the list - for (final Tables.Row row : table) { - final String rowPKStr = UTF8.String(row.getPK()); - final Date date = row.containsKey(WorkTables.TABLE_API_COL_DATE) ? row.get(WorkTables.TABLE_API_COL_DATE, now) : null; - final Date date_recording = row.get(WorkTables.TABLE_API_COL_DATE_RECORDING, date); - final Date date_last_exec = row.get(WorkTables.TABLE_API_COL_DATE_LAST_EXEC, date); - final Date date_next_exec = row.get(WorkTables.TABLE_API_COL_DATE_NEXT_EXEC, (Date) null); - final int callcount = row.get(WorkTables.TABLE_API_COL_APICALL_COUNT, 1); - final int time = row.get(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME, 0); - prop.put("showtable_list_" + count + "_inline", inline ? 1 : 0); - prop.put("showtable_list_" + count + "_dark", dark ? 1 : 0); - dark = !dark; - prop.put("showtable_list_" + count + "_pk", UTF8.String(row.getPK())); - prop.put("showtable_list_" + count + "_count", count); - prop.put("showtable_list_" + count + "_callcount", callcount); - prop.put("showtable_list_" + count + "_dateRecording", date_recording == null ? "-" : dateFormat.format(date_recording)); - prop.put("showtable_list_" + count + "_dateLastExec", date_last_exec == null ? "-" : dateFormat.format(date_last_exec)); - - prop.put("showtable_list_" + count + "_editableDateNext", time != 0); - final String enteredDateBeforeNow = nextExecDatesBeforeNow.get(rowPKStr); - prop.put("showtable_list_" + count + "_editableDateNext_dateBeforeNowError", enteredDateBeforeNow != null); - if(enteredDateBeforeNow != null) { - prop.put("showtable_list_" + count + "_editableDateNext_dateBeforeNowError_invalidDate", enteredDateBeforeNow); - } - - final String invalidEnteredDate = invalidNextExecDateFormats.get(rowPKStr); - prop.put("showtable_list_" + count + "_editableDateNext_dateFormatError", invalidEnteredDate != null); - if(invalidEnteredDate != null) { - prop.put("showtable_list_" + count + "_editableDateNext_dateFormatError_invalidDate", invalidEnteredDate); - } - - prop.put("showtable_list_" + count + "_editableDateNext_dateLastExecPattern", GenericFormatter.PATTERN_SIMPLE_REGEX); - prop.put("showtable_list_" + count + "_editableDateNext_dateNextExec", date_next_exec == null ? "-" : dateFormat.format(date_next_exec)); - prop.put("showtable_list_" + count + "_editableDateNext_pk", rowPKStr); - - prop.put("showtable_list_" + count + "_type", row.get(WorkTables.TABLE_API_COL_TYPE)); - prop.putHTML("showtable_list_" + count + "_comment", row.get(WorkTables.TABLE_API_COL_COMMENT)); - // check type & action to link crawl start URLs back to CrawlStartExpert.html - if (prop.get("showtable_list_" + count + "_type", "").equals(WorkTables.TABLE_API_TYPE_CRAWLER) - && prop.get("showtable_list_" + count + "_comment", "").startsWith("crawl start for")) { - final String editUrl = UTF8.String(row.get(WorkTables.TABLE_API_COL_URL)).replace("Crawler_p", "CrawlStartExpert"); - if (editUrl.length() > 1000) { - final MultiProtocolURL u = new MultiProtocolURL("http://localhost:8090" + editUrl); - prop.put("showtable_list_" + count + "_isCrawlerStart", 2); - prop.put("showtable_list_" + count + "_isCrawlerStart_pk", rowPKStr); - prop.put("showtable_list_" + count + "_isCrawlerStart_servlet", "CrawlStartExpert.html"); - final Map attr = u.getAttributes(); - int ac = 0; - for (final Map.Entry entry: attr.entrySet()) { - prop.put("showtable_list_" + count + "_isCrawlerStart_attr_" + ac + "_key", entry.getKey()); - prop.put("showtable_list_" + count + "_isCrawlerStart_attr_" + ac + "_value", entry.getValue()); - ac++; - } - prop.put("showtable_list_" + count + "_isCrawlerStart_attr", ac); - } else { - // short calls - prop.put("showtable_list_" + count + "_isCrawlerStart", 1); - /* For better integration of YaCy peers behind a reverse proxy subfolder, - * ensure a path relative to this servlet (with no starting slash) is used for clone links. - * We keep the paths starting with a slash for other URL displays. */ - prop.put("showtable_list_" + count + "_isCrawlerStart_url", editUrl.startsWith("/") ? editUrl.substring(1, editUrl.length()) : editUrl); - } - } else { - prop.put("showtable_list_" + count + "_isCrawlerStart", 0); - } - prop.putHTML("showtable_list_" + count + "_inline_url", UTF8.String(row.get(WorkTables.TABLE_API_COL_URL))); - prop.put("showtable_list_" + count + "_scheduler_inline", inline ? "true" : "false"); - prop.put("showtable_list_" + count + "_scheduler_filter", typefilter.pattern()); - prop.put("showtable_list_" + count + "_scheduler_query", query.pattern()); - prop.put("showtable_list_" + count + "_scheduler_startRecord", startRecord); - prop.put("showtable_list_" + count + "_scheduler_maximumRecords", maximumRecords); - - // events - final String kind = row.get(WorkTables.TABLE_API_COL_APICALL_EVENT_KIND, "off"); - final String action = row.get(WorkTables.TABLE_API_COL_APICALL_EVENT_ACTION, "startup"); - prop.put("showtable_list_" + count + "_event_pk", rowPKStr); - final boolean schedulerDisabled = "regular".equals(kind); - if ("off".equals(kind)) { - prop.put("showtable_list_" + count + "_event", 0); - } else { - prop.put("showtable_list_" + count + "_event", 1); - prop.put("showtable_list_" + count + "_event_selectedoff", "off".equals(kind) ? 1 : 0); - prop.put("showtable_list_" + count + "_event_selectedonce", "once".equals(kind) ? 1 : 0); - prop.put("showtable_list_" + count + "_event_selectedregular", "regular".equals(kind) ? 1 : 0); - prop.put("showtable_list_" + count + "_event_selectedstartup", "startup".equals(action) ? 1 : 0); - for (int i = 0; i < 24; i++) { - String is = Integer.toString(i); - if (is.length() == 1) is = "0" + is; - is = is + "00"; - prop.put("showtable_list_" + count + "_event_selected" + is, is.equals(action) ? 1 : 0); - } - } - - // scheduler - final String unit = row.get(WorkTables.TABLE_API_COL_APICALL_SCHEDULE_UNIT, "days"); - prop.put("showtable_list_" + count + "_selectedMinutes", unit.equals("minutes") ? 1 : 0); - prop.put("showtable_list_" + count + "_selectedHours", unit.equals("hours") ? 1 : 0); - prop.put("showtable_list_" + count + "_selectedDays", (unit.isEmpty() || unit.equals("days")) ? 1 : 0); - prop.put("showtable_list_" + count + "_scheduler_pk", rowPKStr); - prop.put("showtable_list_" + count + "_scheduler_disabled", schedulerDisabled ? 1 : 0); - prop.put("showtable_list_" + count + "_repeatTime", time); - if (time == 0) { - prop.put("showtable_list_" + count + "_scheduler", 0); - } else { - scheduledactions = true; - prop.put("showtable_list_" + count + "_scheduler", 1); - prop.put("showtable_list_" + count + "_scheduler_scale_" + 0 + "_time", "off"); - prop.put("showtable_list_" + count + "_scheduler_selectedMinutes", 0); - prop.put("showtable_list_" + count + "_scheduler_selectedHours", 0); - prop.put("showtable_list_" + count + "_scheduler_selectedDays", 0); - if (unit.equals("minutes")) { - for (int i = 1; i <= 5; i++) { - prop.put("showtable_list_" + count + "_scheduler_scale_" + i + "_time", i * 10); - prop.put("showtable_list_" + count + "_scheduler_scale_" + i + "_selected", 0); - } - prop.put("showtable_list_" + count + "_scheduler_scale_" + (time / 10) + "_selected", 1); - prop.put("showtable_list_" + count + "_scheduler_scale", 6); - prop.put("showtable_list_" + count + "_scheduler_selectedMinutes", 1); - } else if (unit.equals("hours")) { - for (int i = 1; i <= 23; i++) { - prop.put("showtable_list_" + count + "_scheduler_scale_" + i + "_time", i); - prop.put("showtable_list_" + count + "_scheduler_scale_" + i + "_selected", 0); - } - prop.put("showtable_list_" + count + "_scheduler_scale_" + time + "_selected", 1); - prop.put("showtable_list_" + count + "_scheduler_scale", 24); - prop.put("showtable_list_" + count + "_scheduler_selectedHours", 1); - } else { - for (int i = 1; i <= 30; i++) { - prop.put("showtable_list_" + count + "_scheduler_scale_" + i + "_time", i); - prop.put("showtable_list_" + count + "_scheduler_scale_" + i + "_selected", 0); - } - prop.put("showtable_list_" + count + "_scheduler_scale_" + time + "_selected", 1); - prop.put("showtable_list_" + count + "_scheduler_scale", 31); - prop.put("showtable_list_" + count + "_scheduler_selectedDays", 1); - } - - } - count++; - } - prop.put("showtable_hasEditableNextExecDate", scheduledactions); - if (scheduledactions) { - prop.put("showschedulerhint", 1); - prop.put("showschedulerhint_tfminutes", sb.getConfigLong(SwitchboardConstants.CLEANUP_BUSYSLEEP, 300000) / 60000); - } else { - prop.put("showschedulerhint", 0); - } - } catch (final IOException e) { - ConcurrentLog.logException(e); - } - prop.put("showtable_list", count); - prop.put("showtable_num", count); - - // write navigation details - prop.put("showtable_startRecord", startRecord); - prop.put("showtable_maximumRecords", maximumRecords); - prop.put("showtable_inline", (inline) ? 1 : 0); - prop.put("showtable_filter", typefilter.pattern()); - prop.put("showtable_query", queryParam); - prop.put("showtable_sort", sortParam); - - putTableSortProperties(prop, sortDir, sortColumn); - - if (filteredSize > maximumRecords) { - prop.put("showtable_navigation", 1); - prop.put("showtable_navigation_startRecord", startRecord); - prop.put("showtable_navigation_to", Math.min(filteredSize, startRecord + table.size())); - prop.put("showtable_navigation_of", filteredSize); - prop.put("showtable_navigation_left", startRecord == 0 ? 0 : 1); - prop.put("showtable_navigation_left_startRecord", Math.max(0, startRecord - maximumRecords)); - prop.put("showtable_navigation_left_maximumRecords", maximumRecords); - prop.put("showtable_navigation_left_inline", (inline) ? 1 : 0); - prop.put("showtable_navigation_left_filter", typefilter.pattern()); - prop.put("showtable_navigation_left_query", queryParam); - prop.put("showtable_navigation_left_sort", sortParam); - prop.put("showtable_navigation_left", startRecord == 0 ? 0 : 1); - prop.put("showtable_navigation_filter", typefilter.pattern()); - prop.put("showtable_navigation_right", startRecord + maximumRecords >= filteredSize ? 0 : 1); - prop.put("showtable_navigation_right_startRecord", startRecord + maximumRecords); - prop.put("showtable_navigation_right_maximumRecords", maximumRecords); - prop.put("showtable_navigation_right_inline", (inline) ? 1 : 0); - prop.put("showtable_navigation_right_filter", typefilter.pattern()); - prop.put("showtable_navigation_right_query", queryParam); - prop.put("showtable_navigation_right_sort", sortParam); - } else { - prop.put("showtable_navigation", 0); - } - - // return rewrite properties - return prop; - } - - /** - * Fill the serverObjects instance with table columns sort properties. - * - * @param prop - * the serverObjects instance to fill. Must not be null. - * @param sortDir - * the current sort direction - * @param sortColumn - * the current sort column - */ - private static void putTableSortProperties(final serverObjects prop, final SortDirection sortDir, - final String sortColumn) { - boolean sortedByAsc = WorkTables.TABLE_API_COL_TYPE.equals(sortColumn) && sortDir == SortDirection.ASC; - prop.put("showtable_sortedByType", WorkTables.TABLE_API_COL_TYPE.equals(sortColumn)); - prop.put("showtable_sortedByType_asc", sortedByAsc); - prop.put("showtable_nextSortTypeDesc", sortedByAsc); - - sortedByAsc = WorkTables.TABLE_API_COL_COMMENT.equals(sortColumn) && sortDir == SortDirection.ASC; - prop.put("showtable_sortedByComment", WorkTables.TABLE_API_COL_COMMENT.equals(sortColumn)); - prop.put("showtable_sortedByComment_asc", sortedByAsc); - prop.put("showtable_nextSortCommentDesc", sortedByAsc); - - sortedByAsc = WorkTables.TABLE_API_COL_APICALL_COUNT.equals(sortColumn) && sortDir == SortDirection.ASC; - prop.put("showtable_sortedByApiCallCount", WorkTables.TABLE_API_COL_APICALL_COUNT.equals(sortColumn)); - prop.put("showtable_sortedByApiCallCount_asc", sortedByAsc); - prop.put("showtable_nextSortApiCallCountDesc", sortedByAsc); - - sortedByAsc = WorkTables.TABLE_API_COL_DATE_RECORDING.equals(sortColumn) && sortDir == SortDirection.ASC; - prop.put("showtable_sortedByDateRecording", WorkTables.TABLE_API_COL_DATE_RECORDING.equals(sortColumn)); - prop.put("showtable_sortedByDateRecording_asc", sortedByAsc); - prop.put("showtable_nextSortDateRecordingDesc", sortedByAsc); - - sortedByAsc = WorkTables.TABLE_API_COL_DATE_LAST_EXEC.equals(sortColumn) && sortDir == SortDirection.ASC; - prop.put("showtable_sortedByDateLastExec", WorkTables.TABLE_API_COL_DATE_LAST_EXEC.equals(sortColumn)); - prop.put("showtable_sortedByDateLastExec_asc", sortedByAsc); - prop.put("showtable_nextSortDateLastExecDesc", sortedByAsc); - - sortedByAsc = WorkTables.TABLE_API_COL_DATE_NEXT_EXEC.equals(sortColumn) && sortDir == SortDirection.ASC; - prop.put("showtable_sortedByDateNextExec", WorkTables.TABLE_API_COL_DATE_NEXT_EXEC.equals(sortColumn)); - prop.put("showtable_sortedByDateNextExec_asc", sortedByAsc); - prop.put("showtable_nextSortDateNextExecDesc", sortedByAsc); - } -} -- cgit v1.2.3