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, 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.ui.apps.cacheadmin;
029
030import com.alkacon.simapi.Simapi;
031
032import org.opencms.loader.CmsImageLoader;
033import org.opencms.loader.I_CmsImageCache;
034import org.opencms.loader.imagecache.CmsImageCacheEntry;
035import org.opencms.loader.imagecache.CmsImageCacheMaintenanceService;
036import org.opencms.ui.A_CmsUI;
037import org.opencms.util.CmsDateUtil;
038import org.opencms.util.CmsFileUtil;
039
040import java.awt.image.BufferedImage;
041import java.io.ByteArrayOutputStream;
042import java.io.FileInputStream;
043import java.nio.file.Files;
044import java.nio.file.LinkOption;
045import java.nio.file.Paths;
046import java.text.DateFormat;
047import java.time.Instant;
048import java.util.Date;
049
050import org.apache.commons.io.IOUtils;
051
052/**
053 * Bean for Variations im image resources.<p>
054 */
055public class CmsVariationBean {
056
057    /**Variation path.*/
058    private String m_variationPath;
059
060    /** The external image cache. */
061    private I_CmsImageCache m_imageCache;
062
063    /** The variation length. */
064    private long m_length = -1;
065
066    /** The maintenance service used for lazy metadata access. */
067    private CmsImageCacheMaintenanceService m_maintenance;
068
069    /** Whether timestamp metadata has been loaded. */
070    private boolean m_metadataLoaded;
071
072    /** The variation name. */
073    private String m_name;
074
075    /** The last modification time. */
076    private Instant m_lastModified;
077
078    /**
079     * Creates a variation bean with lazy metadata access.<p>
080     *
081     * @param imageCache the external image cache
082     * @param maintenance the image cache maintenance service
083     * @param name the image cache entry name
084     * @param length the image cache entry length
085     */
086    public CmsVariationBean(
087        I_CmsImageCache imageCache,
088        CmsImageCacheMaintenanceService maintenance,
089        String name,
090        long length) {
091
092        m_imageCache = imageCache;
093        m_maintenance = maintenance;
094        m_name = name.startsWith("/") ? name : "/" + name;
095        m_length = length;
096
097    }
098
099    /**
100     * Creates a variation bean for an external image cache entry.<p>
101     *
102     * @param imageCache the external image cache
103     * @param name the image cache entry name
104     * @param length the image cache entry length
105     */
106    public CmsVariationBean(I_CmsImageCache imageCache, String name, long length) {
107
108        this(imageCache, null, name, length);
109    }
110
111    /**
112     * public constructor.<p>
113     *
114     * @param variation path to variation file to hold information for
115     */
116    public CmsVariationBean(String variation) {
117
118        m_variationPath = variation;
119    }
120
121    /** Returns the formatted derivative last-modified time, if available. */
122    public String getDateLastModified() {
123
124        loadMetadata();
125        return formatDate(m_lastModified);
126    }
127
128    /**
129     * Gets the dimensions of the current variation.<p>
130     *
131     * @return String representation of the dimensions
132     */
133    public String getDimensions() {
134
135        try {
136            BufferedImage img = Simapi.read(readContent());
137            return "" + img.getWidth() + " x " + img.getHeight() + "px";
138        } catch (Exception e) {
139            return "";
140        }
141    }
142
143    /**
144     * Get length of variation.<p>
145     *
146     * @return string representation of length
147     */
148    public String getLength() {
149
150        if (m_length >= 0) {
151            return CmsFileUtil.formatFilesize(m_length, A_CmsUI.get().getLocale());
152        }
153        return CmsFileUtil.formatFilesize(new java.io.File(m_variationPath).length(), A_CmsUI.get().getLocale());
154    }
155
156    /**
157     * Gets path of variation.<p>
158     *
159     * @return path
160     */
161    public String getName() {
162
163        if (m_name != null) {
164            return m_name;
165        }
166        String repositoryPath = CmsImageLoader.getImageRepositoryPath();
167        if ((repositoryPath == null) || !m_variationPath.startsWith(repositoryPath)) {
168            return "";
169        }
170        return m_variationPath.substring(repositoryPath.length());
171    }
172
173    /** Formats a timestamp for the current UI locale. */
174    private String formatDate(Instant timestamp) {
175
176        if (timestamp == null) {
177            return "";
178        }
179        return CmsDateUtil.getDateTime(Date.from(timestamp), DateFormat.SHORT, A_CmsUI.get().getLocale());
180    }
181
182    /** Loads timestamp metadata when the variations dialog requests it. */
183    private synchronized void loadMetadata() {
184
185        if (m_metadataLoaded) {
186            return;
187        }
188        m_metadataLoaded = true;
189        try {
190            if (m_maintenance != null) {
191                CmsImageCacheEntry entry = m_maintenance.getEntry(m_name);
192                if (entry != null) {
193                    m_lastModified = entry.getLastModified();
194                }
195            } else if (m_variationPath != null) {
196                m_lastModified = Files.getLastModifiedTime(
197                    Paths.get(m_variationPath),
198                    LinkOption.NOFOLLOW_LINKS).toInstant();
199            }
200        } catch (Exception e) {
201            // The cache entry may have disappeared between listing and opening the dialog.
202        }
203    }
204
205    /**
206     * Reads the variation content.<p>
207     *
208     * @return the variation content
209     * @throws Exception if reading fails
210     */
211    private byte[] readContent() throws Exception {
212
213        if (m_imageCache != null) {
214            ByteArrayOutputStream out = new ByteArrayOutputStream();
215            m_imageCache.writeTo(m_name, out);
216            return out.toByteArray();
217        }
218        try (FileInputStream in = new FileInputStream(m_variationPath)) {
219            return IOUtils.toByteArray(in);
220        }
221    }
222}