001/**
002 * Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * 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, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016package org.javamoney.moneta.loader.internal;
017
018import java.io.*;
019import java.util.Map;
020import java.util.Objects;
021import java.util.concurrent.ConcurrentHashMap;
022import java.util.logging.Level;
023import java.util.logging.Logger;
024
025/**
026 * Default implementation of {@link ResourceCache}, using the local file system.
027 *
028 * @author Anatole Tresch
029 */
030public class DefaultResourceCache implements ResourceCache {
031    /**
032     * The logger used.
033     */
034    private static final Logger LOG = Logger.getLogger(DefaultResourceCache.class.getName());
035    /**
036     * Suffix for files created.
037     */
038    private static final String SUFFIX = ".dat";
039    /**
040     * Local temp directory.
041     */
042    private File localDir = new File(System.getProperty("temp.dir", ".resourceCache"));
043    /**
044     * Cached resources.
045     */
046    private Map<String, File> cachedResources = new ConcurrentHashMap<>();
047
048    /**
049     * Constructor.
050     */
051    public DefaultResourceCache() {
052        if (!localDir.exists()) {
053            if (!localDir.mkdirs()) {
054                LOG.severe("Error creating cache dir  " + localDir + ", resource cache disabled!");
055                localDir = null;
056            } else {
057                LOG.finest("Created cache dir  " + localDir);
058            }
059        } else if (!localDir.isDirectory()) {
060            LOG.severe("Error initializing cache dir  " + localDir + ", not a directory, resource cache disabled!");
061            localDir = null;
062        } else if (!localDir.canWrite()) {
063            LOG.severe("Error initializing cache dir  " + localDir + ", not writable, resource cache disabled!");
064            localDir = null;
065        }
066        if (Objects.nonNull(localDir)) {
067            File[] files = localDir.listFiles();
068            if (files != null) {
069                for (File file : files) {
070                    if (file.isFile()) {
071                        String resourceId = file.getName().substring(0, file.getName().length() - 4);
072                        cachedResources.put(resourceId, file);
073                    }
074                }
075            }
076        }
077    }
078
079    /*
080     * (non-Javadoc)
081     *
082     * @see
083     * org.javamoney.moneta.loader.internal.ResourceCache#write(java.lang.String
084     * , byte[])
085     */
086    @Override
087    public void write(String resourceId, byte[] data) {
088        try {
089            File f = this.cachedResources.get(resourceId);
090            if (Objects.isNull(f)) {
091                f = new File(localDir, resourceId + SUFFIX);
092                writeFile(f, data);
093                this.cachedResources.put(resourceId, f);
094            } else {
095                writeFile(f, data);
096            }
097        } catch (Exception e) {
098            LOG.log(Level.WARNING, "Caching of resource failed: " + resourceId, e);
099        }
100    }
101
102    /**
103     * Writees a file with the given data,
104     *
105     * @param f    the file
106     * @param data the data
107     * @throws IOException if writing failed.
108     */
109    private void writeFile(File f, byte[] data) throws IOException {
110        BufferedOutputStream bos = null;
111        try {
112            bos = new BufferedOutputStream(new FileOutputStream(f));
113            bos.write(data);
114            bos.flush();
115        } finally {
116            try {
117                if (Objects.nonNull(bos)) {
118                    bos.close();
119                }
120            } catch (Exception e2) {
121                LOG.log(Level.SEVERE, "Error closing output stream for " + f, e2);
122            }
123        }
124
125    }
126
127    /*
128     * (non-Javadoc)
129     *
130     * @see
131     * org.javamoney.moneta.loader.internal.ResourceCache#isCached(java.lang
132     * .String)
133     */
134    @Override
135    public boolean isCached(String resourceId) {
136        return this.cachedResources.containsKey(resourceId);
137    }
138
139    /*
140     * (non-Javadoc)
141     *
142     * @see
143     * org.javamoney.moneta.loader.internal.ResourceCache#read(java.lang.String)
144     */
145    @Override
146    public byte[] read(String resourceId) {
147        File f = this.cachedResources.get(resourceId);
148        if (Objects.isNull(f)) {
149            return null;
150        }
151        return readFile(f);
152    }
153
154    @Override
155    public void clear(String resourceId) {
156        File f = this.cachedResources.get(resourceId);
157        if (f != null) {
158            if (f.exists()) {
159                if (!f.delete()) {
160                    LOG.warning("Failed to delete caching file: " + f.getAbsolutePath());
161                }
162            }
163            this.cachedResources.remove(resourceId);
164        }
165    }
166
167    /**
168     * Read a file.
169     *
170     * @param f the file
171     * @return the bytes read.
172     */
173    private byte[] readFile(File f) {
174        ByteArrayOutputStream bos = new ByteArrayOutputStream();
175        BufferedInputStream is = null;
176        try {
177            is = new BufferedInputStream(new FileInputStream(f));
178            byte[] input = new byte[1024];
179            int read = 1;
180            while (read > 0) {
181                read = is.read(input);
182                if (read > 0) {
183                    bos.write(input, 0, read);
184                }
185            }
186            return bos.toByteArray();
187        } catch (Exception e) {
188            LOG.log(Level.SEVERE, "Error reading cached resource from " + f, e);
189            return null;
190        } finally {
191            try {
192                if (Objects.nonNull(is)) {
193                    is.close();
194                }
195            } catch (Exception e2) {
196                LOG.log(Level.SEVERE, "Error closing input stream from " + f, e2);
197            }
198        }
199/*
200URI fileUri = this.cachedResource;
201        if(fileUri == null){
202            String userHome = System.getProperty("user.home");
203            File file = new File(userHome + "/.cache", resourceId);
204            if(file.exists()){
205                fileUri = file.toURI();
206            }
207        }
208        if(fileUri != null){
209            File file = new File(fileUri);
210            try(
211                    FileInputStream fis = new FileInputStream(file);
212                    BufferedInputStream bis = new BufferedInputStream(fis);
213                    ObjectInputStream ois = new ObjectInputStream(bis)
214            ){
215                long loadTS = ois.readLong();
216                byte[] data = (byte[]) ois.readObject();
217                this.lastLoaded = loadTS;
218                setData(data);
219                return true;
220            }
221            catch(Exception e){
222                LOG.log(Level.WARNING, "Failed to read data from cache: " + fileUri, e);
223            }
224        }
225        return false;
226 */
227    }
228
229    @Override
230    public String toString() {
231        return "DefaultResourceCache [localDir=" + localDir + ", cachedResources=" + cachedResources + ']';
232    }
233
234}