Merge pull request #1014 from kw-udon/add-admin-api-April-29

Add Admin API: backup & systeminfo
This commit is contained in:
Shinsuke Sugaya 2017-04-29 22:47:42 +09:00 committed by GitHub
commit 78997008e2
6 changed files with 296 additions and 41 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

@ -26,6 +26,7 @@ import org.codelibs.core.lang.StringUtil;
import org.codelibs.core.misc.DynamicProperties;
import org.codelibs.fess.Constants;
import org.codelibs.fess.app.web.base.FessAdminAction;
import org.codelibs.fess.util.ComponentUtil;
import org.codelibs.fess.util.RenderDataUtil;
import org.lastaflute.web.Execute;
import org.lastaflute.web.response.HtmlResponse;
@ -74,56 +75,74 @@ public class AdminSysteminfoAction extends FessAdminAction {
// ============
protected void registerEnvItems(final RenderData data) {
RenderDataUtil.register(data, "envItems", getEnvItems());
}
protected void registerPropItems(final RenderData data) {
RenderDataUtil.register(data, "propItems", getPropItems());
}
protected void registerFessPropItems(final RenderData data) {
RenderDataUtil.register(data, "fessPropItems", getFessPropItems());
}
protected void registerBugReportItems(final RenderData data) {
RenderDataUtil.register(data, "bugReportItems", getBugReportItems());
}
public static List<Map<String, String>> getEnvItems() {
final List<Map<String, String>> itemList = new ArrayList<>();
for (final Map.Entry<String, String> entry : System.getenv().entrySet()) {
itemList.add(createItem(entry.getKey(), entry.getValue()));
}
RenderDataUtil.register(data, "envItems", itemList);
return itemList;
}
protected void registerPropItems(final RenderData data) {
public static List<Map<String, String>> getPropItems() {
final List<Map<String, String>> itemList = new ArrayList<>();
for (final Map.Entry<Object, Object> entry : System.getProperties().entrySet()) {
itemList.add(createItem(entry.getKey(), entry.getValue()));
}
RenderDataUtil.register(data, "propItems", itemList);
return itemList;
}
protected void registerFessPropItems(final RenderData data) {
public static List<Map<String, String>> getFessPropItems() {
final List<Map<String, String>> itemList = new ArrayList<>();
final DynamicProperties systemProperties = ComponentUtil.getSystemProperties();
for (final Map.Entry<Object, Object> entry : systemProperties.entrySet()) {
itemList.add(createItem(entry.getKey(), entry.getValue()));
}
RenderDataUtil.register(data, "fessPropItems", itemList);
return itemList;
}
protected void registerBugReportItems(final RenderData data) {
public static List<Map<String, String>> getBugReportItems() {
final List<Map<String, String>> itemList = new ArrayList<>();
for (final String label : bugReportLabels) {
itemList.add(createPropItem(label));
}
final DynamicProperties systemProperties = ComponentUtil.getSystemProperties();
for (final Map.Entry<Object, Object> entry : systemProperties.entrySet()) {
if (isBugReportTarget(entry.getKey())) {
itemList.add(createItem(entry.getKey(), entry.getValue()));
}
}
RenderDataUtil.register(data, "bugReportItems", itemList);
return itemList;
}
private boolean isBugReportTarget(final Object key) {
private static boolean isBugReportTarget(final Object key) {
if ("snapshot.path".equals(key) || "label.value".equals(key)) {
return false;
}
return true;
}
protected Map<String, String> createPropItem(final String key) {
protected static Map<String, String> createPropItem(final String key) {
return createItem(key, System.getProperty(key));
}
protected Map<String, String> createItem(final Object label, final Object value) {
protected static Map<String, String> createItem(final Object label, final Object value) {
final Map<String, String> map = new HashMap<>(2);
map.put(Constants.ITEM_LABEL, label != null ? label.toString() : StringUtil.EMPTY);
map.put(Constants.ITEM_VALUE, value != null ? value.toString() : StringUtil.EMPTY);

View file

@ -150,11 +150,11 @@ public class ApiResult {
}
public static class ApiLogFilesResponse extends ApiResponse {
protected List<Map<String, Object>> logfiles;
protected List<Map<String, Object>> files;
protected long total = 0;
public ApiLogFilesResponse logfiles(final List<Map<String, Object>> logfiles) {
this.logfiles = logfiles;
public ApiLogFilesResponse files(final List<Map<String, Object>> files) {
this.files = files;
return this;
}
@ -169,6 +169,58 @@ public class ApiResult {
}
}
public static class ApiBackupFilesResponse extends ApiResponse {
protected List<Map<String, String>> files;
protected long total = 0;
public ApiBackupFilesResponse files(final List<Map<String, String>> files) {
this.files = files;
return this;
}
public ApiBackupFilesResponse total(final long total) {
this.total = total;
return this;
}
@Override
public ApiResult result() {
return new ApiResult(this);
}
}
public static class ApiSystemInfoResponse extends ApiResponse {
protected List<Map<String, String>> envProps;
protected List<Map<String, String>> systemProps;
protected List<Map<String, String>> fessProps;
protected List<Map<String, String>> bugReportProps;
public ApiSystemInfoResponse envProps(final List<Map<String, String>> envProps) {
this.envProps = envProps;
return this;
}
public ApiSystemInfoResponse systemProps(final List<Map<String, String>> systemProps) {
this.systemProps = systemProps;
return this;
}
public ApiSystemInfoResponse fessProps(final List<Map<String, String>> fessProps) {
this.fessProps = fessProps;
return this;
}
public ApiSystemInfoResponse bugReportProps(final List<Map<String, String>> bugReportProps) {
this.bugReportProps = bugReportProps;
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.ApiBackupFilesResponse;
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 ApiBackupFilesResponse().files(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();
}
});
}
}

View file

@ -42,16 +42,16 @@ public class ApiAdminLogAction extends FessApiAdminAction {
// Search Execute
// ==============
// GET /api/admin/log/logfiles
// GET /api/admin/log/files
@Execute
public JsonResponse<ApiResult> logfiles() {
public JsonResponse<ApiResult> files() {
final List<Map<String, Object>> list = getLogFileItems();
return asJson(new ApiResult.ApiLogFilesResponse().logfiles(list).total(list.size()).status(ApiResult.Status.OK).result());
return asJson(new ApiResult.ApiLogFilesResponse().files(list).total(list.size()).status(ApiResult.Status.OK).result());
}
// GET /api/admin/log/logfile/{id}
// GET /api/admin/log/file/{id}
@Execute
public StreamResponse get$logfile(final String id) {
public StreamResponse get$file(final String id) {
final String filename = new String(Base64.getDecoder().decode(id), StandardCharsets.UTF_8).replace("..", "").replaceAll("\\s", "");
final String logFilePath = systemHelper.getLogFilePath();
if (StringUtil.isNotBlank(logFilePath)) {

View file

@ -0,0 +1,50 @@
/*
* 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.systeminfo;
import static org.codelibs.fess.app.web.admin.systeminfo.AdminSysteminfoAction.getBugReportItems;
import static org.codelibs.fess.app.web.admin.systeminfo.AdminSysteminfoAction.getEnvItems;
import static org.codelibs.fess.app.web.admin.systeminfo.AdminSysteminfoAction.getFessPropItems;
import static org.codelibs.fess.app.web.admin.systeminfo.AdminSysteminfoAction.getPropItems;
import java.util.List;
import java.util.Map;
import org.codelibs.fess.app.web.api.ApiResult;
import org.codelibs.fess.app.web.api.admin.FessApiAdminAction;
import org.lastaflute.web.Execute;
import org.lastaflute.web.response.JsonResponse;
/**
* @author Keiichi Watanabe
*/
public class ApiAdminSysteminfoAction extends FessApiAdminAction {
// ===================================================================================
// Search Execute
// ==============
// GET /api/admin/systeminfo/info
@Execute
public JsonResponse<ApiResult> info() {
final List<Map<String, String>> bugReportItems = getBugReportItems();
final List<Map<String, String>> envItems = getEnvItems();
final List<Map<String, String>> fessPropItems = getFessPropItems();
final List<Map<String, String>> propItems = getPropItems();
return asJson(new ApiResult.ApiSystemInfoResponse().bugReportProps(bugReportItems).envProps(envItems).fessProps(fessPropItems)
.systemProps(propItems).status(ApiResult.Status.OK).result());
}
}