View Javadoc
1   /*
2    * Copyright 2012-2025 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.pathmap;
17  
18  import static org.codelibs.fess.app.web.admin.pathmap.AdminPathmapAction.getPathMapping;
19  
20  import java.util.List;
21  import java.util.stream.Collectors;
22  
23  import org.apache.logging.log4j.LogManager;
24  import org.apache.logging.log4j.Logger;
25  import org.codelibs.fess.Constants;
26  import org.codelibs.fess.app.pager.PathMapPager;
27  import org.codelibs.fess.app.service.PathMappingService;
28  import org.codelibs.fess.app.web.CrudMode;
29  import org.codelibs.fess.app.web.api.ApiResult;
30  import org.codelibs.fess.app.web.api.admin.FessApiAdminAction;
31  import org.codelibs.fess.opensearch.config.exentity.PathMapping;
32  import org.lastaflute.web.Execute;
33  import org.lastaflute.web.response.JsonResponse;
34  
35  import jakarta.annotation.Resource;
36  
37  /**
38   * API action for admin path mapping management.
39   * Provides RESTful API endpoints for managing path mapping settings in the Fess search engine.
40   * Path mappings define URL path transformations and redirections for crawling and indexing.
41   */
42  public class ApiAdminPathmapAction extends FessApiAdminAction {
43  
44      private static final Logger logger = LogManager.getLogger(ApiAdminPathmapAction.class);
45  
46      // ===================================================================================
47      //                                                                         Constructor
48      //                                                                         ===========
49      /**
50       * Default constructor.
51       */
52      public ApiAdminPathmapAction() {
53          super();
54      }
55  
56      // ===================================================================================
57      //                                                                           Attribute
58      //                                                                           =========
59  
60      /** Service for managing path mapping configurations */
61      @Resource
62      private PathMappingService pathMappingService;
63  
64      // GET /api/admin/pathmap
65      // PUT /api/admin/pathmap
66      /**
67       * Returns list of path mapping settings.
68       * Supports both GET and PUT requests for retrieving paginated path mapping configurations.
69       *
70       * @param body search parameters for filtering and pagination
71       * @return JSON response containing path mapping settings list with pagination info
72       */
73      @Execute
74      public JsonResponse<ApiResult> settings(final SearchBody body) {
75          validateApi(body, messages -> {});
76          final PathMapPager pager = copyBeanToNewBean(body, PathMapPager.class);
77          final List<PathMapping> list = pathMappingService.getPathMappingList(pager);
78          return asJson(
79                  new ApiResult.ApiConfigsResponse<EditBody>().settings(list.stream().map(this::createEditBody).collect(Collectors.toList()))
80                          .total(pager.getAllRecordCount())
81                          .status(ApiResult.Status.OK)
82                          .result());
83      }
84  
85      // GET /api/admin/pathmap/setting/{id}
86      /**
87       * Returns specific path mapping setting by ID.
88       *
89       * @param id the path mapping setting ID
90       * @return JSON response containing the path mapping setting details
91       */
92      @Execute
93      public JsonResponse<ApiResult> get$setting(final String id) {
94          return asJson(
95                  new ApiResult.ApiConfigResponse().setting(pathMappingService.getPathMapping(id).map(this::createEditBody).orElseGet(() -> {
96                      throwValidationErrorApi(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id));
97                      return null;
98                  })).status(ApiResult.Status.OK).result());
99      }
100 
101     // POST /api/admin/pathmap/setting
102     /**
103      * Creates a new path mapping setting.
104      *
105      * @param body path mapping setting data to create
106      * @return JSON response with created setting ID and status
107      */
108     @Execute
109     public JsonResponse<ApiResult> post$setting(final CreateBody body) {
110         validateApi(body, messages -> {});
111         body.crudMode = CrudMode.CREATE;
112         final PathMapping entity = getPathMapping(body).orElseGet(() -> {
113             throwValidationErrorApi(messages -> {
114                 messages.addErrorsCrudFailedToCreateInstance(GLOBAL);
115             });
116             return null;
117         });
118         try {
119             pathMappingService.store(entity);
120             saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
121         } catch (final Exception e) {
122             logger.warn("Failed to process a request.", e);
123             throwValidationErrorApi(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)));
124         }
125         return asJson(new ApiResult.ApiUpdateResponse().id(entity.getId()).created(true).status(ApiResult.Status.OK).result());
126     }
127 
128     // PUT /api/admin/pathmap/setting
129     /**
130      * Updates an existing path mapping setting.
131      *
132      * @param body path mapping setting data to update
133      * @return JSON response with updated setting ID and status
134      */
135     @Execute
136     public JsonResponse<ApiResult> put$setting(final EditBody body) {
137         validateApi(body, messages -> {});
138         body.crudMode = CrudMode.EDIT;
139         final PathMapping entity = getPathMapping(body).orElseGet(() -> {
140             throwValidationErrorApi(messages -> {
141                 messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, body.id);
142             });
143             return null;
144         });
145         try {
146             pathMappingService.store(entity);
147         } catch (final Exception e) {
148             logger.warn("Failed to process a request.", e);
149             throwValidationErrorApi(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)));
150         }
151         return asJson(new ApiResult.ApiUpdateResponse().id(entity.getId()).created(false).status(ApiResult.Status.OK).result());
152     }
153 
154     // DELETE /api/admin/pathmap/setting/{id}
155     /**
156      * Deletes a specific path mapping setting.
157      *
158      * @param id the path mapping setting ID to delete
159      * @return JSON response with deletion status
160      */
161     @Execute
162     public JsonResponse<ApiResult> delete$setting(final String id) {
163         final PathMapping entity = pathMappingService.getPathMapping(id).orElseGet(() -> {
164             throwValidationErrorApi(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id));
165             return null;
166         });
167         try {
168             pathMappingService.delete(entity);
169             saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL));
170         } catch (final Exception e) {
171             logger.warn("Failed to process a request.", e);
172             throwValidationErrorApi(messages -> messages.addErrorsCrudFailedToDeleteCrudTable(GLOBAL, buildThrowableMessage(e)));
173         }
174         return asJson(new ApiResult.ApiUpdateResponse().id(id).created(false).status(ApiResult.Status.OK).result());
175     }
176 
177     /**
178      * Creates an edit body from a path mapping entity for API responses.
179      *
180      * @param entity the path mapping entity to convert
181      * @return edit body containing the entity data
182      */
183     protected EditBody createEditBody(final PathMapping entity) {
184         final EditBody body = new EditBody();
185         copyBeanToBean(entity, body, op -> op.exclude(Constants.COMMON_CONVERSION_RULE));
186         return body;
187     }
188 }