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