add #963 Admin API: /api/admin/backup

This commit is contained in:
Keiichi Watanabe 2017-04-29 17:23:23 +09:00
parent 49a5412e6e
commit 164a273b6d
3 changed files with 177 additions and 23 deletions

View file

@ -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<CsvWriter> 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<CsvWriter> 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<CsvWriter> 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<CsvWriter> 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<CsvWriter> 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<String> list) {
private static void addToList(final Object value, final List<String> list) {
if (value == null) {
list.add(StringUtil.EMPTY);
} else if (value instanceof LocalDateTime) {
@ -326,7 +327,8 @@ public class AdminBackupAction extends FessAdminAction {
}
}
private List<Map<String, String>> getBackupItems() {
static public List<Map<String, String>> getBackupItems() {
FessConfig fessConfig = ComponentUtil.getFessConfig();
return stream(fessConfig.getIndexBackupAllTargets()).get(stream -> stream.map(name -> {
final Map<String, String> map = new HashMap<>();
map.put("id", name);

View file

@ -169,6 +169,26 @@ public class ApiResult {
}
}
public static class ApiFilesResponse extends ApiResponse {
protected List<Map<String, String>> files;
protected long total = 0;
public ApiFilesResponse backupfiles(final List<Map<String, String>> 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;

View file

@ -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<ApiResult> files() {
final List<Map<String, String>> 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<CsvWriter> 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();
}
});
}
}