001/**
002 * Copyright (c) 2022-2023, Mybatis-Flex (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 com.mybatisflex.core.audit;
017
018import java.util.ArrayList;
019import java.util.Collections;
020import java.util.List;
021import java.util.concurrent.Executors;
022import java.util.concurrent.ScheduledExecutorService;
023import java.util.concurrent.TimeUnit;
024import java.util.concurrent.locks.ReentrantReadWriteLock;
025
026/**
027 * 默认的审计消息收集器,其收集消息后,定时通过消息发送器{@link MessageReporter}把消息发送过去
028 */
029public class ScheduledMessageCollector implements MessageCollector, Runnable {
030
031    private long period;
032    private ScheduledExecutorService scheduler;
033    private MessageReporter messageSender;
034
035    private List<AuditMessage> messages = Collections.synchronizedList(new ArrayList<>());
036    private ReentrantReadWriteLock rrwLock = new ReentrantReadWriteLock();
037
038    public ScheduledMessageCollector() {
039        this(10, new ConsoleMessageReporter());
040    }
041
042
043    public ScheduledMessageCollector(long period, MessageReporter messageSender) {
044        this.period = period;
045        this.messageSender = messageSender;
046        this.scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> {
047            Thread thread = new Thread(runnable, "ScheduledMessageCollector");
048            thread.setDaemon(true);
049            return thread;
050        });
051        this.scheduler.scheduleAtFixedRate(this, period, period, TimeUnit.SECONDS);
052    }
053
054
055    @Override
056    public void collect(AuditMessage message) {
057        try {
058            rrwLock.readLock().lock();
059            messages.add(message);
060        } finally {
061            rrwLock.readLock().unlock();
062        }
063    }
064
065
066    @Override
067    public void run() {
068        if (messages.isEmpty()) {
069            return;
070        }
071        List<AuditMessage> sendMessages;
072        try {
073            rrwLock.writeLock().lock();
074            sendMessages = new ArrayList<>(messages);
075            messages.clear();
076        } finally {
077            rrwLock.writeLock().unlock();
078        }
079        messageSender.sendMessages(sendMessages);
080    }
081
082    public void release() {
083        run(); //clear the messages
084        scheduler.shutdown();
085    }
086}