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