001/*
002 * This library is part of OpenCms -
003 * The Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.loader.imagecache;
029
030import org.opencms.configuration.CmsImageCacheConfiguration;
031import org.opencms.configuration.CmsImageCacheConfiguration.RetentionMode;
032import org.opencms.loader.CmsFsImageCache;
033import org.opencms.loader.CmsImageLoader;
034import org.opencms.loader.CmsRfsImageCache;
035import org.opencms.loader.CmsS3ImageCache;
036import org.opencms.loader.I_CmsImageCache;
037import org.opencms.loader.imagecache.CmsImageCacheCapabilities.Capability;
038import org.opencms.main.OpenCms;
039
040import java.util.Objects;
041
042/**
043 * Capability-aware entry point for image cache maintenance clients.<p>
044 */
045public final class CmsImageCacheMaintenanceService {
046
047    /** The maintenance backend. */
048    private final I_CmsImageCacheMaintenance m_backend;
049
050    /**
051     * Creates a maintenance service.<p>
052     *
053     * @param backend the maintenance backend
054     */
055    public CmsImageCacheMaintenanceService(I_CmsImageCacheMaintenance backend) {
056
057        m_backend = Objects.requireNonNull(backend, "backend");
058    }
059
060    /**
061     * Creates a service for an image cache implementation.<p>
062     *
063     * @param cache the image cache
064     * @return the maintenance service
065     */
066    public static CmsImageCacheMaintenanceService create(I_CmsImageCache cache) {
067
068        Objects.requireNonNull(cache, "cache");
069        if (cache instanceof CmsFsImageCache) {
070            return new CmsImageCacheMaintenanceService(new CmsFsImageCacheMaintenance((CmsFsImageCache)cache));
071        }
072        if (cache instanceof CmsS3ImageCache) {
073            return new CmsImageCacheMaintenanceService(new CmsS3ImageCacheMaintenance((CmsS3ImageCache)cache));
074        }
075        if (cache instanceof CmsRfsImageCache) {
076            return new CmsImageCacheMaintenanceService(new CmsRfsImageCacheMaintenance((CmsRfsImageCache)cache));
077        }
078        throw new IllegalArgumentException("Unsupported image cache implementation: " + cache.getClass().getName());
079    }
080
081    /**
082     * Creates a service using the central image cache maintenance configuration.<p>
083     *
084     * @param cache the image cache
085     * @param configuration the image cache configuration
086     * @return the maintenance service
087     */
088    public static CmsImageCacheMaintenanceService create(
089        I_CmsImageCache cache,
090        CmsImageCacheConfiguration configuration) {
091
092        Objects.requireNonNull(cache, "cache");
093        Objects.requireNonNull(configuration, "configuration");
094        if (cache instanceof CmsFsImageCache) {
095            return new CmsImageCacheMaintenanceService(
096                new CmsFsImageCacheMaintenance(
097                    (CmsFsImageCache)cache,
098                    configuration.getRetentionMode() == RetentionMode.renewOnUse,
099                    configuration.getFsTouchConcurrency()));
100        }
101        if (cache instanceof CmsS3ImageCache) {
102            return new CmsImageCacheMaintenanceService(
103                new CmsS3ImageCacheMaintenance(
104                    (CmsS3ImageCache)cache,
105                    configuration.getS3DeleteBatchSize(),
106                    configuration.getS3DeleteConcurrency(),
107                    configuration.getS3CopyConcurrency(),
108                    configuration.getS3MaxCopiesPerSecond(),
109                    configuration.getS3RenewalQueueCapacity()));
110        }
111        return create(cache);
112    }
113
114    /**
115     * Creates a service for the image cache currently configured in the image loader.<p>
116     *
117     * @return the maintenance service
118     * @throws Exception if the configured cache can not be accessed
119     */
120    public static CmsImageCacheMaintenanceService createForConfiguredCache() throws Exception {
121
122        I_CmsImageCache imageCache = CmsImageLoader.getImageCache();
123        if (imageCache != null) {
124            return create(imageCache, OpenCms.getImageCacheConfiguration());
125        }
126        String repositoryPath = CmsImageLoader.getImageRepositoryPath();
127        if (repositoryPath != null) {
128            return createForRfsRepository(repositoryPath);
129        }
130        throw new IllegalStateException("No image cache repository is configured.");
131    }
132
133    /**
134     * Creates a service for the classic RFS image cache repository.<p>
135     *
136     * @param repositoryPath the repository path
137     * @return the maintenance service
138     * @throws Exception if the repository can not be initialized
139     */
140    public static CmsImageCacheMaintenanceService createForRfsRepository(String repositoryPath) throws Exception {
141
142        return create(new CmsRfsImageCache(repositoryPath));
143    }
144
145    /**
146     * Executes a maintenance request after checking backend capabilities.<p>
147     *
148     * @param request the request
149     * @return the result
150     * @throws Exception if execution fails
151     */
152    public CmsImageCacheMaintenanceResult execute(CmsImageCacheMaintenanceRequest request) throws Exception {
153
154        Capability capability;
155        switch (request.getOperation()) {
156            case CLEAR:
157                capability = Capability.CLEAR;
158                break;
159            case DELETE:
160                capability = Capability.DELETE_ENTRIES;
161                break;
162            case RENEW:
163                capability = Capability.RENEW_ENTRIES;
164                break;
165            default:
166                throw new IllegalArgumentException(
167                    "Unsupported image cache maintenance operation: " + request.getOperation());
168        }
169        requireCapability(capability);
170        return m_backend.execute(request);
171    }
172
173    /** Returns the backend identifier. */
174    public String getBackendId() {
175
176        return m_backend.getBackendId();
177    }
178
179    /** Returns the backend capabilities. */
180    public CmsImageCacheCapabilities getCapabilities() {
181
182        return m_backend.getCapabilities();
183    }
184
185    /**
186     * Loads metadata for one cache entry.<p>
187     *
188     * @param key the image cache key
189     * @return the entry metadata, or {@code null} if the entry does not exist
190     * @throws Exception if the metadata can not be loaded
191     */
192    public CmsImageCacheEntry getEntry(String key) throws Exception {
193
194        requireCapability(Capability.LIST_ENTRIES);
195        return m_backend.getEntry(key);
196    }
197
198    /**
199     * Streams all cache entries.<p>
200     *
201     * @param visitor the visitor
202     * @throws Exception if listing fails
203     */
204    public void visitEntries(I_CmsImageCacheMaintenanceEntryVisitor visitor) throws Exception {
205
206        requireCapability(Capability.LIST_ENTRIES);
207        m_backend.visitEntries(visitor);
208    }
209
210    /** Ensures that a backend capability is available. */
211    private void requireCapability(Capability capability) {
212
213        if (!m_backend.getCapabilities().supports(capability)) {
214            throw new UnsupportedOperationException(
215                "Image cache backend " + m_backend.getBackendId() + " does not support " + capability + ".");
216        }
217    }
218}