123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* $Id$ */
-
- package org.apache.fop.fonts;
-
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
- import java.io.OutputStream;
- import java.io.Serializable;
- import java.util.Map;
-
- import org.apache.commons.io.IOUtils;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.apache.fop.apps.FOPException;
- import org.apache.fop.util.LogUtil;
-
- /**
- * Fop cache (currently only used for font info caching)
- */
- public final class FontCache implements Serializable {
-
- /** Serialization Version UID */
- private static final long serialVersionUID = 605232520271754717L;
-
- /** logging instance */
- private static Log log = LogFactory.getLog(FontCache.class);
-
- /** FOP's user directory name */
- private static final String FOP_USER_DIR = ".fop";
-
- /** font cache file path */
- private static final String DEFAULT_CACHE_FILENAME = "fop-fonts.cache";
-
- /** has this cache been changed since it was last read? */
- private transient boolean changed = false;
-
- /** change lock */
- private transient Object changeLock = new Object();
-
- /** master mapping of font url -> font info */
- private Map fontMap = new java.util.HashMap();
-
- /** mapping of font url -> file modified date */
- private Map failedFontMap = new java.util.HashMap();
-
- /**
- * Default constructor
- */
- public FontCache() {
- //nop
- }
-
- private void readObject(java.io.ObjectInputStream in)
- throws IOException, ClassNotFoundException {
- in.defaultReadObject();
- this.changeLock = new Object(); //Initialize transient field
- }
-
- private static File getUserHome() {
- String s = System.getProperty("user.home");
- if (s != null) {
- File userDir = new File(s);
- if (userDir.exists()) {
- return userDir;
- }
- }
- return null;
- }
-
- /**
- * Returns the default font cache file.
- * @param forWriting true if the user directory should be created
- * @return the default font cache file
- */
- public static File getDefaultCacheFile(boolean forWriting) {
- File userHome = getUserHome();
- if (userHome != null) {
- File fopUserDir = new File(userHome, FOP_USER_DIR);
- if (forWriting) {
- fopUserDir.mkdir();
- }
- return new File(fopUserDir, DEFAULT_CACHE_FILENAME);
- }
- return new File(FOP_USER_DIR);
- }
-
- /**
- * Reads the default font cache file and returns its contents.
- * @return the font cache deserialized from the file (or null if no cache file exists or if
- * it could not be read)
- */
- public static FontCache load() {
- return loadFrom(getDefaultCacheFile(false));
- }
-
- /**
- * Reads a font cache file and returns its contents.
- * @param cacheFile the cache file
- * @return the font cache deserialized from the file (or null if no cache file exists or if
- * it could not be read)
- */
- public static FontCache loadFrom(File cacheFile) {
- if (cacheFile.exists()) {
- try {
- if (log.isTraceEnabled()) {
- log.trace("Loading font cache from " + cacheFile.getCanonicalPath());
- }
- InputStream in = new java.io.FileInputStream(cacheFile);
- in = new java.io.BufferedInputStream(in);
- ObjectInputStream oin = new ObjectInputStream(in);
- try {
- return (FontCache)oin.readObject();
- } finally {
- IOUtils.closeQuietly(oin);
- }
- } catch (ClassNotFoundException e) {
- //We don't really care about the exception since it's just a cache file
- log.warn("Could not read font cache. Discarding font cache file. Reason: "
- + e.getMessage());
- } catch (IOException ioe) {
- //We don't really care about the exception since it's just a cache file
- log.warn("I/O exception while reading font cache (" + ioe.getMessage()
- + "). Discarding font cache file.");
- }
- }
- return null;
- }
-
- /**
- * Writes the font cache to disk.
- * @throws FOPException fop exception
- */
- public void save() throws FOPException {
- saveTo(getDefaultCacheFile(true));
- }
-
- /**
- * Writes the font cache to disk.
- * @param cacheFile the file to write to
- * @throws FOPException fop exception
- */
- public void saveTo(File cacheFile) throws FOPException {
- synchronized (changeLock) {
- if (changed) {
- try {
- if (log.isTraceEnabled()) {
- log.trace("Writing font cache to " + cacheFile.getCanonicalPath());
- }
- OutputStream out = new java.io.FileOutputStream(cacheFile);
- out = new java.io.BufferedOutputStream(out);
- ObjectOutputStream oout = new ObjectOutputStream(out);
- try {
- oout.writeObject(this);
- } finally {
- IOUtils.closeQuietly(oout);
- }
- } catch (IOException ioe) {
- LogUtil.handleException(log, ioe, true);
- }
- changed = false;
- log.trace("Cache file written.");
- }
- }
- }
-
- /**
- * creates a key given a font info for the font mapping
- * @param fontInfo font info
- * @return font cache key
- */
- protected static String getCacheKey(EmbedFontInfo fontInfo) {
- if (fontInfo != null) {
- String embedFile = fontInfo.getEmbedFile();
- String metricsFile = fontInfo.getMetricsFile();
- return (embedFile != null) ? embedFile : metricsFile;
- }
- return null;
- }
-
- /**
- * cache has been updated since it was read
- * @return if this cache has changed
- */
- public boolean hasChanged() {
- return this.changed;
- }
-
- /**
- * is this font in the cache?
- * @param embedUrl font info
- * @return boolean
- */
- public boolean containsFont(String embedUrl) {
- if (embedUrl != null) {
- return fontMap.containsKey(embedUrl);
- }
- return false;
- }
-
- /**
- * is this font info in the cache?
- * @param fontInfo font info
- * @return font
- */
- public boolean containsFont(EmbedFontInfo fontInfo) {
- if (fontInfo != null) {
- return fontMap.containsKey(getCacheKey(fontInfo));
- }
- return false;
- }
-
- /**
- * adds a font info to cache
- * @param fontInfo font info
- */
- public void addFont(EmbedFontInfo fontInfo) {
- String cacheKey = getCacheKey(fontInfo);
- synchronized (changeLock) {
- if (!containsFont(cacheKey)) {
- if (log.isTraceEnabled()) {
- log.trace("Font added to cache: " + cacheKey);
- }
- if (fontInfo instanceof CachedFontInfo) {
- fontMap.put(cacheKey, fontInfo);
- } else {
- fontMap.put(cacheKey, new CachedFontInfo(fontInfo));
- }
- changed = true;
- }
- }
- }
-
- /**
- * returns a font from the cache
- * @param embedUrl font info
- * @return boolean
- */
- public CachedFontInfo getFont(String embedUrl) {
- if (containsFont(embedUrl)) {
- return (CachedFontInfo)fontMap.get(embedUrl);
- }
- return null;
- }
-
- /**
- * removes font from cache
- * @param embedUrl embed url
- */
- public void removeFont(String embedUrl) {
- synchronized (changeLock) {
- if (containsFont(embedUrl)) {
- if (log.isTraceEnabled()) {
- log.trace("Font removed from cache: " + embedUrl);
- }
- fontMap.remove(embedUrl);
- changed = true;
- }
- }
- }
-
- /**
- * has this font previously failed to load?
- * @param embedUrl embed url
- * @param lastModified last modified
- * @return whether this is a failed font
- */
- public boolean isFailedFont(String embedUrl, long lastModified) {
- if (failedFontMap.containsKey(embedUrl)) {
- synchronized (changeLock) {
- long failedLastModified = ((Long)failedFontMap.get(embedUrl)).longValue();
- if (lastModified != failedLastModified) {
- // this font has been changed so lets remove it
- // from failed font map for now
- failedFontMap.remove(embedUrl);
- changed = true;
- }
- }
- return true;
- }
- return false;
- }
-
- /**
- * registers a failed font with the cache
- * @param embedUrl embed url
- * @param lastModified time last modified
- */
- public void registerFailedFont(String embedUrl, long lastModified) {
- synchronized (changeLock) {
- if (!failedFontMap.containsKey(embedUrl)) {
- failedFontMap.put(embedUrl, new Long(lastModified));
- changed = true;
- }
- }
- }
-
- /**
- * Clears font cache
- */
- public void clear() {
- synchronized (changeLock) {
- if (log.isTraceEnabled()) {
- log.trace("Font cache cleared.");
- }
- fontMap.clear();
- failedFontMap.clear();
- changed = true;
- }
- }
- }
|