diff --git a/src/main/java/org/codelibs/fess/app/web/admin/backup/AdminBackupAction.java b/src/main/java/org/codelibs/fess/app/web/admin/backup/AdminBackupAction.java index f78b9da8a..8510f5a67 100644 --- a/src/main/java/org/codelibs/fess/app/web/admin/backup/AdminBackupAction.java +++ b/src/main/java/org/codelibs/fess/app/web/admin/backup/AdminBackupAction.java @@ -46,6 +46,7 @@ import org.codelibs.fess.es.log.exbhv.FavoriteLogBhv; import org.codelibs.fess.es.log.exbhv.SearchFieldLogBhv; import org.codelibs.fess.es.log.exbhv.SearchLogBhv; import org.codelibs.fess.es.log.exbhv.UserInfoBhv; +import org.codelibs.fess.mylasta.direction.FessConfig; import org.codelibs.fess.util.ComponentUtil; import org.codelibs.fess.util.RenderDataUtil; import org.codelibs.fess.util.ResourceUtil; @@ -69,7 +70,7 @@ public class AdminBackupAction extends FessAdminAction { private static final Logger logger = LoggerFactory.getLogger(AdminBackupAction.class); - private static final String CSV_EXTENTION = ".csv"; + public static final String CSV_EXTENTION = ".csv"; private static final DateTimeFormatter ISO_8601_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"); @@ -139,15 +140,15 @@ public class AdminBackupAction extends FessAdminAction { } else if (id.endsWith(CSV_EXTENTION)) { final String name = id.substring(0, id.length() - CSV_EXTENTION.length()); if ("search_log".equals(name)) { - return writeSearchLogCsvResponse(id); + return writeCsvResponse(id, getSearchLogCsvWriteCall()); } else if ("search_field_log".equals(name)) { - return writeSearchFieldLogCsvResponse(id); + return writeCsvResponse(id, getSearchFieldLogCsvWriteCall()); } else if ("user_info".equals(name)) { - return writeUserInfoCsvResponse(id); + return writeCsvResponse(id, getUserInfoCsvWriteCall()); } else if ("click_log".equals(name)) { - return writeClickLogCsvResponse(id); + return writeCsvResponse(id, getClickLogCsvWriteCall()); } else if ("favorite_log".equals(name)) { - return writeFavoriteLogCsvResponse(id); + return writeCsvResponse(id, getFavoriteLogCsvWriteCall()); } } else { final String index; @@ -195,8 +196,8 @@ public class AdminBackupAction extends FessAdminAction { }); } - private StreamResponse writeSearchLogCsvResponse(final String id) { - return writeCsvResponse(id, writer -> { + public static Consumer getSearchLogCsvWriteCall() { + return writer -> { final SearchLogBhv bhv = ComponentUtil.getComponent(SearchLogBhv.class); bhv.selectCursor(cb -> { cb.query().matchAll(); @@ -226,11 +227,11 @@ public class AdminBackupAction extends FessAdminAction { throw new RuntimeIOException(e); } }); - }); + }; } - private StreamResponse writeUserInfoCsvResponse(final String id) { - return writeCsvResponse(id, writer -> { + public static Consumer getUserInfoCsvWriteCall() { + return writer -> { final UserInfoBhv bhv = ComponentUtil.getComponent(UserInfoBhv.class); bhv.selectCursor(cb -> { cb.query().matchAll(); @@ -245,11 +246,11 @@ public class AdminBackupAction extends FessAdminAction { throw new RuntimeIOException(e); } }); - }); + }; } - private StreamResponse writeFavoriteLogCsvResponse(final String id) { - return writeCsvResponse(id, writer -> { + public static Consumer getFavoriteLogCsvWriteCall() { + return writer -> { final FavoriteLogBhv bhv = ComponentUtil.getComponent(FavoriteLogBhv.class); bhv.selectCursor(cb -> { cb.query().matchAll(); @@ -267,11 +268,11 @@ public class AdminBackupAction extends FessAdminAction { throw new RuntimeIOException(e); } }); - }); + }; } - private StreamResponse writeClickLogCsvResponse(final String id) { - return writeCsvResponse(id, writer -> { + public static Consumer getClickLogCsvWriteCall() { + return writer -> { final ClickLogBhv bhv = ComponentUtil.getComponent(ClickLogBhv.class); bhv.selectCursor(cb -> { cb.query().matchAll(); @@ -291,11 +292,11 @@ public class AdminBackupAction extends FessAdminAction { throw new RuntimeIOException(e); } }); - }); + }; } - private StreamResponse writeSearchFieldLogCsvResponse(final String id) { - return writeCsvResponse(id, writer -> { + public static Consumer getSearchFieldLogCsvWriteCall() { + return writer -> { final SearchFieldLogBhv bhv = ComponentUtil.getComponent(SearchFieldLogBhv.class); bhv.selectCursor(cb -> { cb.query().matchAll(); @@ -311,10 +312,10 @@ public class AdminBackupAction extends FessAdminAction { throw new RuntimeIOException(e); } }); - }); + }; } - private void addToList(final Object value, final List list) { + private static void addToList(final Object value, final List list) { if (value == null) { list.add(StringUtil.EMPTY); } else if (value instanceof LocalDateTime) { @@ -326,7 +327,8 @@ public class AdminBackupAction extends FessAdminAction { } } - private List> getBackupItems() { + static public List> getBackupItems() { + FessConfig fessConfig = ComponentUtil.getFessConfig(); return stream(fessConfig.getIndexBackupAllTargets()).get(stream -> stream.map(name -> { final Map map = new HashMap<>(); map.put("id", name); diff --git a/src/main/java/org/codelibs/fess/app/web/api/ApiResult.java b/src/main/java/org/codelibs/fess/app/web/api/ApiResult.java index fedc9970a..1040a3c22 100644 --- a/src/main/java/org/codelibs/fess/app/web/api/ApiResult.java +++ b/src/main/java/org/codelibs/fess/app/web/api/ApiResult.java @@ -169,6 +169,26 @@ public class ApiResult { } } + public static class ApiFilesResponse extends ApiResponse { + protected List> files; + protected long total = 0; + + public ApiFilesResponse backupfiles(final List> files) { + this.files = files; + return this; + } + + public ApiFilesResponse total(final long total) { + this.total = total; + return this; + } + + @Override + public ApiResult result() { + return new ApiResult(this); + } + } + public static class ApiErrorResponse extends ApiResponse { protected String message; diff --git a/src/main/java/org/codelibs/fess/app/web/api/admin/backup/ApiAdminBackupAction.java b/src/main/java/org/codelibs/fess/app/web/api/admin/backup/ApiAdminBackupAction.java new file mode 100644 index 000000000..71febaa28 --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/web/api/admin/backup/ApiAdminBackupAction.java @@ -0,0 +1,132 @@ +/* + * Copyright 2012-2017 CodeLibs Project and the Others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.codelibs.fess.app.web.api.admin.backup; + +import static org.codelibs.core.stream.StreamUtil.stream; +import static org.codelibs.fess.app.web.admin.backup.AdminBackupAction.CSV_EXTENTION; +import static org.codelibs.fess.app.web.admin.backup.AdminBackupAction.getBackupItems; +import static org.codelibs.fess.app.web.admin.backup.AdminBackupAction.getClickLogCsvWriteCall; +import static org.codelibs.fess.app.web.admin.backup.AdminBackupAction.getFavoriteLogCsvWriteCall; +import static org.codelibs.fess.app.web.admin.backup.AdminBackupAction.getSearchFieldLogCsvWriteCall; +import static org.codelibs.fess.app.web.admin.backup.AdminBackupAction.getSearchLogCsvWriteCall; +import static org.codelibs.fess.app.web.admin.backup.AdminBackupAction.getUserInfoCsvWriteCall; + +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import org.codelibs.elasticsearch.runner.net.Curl; +import org.codelibs.elasticsearch.runner.net.CurlResponse; +import org.codelibs.fess.app.web.api.ApiResult; +import org.codelibs.fess.app.web.api.ApiResult.ApiFilesResponse; +import org.codelibs.fess.app.web.api.admin.FessApiAdminAction; +import org.codelibs.fess.mylasta.direction.FessConfig; +import org.codelibs.fess.util.ComponentUtil; +import org.codelibs.fess.util.ResourceUtil; +import org.lastaflute.web.Execute; +import org.lastaflute.web.response.JsonResponse; +import org.lastaflute.web.response.StreamResponse; + +import com.orangesignal.csv.CsvConfig; +import com.orangesignal.csv.CsvWriter; + +/** + * @author Keiichi Watanabe + */ +public class ApiAdminBackupAction extends FessApiAdminAction { + + // GET /api/admin/backup/files + @Execute + public JsonResponse files() { + final List> list = getBackupItems(); + return asJson(new ApiFilesResponse().backupfiles(list).total(list.size()).status(ApiResult.Status.OK).result()); + } + + // GET /api/admin/backup/file/{id} + @Execute + public StreamResponse get$file(final String id) { + FessConfig fessConfig = ComponentUtil.getFessConfig(); + if (stream(fessConfig.getIndexBackupAllTargets()).get(stream -> stream.anyMatch(s -> s.equals(id)))) { + if (id.equals("system.properties")) { + return asStream(id).contentTypeOctetStream().stream(out -> { + try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + ComponentUtil.getSystemProperties().store(baos, id); + try (final InputStream in = new ByteArrayInputStream(baos.toByteArray())) { + out.write(in); + } + } + }); + } else if (id.endsWith(CSV_EXTENTION)) { + final String name = id.substring(0, id.length() - CSV_EXTENTION.length()); + if ("search_log".equals(name)) { + return writeCsvResponse(id, getSearchLogCsvWriteCall()); + } else if ("search_field_log".equals(name)) { + return writeCsvResponse(id, getSearchFieldLogCsvWriteCall()); + } else if ("user_info".equals(name)) { + return writeCsvResponse(id, getUserInfoCsvWriteCall()); + } else if ("click_log".equals(name)) { + return writeCsvResponse(id, getClickLogCsvWriteCall()); + } else if ("favorite_log".equals(name)) { + return writeCsvResponse(id, getFavoriteLogCsvWriteCall()); + } + } else { + final String index; + final String filename; + if (id.endsWith(".bulk")) { + index = id.substring(0, id.length() - 5); + filename = id; + } else { + index = id; + filename = id + ".bulk"; + } + return asStream(filename).contentTypeOctetStream().stream( + out -> { + try (CurlResponse response = + Curl.get(ResourceUtil.getElasticsearchHttpUrl() + "/" + index + "/_data") + .header("Content-Type", "application/json").param("format", "json").execute()) { + out.write(response.getContentAsStream()); + } + }); + } + } + + throwValidationErrorApi(messages -> messages.addErrorsCouldNotFindBackupIndex(GLOBAL)); + return StreamResponse.asEmptyBody(); // no-op + } + + private StreamResponse writeCsvResponse(final String id, final Consumer writeCall) { + return asStream(id) + .contentTypeOctetStream() + .header("Pragma", "no-cache") + .header("Cache-Control", "no-cache") + .header("Expires", "Thu, 01 Dec 1994 16:00:00 GMT") + .stream(out -> { + final CsvConfig cfg = new CsvConfig(',', '"', '"'); + cfg.setEscapeDisabled(false); + cfg.setQuoteDisabled(false); + try (final CsvWriter writer = + new CsvWriter(new BufferedWriter(new OutputStreamWriter(out.stream(), fessConfig.getCsvFileEncoding())), cfg)) { + writeCall.accept(writer); + writer.flush(); + } + }); + } +}