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.service;
17
18 import java.util.List;
19
20 import org.codelibs.core.beans.util.BeanUtil;
21 import org.codelibs.core.lang.StringUtil;
22 import org.codelibs.fess.Constants;
23 import org.codelibs.fess.app.pager.DataConfigPager;
24 import org.codelibs.fess.mylasta.direction.FessConfig;
25 import org.codelibs.fess.opensearch.config.cbean.DataConfigCB;
26 import org.codelibs.fess.opensearch.config.exbhv.DataConfigBhv;
27 import org.codelibs.fess.opensearch.config.exentity.DataConfig;
28 import org.codelibs.fess.util.ParameterUtil;
29 import org.dbflute.cbean.result.ListResultBean;
30 import org.dbflute.cbean.result.PagingResultBean;
31 import org.dbflute.optional.OptionalEntity;
32
33 import jakarta.annotation.Resource;
34
35 /**
36 * Service class for managing data configuration CRUD operations.
37 * This service provides functionality to create, read, update, and delete
38 * data configurations used by the Fess crawler system.
39 *
40 * <p>Data configurations define how the crawler should access and process
41 * various data sources such as databases, CSV files, or other structured data.</p>
42 */
43 public class DataConfigService extends FessAppService {
44
45 /**
46 * DBFlute behavior for data configuration operations.
47 * Provides database access methods for DataConfig entities.
48 */
49 @Resource
50 protected DataConfigBhv dataConfigBhv;
51
52 /**
53 * Fess configuration containing application settings.
54 * Used to retrieve paging and other configuration parameters.
55 */
56 @Resource
57 protected FessConfig fessConfig;
58
59 /**
60 * Creates a new instance of DataConfigService.
61 * This constructor initializes the service for managing data configuration operations
62 * including CRUD operations and search functionality.
63 */
64 public DataConfigService() {
65 super();
66 }
67
68 /**
69 * Retrieves a paginated list of data configurations based on search criteria.
70 *
71 * <p>This method performs a paginated search through all data configurations,
72 * applying any search filters specified in the pager. The results are sorted
73 * by sort order and name.</p>
74 *
75 * @param dataConfigPager the pager containing search criteria and pagination settings
76 * @return a list of DataConfig entities matching the search criteria
77 * @throws IllegalArgumentException if dataConfigPager is null
78 */
79 public List<DataConfig> getDataConfigList(final DataConfigPager dataConfigPager) {
80
81 final PagingResultBean<DataConfig> dataConfigList = dataConfigBhv.selectPage(cb -> {
82 cb.paging(dataConfigPager.getPageSize(), dataConfigPager.getCurrentPageNumber());
83
84 setupListCondition(cb, dataConfigPager);
85 });
86
87 // update pager
88 BeanUtil.copyBeanToBean(dataConfigList, dataConfigPager, option -> option.include(Constants.PAGER_CONVERSION_RULE));
89 dataConfigPager.setPageNumberList(dataConfigList.pageRange(op -> {
90 op.rangeSize(fessConfig.getPagingPageRangeSizeAsInteger());
91 }).createPageNumberList());
92
93 return dataConfigList;
94 }
95
96 /**
97 * Deletes the specified data configuration from the system.
98 *
99 * <p>This operation permanently removes the data configuration and
100 * immediately refreshes the index to ensure the change is visible.</p>
101 *
102 * @param dataConfig the data configuration to delete
103 * @throws IllegalArgumentException if dataConfig is null
104 * @throws org.dbflute.exception.EntityAlreadyDeletedException if the entity has already been deleted
105 */
106 public void delete(final DataConfig dataConfig) {
107 dataConfigBhv.delete(dataConfig, op -> {
108 op.setRefreshPolicy(Constants.TRUE);
109 });
110 }
111
112 /**
113 * Retrieves a data configuration by its unique identifier.
114 *
115 * @param id the unique identifier of the data configuration
116 * @return an OptionalEntity containing the DataConfig if found, empty otherwise
117 * @throws IllegalArgumentException if id is null or empty
118 */
119 public OptionalEntity<DataConfig> getDataConfig(final String id) {
120 return dataConfigBhv.selectByPK(id);
121 }
122
123 /**
124 * Retrieves a data configuration by its name.
125 *
126 * <p>If multiple configurations exist with the same name, returns the first one
127 * ordered by sort order ascending.</p>
128 *
129 * @param name the name of the data configuration to retrieve
130 * @return an OptionalEntity containing the DataConfig if found, empty otherwise
131 * @throws IllegalArgumentException if name is null or empty
132 */
133 public OptionalEntity<DataConfig> getDataConfigByName(final String name) {
134 final ListResultBean<DataConfig> list = dataConfigBhv.selectList(cb -> {
135 cb.query().setName_Equal(name);
136 cb.query().addOrderBy_SortOrder_Asc();
137 });
138 if (list.isEmpty()) {
139 return OptionalEntity.empty();
140 }
141 return OptionalEntity.of(list.get(0));
142 }
143
144 /**
145 * Stores (inserts or updates) a data configuration.
146 *
147 * <p>This method encrypts sensitive handler parameters before storing
148 * and immediately refreshes the index to ensure the change is visible.
149 * If the configuration already exists (based on ID), it will be updated;
150 * otherwise, a new configuration will be created.</p>
151 *
152 * @param dataConfig the data configuration to store
153 * @throws IllegalArgumentException if dataConfig is null
154 */
155 public void store(final DataConfig dataConfig) {
156 dataConfig.setHandlerParameter(ParameterUtil.encrypt(dataConfig.getHandlerParameter()));
157 dataConfigBhv.insertOrUpdate(dataConfig, op -> {
158 op.setRefreshPolicy(Constants.TRUE);
159 });
160
161 }
162
163 /**
164 * Sets up the search conditions for listing data configurations.
165 *
166 * <p>This method configures the condition bean with search criteria from the pager,
167 * including name wildcards, handler name wildcards, and description matching.
168 * Results are ordered by sort order and name in ascending order.</p>
169 *
170 * <p>Description matching supports:</p>
171 * <ul>
172 * <li>Wildcard matching (if starts or ends with *)</li>
173 * <li>Prefix matching (if ends with *)</li>
174 * <li>Exact phrase matching (otherwise)</li>
175 * </ul>
176 *
177 * @param cb the condition bean to configure
178 * @param dataConfigPager the pager containing search criteria
179 */
180 protected void setupListCondition(final DataConfigCB cb, final DataConfigPager dataConfigPager) {
181 if (StringUtil.isNotBlank(dataConfigPager.name)) {
182 cb.query().setName_Wildcard(dataConfigPager.name);
183 }
184 if (StringUtil.isNotBlank(dataConfigPager.handlerName)) {
185 cb.query().setHandlerName_Wildcard(wrapQuery(dataConfigPager.handlerName));
186 }
187 if (StringUtil.isNotBlank(dataConfigPager.description)) {
188 if (dataConfigPager.description.startsWith("*")) {
189 cb.query().setDescription_Wildcard(dataConfigPager.description);
190 } else if (dataConfigPager.description.endsWith("*")) {
191 cb.query().setDescription_Prefix(dataConfigPager.description.replaceAll("\\*$", StringUtil.EMPTY));
192 } else {
193 cb.query().setDescription_MatchPhrase(dataConfigPager.description);
194 }
195 }
196 // TODO Long, Integer, String supported only.
197
198 // setup condition
199 cb.query().addOrderBy_SortOrder_Asc();
200 cb.query().addOrderBy_Name_Asc();
201
202 // search
203
204 }
205
206 }