View Javadoc
1   /*
2    * Copyright 2012-2021 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.app.web.api.admin.backup;
17  
18  import static org.codelibs.core.stream.StreamUtil.stream;
19  import static org.codelibs.fess.app.web.admin.backup.AdminBackupAction.NDJSON_EXTENTION;
20  import static org.codelibs.fess.app.web.admin.backup.AdminBackupAction.getBackupItems;
21  import static org.codelibs.fess.app.web.admin.backup.AdminBackupAction.getClickLogNdjsonWriteCall;
22  import static org.codelibs.fess.app.web.admin.backup.AdminBackupAction.getFavoriteLogNdjsonWriteCall;
23  import static org.codelibs.fess.app.web.admin.backup.AdminBackupAction.getSearchLogNdjsonWriteCall;
24  import static org.codelibs.fess.app.web.admin.backup.AdminBackupAction.getUserInfoNdjsonWriteCall;
25  
26  import java.io.BufferedWriter;
27  import java.io.ByteArrayInputStream;
28  import java.io.ByteArrayOutputStream;
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.io.OutputStreamWriter;
32  import java.io.Writer;
33  import java.util.List;
34  import java.util.Map;
35  import java.util.function.Consumer;
36  
37  import org.apache.commons.text.StringEscapeUtils;
38  import org.codelibs.core.exception.IORuntimeException;
39  import org.codelibs.fess.Constants;
40  import org.codelibs.fess.app.web.api.ApiResult;
41  import org.codelibs.fess.app.web.api.ApiResult.ApiBackupFilesResponse;
42  import org.codelibs.fess.app.web.api.admin.FessApiAdminAction;
43  import org.codelibs.fess.mylasta.direction.FessConfig;
44  import org.codelibs.fess.util.ComponentUtil;
45  import org.codelibs.fess.util.SearchEngineUtil;
46  import org.lastaflute.web.Execute;
47  import org.lastaflute.web.response.JsonResponse;
48  import org.lastaflute.web.response.StreamResponse;
49  
50  /**
51   * @author Keiichi Watanabe
52   */
53  public class ApiAdminBackupAction extends FessApiAdminAction {
54  
55      // GET /api/admin/backup/files
56      @Execute
57      public JsonResponse<ApiResult> files() {
58          final List<Map<String, String>> list = getBackupItems();
59          return asJson(new ApiBackupFilesResponse().files(list).total(list.size()).status(ApiResult.Status.OK).result());
60      }
61  
62      // GET /api/admin/backup/file/{id}
63      @Execute
64      public StreamResponse get$file(final String id) {
65          final FessConfig fessConfig = ComponentUtil.getFessConfig();
66          if (stream(fessConfig.getIndexBackupAllTargets()).get(stream -> stream.anyMatch(s -> s.equals(id)))) {
67              if ("system.properties".equals(id)) {
68                  return asStream(id).contentTypeOctetStream().stream(out -> {
69                      try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
70                          ComponentUtil.getSystemProperties().store(baos, id);
71                          try (final InputStream in = new ByteArrayInputStream(baos.toByteArray())) {
72                              out.write(in);
73                          }
74                      }
75                  });
76              }
77              if (!id.endsWith(NDJSON_EXTENTION)) {
78                  final String index;
79                  final String filename;
80                  if (id.endsWith(".bulk")) {
81                      index = id.substring(0, id.length() - 5);
82                      filename = id;
83                  } else {
84                      index = id;
85                      filename = id + ".bulk";
86                  }
87                  return asStream(filename).contentTypeOctetStream().stream(out -> {
88                      try (final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out.stream(), Constants.CHARSET_UTF_8))) {
89                          SearchEngineUtil.scroll(index, hit -> {
90                              try {
91                                  writer.write("{\"index\":{\"_index\":\"" + index + "\",\"_id\":\""
92                                          + StringEscapeUtils.escapeJson(hit.getId()) + "\"}}\n");
93                                  writer.write(hit.getSourceAsString());
94                                  writer.write("\n");
95                              } catch (final IOException e) {
96                                  throw new IORuntimeException(e);
97                              }
98                              return true;
99                          });
100                         writer.flush();
101                     }
102                 });
103             }
104             final String name = id.substring(0, id.length() - NDJSON_EXTENTION.length());
105             if ("search_log".equals(name)) {
106                 return writeNdjsonResponse(id, getSearchLogNdjsonWriteCall());
107             } else if ("user_info".equals(name)) {
108                 return writeNdjsonResponse(id, getUserInfoNdjsonWriteCall());
109             } else if ("click_log".equals(name)) {
110                 return writeNdjsonResponse(id, getClickLogNdjsonWriteCall());
111             } else if ("favorite_log".equals(name)) {
112                 return writeNdjsonResponse(id, getFavoriteLogNdjsonWriteCall());
113             }
114         }
115 
116         throwValidationErrorApi(messages -> messages.addErrorsCouldNotFindBackupIndex(GLOBAL));
117         return StreamResponse.asEmptyBody(); // no-op
118     }
119 
120     private StreamResponse writeNdjsonResponse(final String id, final Consumer<Writer> writeCall) {
121         return asStream(id)//
122                 .header("Pragma", "no-cache")//
123                 .header("Cache-Control", "no-cache")//
124                 .header("Expires", "Thu, 01 Dec 1994 16:00:00 GMT")//
125                 .header("Content-Type", "application/x-ndjson")//
126                 .stream(out -> {
127                     try (final Writer writer = new BufferedWriter(new OutputStreamWriter(out.stream(), Constants.CHARSET_UTF_8))) {
128                         writeCall.accept(writer);
129                         writer.flush();
130                     }
131                 });
132     }
133 }