001/*
002 *  Copyright 2016 Anyware Services
003 *
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 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
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 */
016
017package org.ametys.plugins.site.cache.monitoring.process.access;
018
019import java.util.List;
020
021import org.apache.ibatis.session.SqlSession;
022
023import org.ametys.core.datasource.AbstractMyBatisDAO;
024import org.ametys.core.util.DateUtils;
025import org.ametys.runtime.config.Config;
026
027import com.google.common.collect.LinkedListMultimap;
028import com.google.common.collect.ListMultimap;
029
030/**
031 * The RessourceAccessMonitor collects the resources that have been requested,
032 * and export them into a database.
033 */
034public class ResourceAccessComponent extends AbstractMyBatisDAO
035{
036    /** Avalon ROLE. */
037    public static final String ROLE = ResourceAccessComponent.class.getName();
038
039    /** List of pending {@link ResourceAccess} waiting to be exported to the database. */
040    protected ListMultimap<String, ResourceAccess> _pendingRecords = LinkedListMultimap.create();
041
042    /**
043     * Add a new {@link ResourceAccess} to the monitored resources.
044     * @param ra The resource access object.
045     */
046    public void addAccessRecord(ResourceAccess ra)
047    {
048        boolean enabled = Config.getInstance().getValueAsBoolean("front.cache.monitoring.schedulers.enable");
049        if (!enabled || ra == null)
050        {
051            return;
052        }
053
054        synchronized (this)
055        {
056            _pendingRecords.put(ra.getClass().getName(), ra);
057        }
058    }
059
060    /**
061     * Call this method to transfer pendings resource access from memory to database
062     * This is normally called by a scheduler
063     */
064    public void exportPendings()
065    {
066        long start = 0;
067        int successCount = 0;
068        ListMultimap<String, ResourceAccess> resourcesAccesstoExport;
069
070        if (getLogger().isDebugEnabled())
071        {
072            getLogger().debug("Start to insert pending records.");
073            start = System.currentTimeMillis();
074        }
075
076        // Copy the current pending records by switching references
077        synchronized (this)
078        {
079            resourcesAccesstoExport = _pendingRecords;
080            _pendingRecords = LinkedListMultimap.create();
081        }
082
083        // Export
084        if (!resourcesAccesstoExport.isEmpty())
085        {
086            successCount = _fillDatabase(resourcesAccesstoExport);
087        }
088
089        if (getLogger().isDebugEnabled())
090        {
091            String durationStr = DateUtils.formatDuration(System.currentTimeMillis() - start);
092            getLogger().debug(String.format("%s/%s pending records exported into database in %s", successCount, resourcesAccesstoExport.size(), durationStr));
093        }
094    }
095
096    private int _fillDatabase(ListMultimap<String, ResourceAccess> resourcesAccess)
097    {
098        int success = 0;
099        for (String resourceAccessType : resourcesAccess.keySet())
100        {
101            try (SqlSession sqlSession = getSession())
102            {
103                success += _fillDatabase(sqlSession, resourcesAccess.get(resourceAccessType));
104                
105                // Commit the transaction.
106                sqlSession.commit();
107            }
108        }
109        return success;
110    }
111
112    private int _fillDatabase(SqlSession sqlSession, List<ResourceAccess> resourcesAccess)
113    {
114        try
115        {
116            for (ResourceAccess ra : resourcesAccess)
117            {
118                sqlSession.insert(ra.getInsertStatementId(), ra.getInsertStatementParameters());
119            }
120            
121            return resourcesAccess.size();
122        }
123        catch (Exception e)
124        {
125            getLogger().error("Exception exception while inserting new records to the database", e);
126            return 0;
127        }
128    }
129}