001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.jboot.service;
017
018import com.jfinal.kit.LogKit;
019import com.jfinal.plugin.activerecord.*;
020import io.jboot.db.model.Columns;
021import io.jboot.db.model.JbootModel;
022import io.jboot.utils.ClassUtil;
023import io.jboot.utils.ObjectFunc;
024import io.jboot.utils.ObjectUtil;
025
026import java.lang.reflect.ParameterizedType;
027import java.lang.reflect.Type;
028import java.util.ArrayList;
029import java.util.Collection;
030import java.util.List;
031
032/**
033 * JbootServiceBase 类
034 * Jboot 1.x 的 Service 需要 Join 功能的话,需要实现 JbootServiceJoiner 接口
035 */
036public class JbootServiceBase<M extends JbootModel<M>>
037        extends JbootServiceJoinerImpl
038        implements JbootServiceJoiner {
039
040    protected static final int ACTION_ADD = 1;
041    protected static final int ACTION_DEL = 2;
042    protected static final int ACTION_UPDATE = 3;
043
044    protected JbootModel<M> DAO = null;
045
046    public JbootServiceBase() {
047        DAO = initDao();
048    }
049
050    /**
051     * 初始化 DAO
052     * 子类可以复写 自定义自己的DAO
053     *
054     * @return
055     */
056    protected M initDao() {
057        Class<?> usefulClass = ClassUtil.getUsefulClass(getClass());
058        return createDao(usefulClass);
059    }
060
061
062    private M createDao(Class<?> usefulClass) {
063        Type type = usefulClass.getGenericSuperclass();
064        if (type instanceof ParameterizedType) {
065            Class<M> modelClass = (Class<M>) ((ParameterizedType) type).getActualTypeArguments()[0];
066            return ClassUtil.newInstance(modelClass, false).dao();
067        }
068        //from child class
069        else if (type instanceof Class) {
070            Class<?> typeClass = (Class<?>) type;
071            if (typeClass != JbootServiceBase.class
072                    && typeClass != Object.class
073            ) {
074                return createDao(typeClass);
075            }
076        }
077
078        LogKit.warn("Not define Model class in service: " +usefulClass);
079        return null;
080    }
081
082
083    public JbootModel getDao() {
084        return DAO;
085    }
086
087
088    /**
089     * 根据ID查找model
090     *
091     * @param id
092     * @return
093     */
094    public M findById(Object id) {
095        return DAO.findById(id);
096    }
097
098
099    /**
100     * 根据 Columns 查找单条数据
101     *
102     * @param columns
103     * @return
104     */
105    public M findFirstByColumns(Columns columns) {
106        return findFirstByColumns(columns, null);
107    }
108
109
110    /**
111     * 根据 Columns 查找单条数据
112     *
113     * @param columns
114     * @param orderBy
115     * @return
116     */
117    public M findFirstByColumns(Columns columns, String orderBy) {
118        return DAO.findFirstByColumns(columns, orderBy);
119    }
120
121
122    /**
123     * 查找全部数据
124     *
125     * @return
126     */
127    public List<M> findAll() {
128        return DAO.findAll();
129    }
130
131
132    /**
133     * 根据 Columns 查找数据
134     *
135     * @param columns
136     * @return
137     */
138    public List<M> findListByColumns(Columns columns) {
139        return DAO.findListByColumns(columns);
140    }
141
142
143    /**
144     * 根据 Columns 查找数据
145     *
146     * @param columns
147     * @param orderBy
148     * @return
149     */
150    public List<M> findListByColumns(Columns columns, String orderBy) {
151        return DAO.findListByColumns(columns, orderBy);
152    }
153
154    /**
155     * 根据 Columns 查找数据
156     *
157     * @param columns
158     * @param count
159     * @return
160     */
161    public List<M> findListByColumns(Columns columns, Integer count) {
162        return DAO.findListByColumns(columns, count);
163    }
164
165    /**
166     * 根据 Columns 查找数据
167     *
168     * @param columns
169     * @param orderBy
170     * @param count
171     * @return
172     */
173    public List<M> findListByColumns(Columns columns, String orderBy, Integer count) {
174        return DAO.findListByColumns(columns, orderBy, count);
175    }
176
177
178    /**
179     * 根据多个 id 查找多个对象
180     *
181     * @param ids
182     * @return
183     */
184    public List<M> findListByIds(Object... ids) {
185        return DAO.findListByIds(ids);
186    }
187
188
189    /**
190     * 根据提交查询数据量
191     *
192     * @param columns
193     * @return
194     */
195    public long findCountByColumns(Columns columns) {
196        return DAO.findCountByColumns(columns);
197    }
198
199
200    /**
201     * 根据ID 删除model
202     *
203     * @param id
204     * @return
205     */
206    public boolean deleteById(Object id) {
207        boolean result = DAO.deleteById(id);
208        if (result) {
209            shouldUpdateCache(ACTION_DEL, null, id);
210        }
211        return result;
212    }
213
214
215    /**
216     * 删除
217     *
218     * @param model
219     * @return
220     */
221    public boolean delete(M model) {
222        boolean result = model.delete();
223        if (result) {
224            shouldUpdateCache(ACTION_DEL, model, model._getIdValue());
225        }
226        return result;
227    }
228
229
230    /**
231     * 根据 多个 id 批量删除
232     *
233     * @param ids
234     * @return
235     */
236    public boolean batchDeleteByIds(Object... ids) {
237        boolean result = DAO.batchDeleteByIds(ids);
238        if (result) {
239            for (Object id : ids) {
240                shouldUpdateCache(ACTION_DEL, null, id);
241            }
242        }
243        return result;
244    }
245
246
247    /**
248     * 保存到数据库
249     *
250     * @param model
251     * @return id if success
252     */
253    public Object save(M model) {
254        boolean result = model.save();
255        if (result) {
256            shouldUpdateCache(ACTION_ADD, model, model._getIdValue());
257            return model._getIdValue();
258        }
259        return null;
260    }
261
262
263    /**
264     * 保存或更新
265     *
266     * @param model
267     * @return id if success
268     */
269    public Object saveOrUpdate(M model) {
270        if (model._getIdValue() == null) {
271            return save(model);
272        } else if (update(model)) {
273            return model._getIdValue();
274        }
275        return null;
276    }
277
278    /**
279     * 更新
280     *
281     * @param model
282     * @return
283     */
284    public boolean update(M model) {
285        boolean result = model.update();
286        if (result) {
287            shouldUpdateCache(ACTION_UPDATE, model, model._getIdValue());
288        }
289        return result;
290    }
291
292
293    /**
294     * 分页
295     *
296     * @param page
297     * @param pageSize
298     * @return
299     */
300    public Page<M> paginate(int page, int pageSize) {
301        return DAO.paginate(page, pageSize);
302    }
303
304
305    /**
306     * 分页
307     *
308     * @param page
309     * @param pageSize
310     * @return
311     */
312    public Page<M> paginateByColumns(int page, int pageSize, Columns columns) {
313        return DAO.paginateByColumns(page, pageSize, columns);
314    }
315
316
317    /**
318     * 分页
319     *
320     * @param page
321     * @param pageSize
322     * @param columns
323     * @param orderBy
324     * @return
325     */
326    public Page<M> paginateByColumns(int page, int pageSize, Columns columns, String orderBy) {
327        return DAO.paginateByColumns(page, pageSize, columns, orderBy);
328    }
329
330
331    /**
332     * 同步 model 数据到数据库
333     *
334     * @param columns
335     * @param syncModels
336     * @param compareAttrGetters
337     */
338    public void syncModels(Columns columns, Collection<M> syncModels, ObjectFunc<M>... compareAttrGetters) {
339        if (columns == null) {
340            throw new NullPointerException("columns must not be null");
341        }
342
343        if (syncModels == null || syncModels.isEmpty()) {
344            DAO.deleteByColumns(columns);
345            return;
346        }
347
348        List<M> existModels = findListByColumns(columns);
349        if (existModels == null || existModels.isEmpty()) {
350            Db.batchSave(new ArrayList<>(syncModels), syncModels.size());
351            return;
352        }
353
354
355        for (M existModel : existModels) {
356            if (!ObjectUtil.isContainsObject(syncModels, existModel, compareAttrGetters)) {
357                existModel.delete();
358            }
359        }
360
361
362        for (M syncModel : syncModels) {
363            M existModel = ObjectUtil.getContainsObject(existModels, syncModel, compareAttrGetters);
364            if (existModel == null) {
365                syncModel.save();
366            } else {
367                existModel._setAttrs(syncModel).update();
368            }
369        }
370    }
371
372
373    /**
374     * 复写 JbootServiceJoinerImpl 的方法
375     *
376     * @param columnValue
377     * @return
378     */
379    @Override
380    protected JbootModel joinByValue(Object columnValue, JbootModel sourceModel) {
381        return findById(columnValue);
382    }
383
384
385    /**
386     * 用于给子类复写,用于刷新缓存
387     *
388     * @param action
389     * @param model
390     * @param id
391     */
392    public void shouldUpdateCache(int action, Model model, Object id) {
393    }
394
395
396    @Override
397    protected <M extends JbootModel> List<M> joinManyByValue(String columnName, Object value, M sourceModel) {
398        return (List<M>) findListByColumns(Columns.create(columnName, value));
399    }
400}