ResourceFontCache.java 15 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  javax.jcr.Item
 *  javax.jcr.Node
 *  javax.jcr.Property
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.observation.Event
 *  javax.jcr.observation.EventIterator
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ResourceUtil
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.day.image.internal.font.resource;

import com.day.image.font.AbstractFont;
import com.day.image.font.FontListEntry;
import com.day.image.internal.font.AbstractFontCache;
import com.day.image.internal.font.FontFileProvider;
import java.awt.Font;
import java.awt.FontFormatException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.jcr.Item;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/*
 * This class specifies class file version 49.0 but uses Java 6 signatures.  Assumed Java 6.
 */
public class ResourceFontCache
extends AbstractFontCache<Font> {
    private static final String CONTENT_DATA = "/jcr:data/jcr:content";
    private static final String NODE_TYPE_DEFAULT = "nt:unstructured";
    private static final String PROP_FAMILY = "family";
    private static final String PROP_PSNAME = "psName";
    private static final String PROP_FONT_PATH = "fontPath";
    private static final String PROP_FONT_FILE_PATH = "fontFilePath";
    private final Logger log;
    private static final String FONT_MAP_RESOURCE_NAME = ".fontlist";
    private final ResourceResolver systemTicket;
    private FontFileProvider fontFileProvider;
    private final String[] fontPath;
    private Map<String, String> fontMap;

    ResourceFontCache(ResourceResolver systemTicket, String[] fontPath, FontFileProvider ffp) {
        this.log = LoggerFactory.getLogger(this.getClass());
        this.systemTicket = systemTicket;
        this.fontPath = fontPath;
        this.fontFileProvider = ffp;
        this.setupCache();
    }

    @Override
    public void destroy() {
        AbstractFontCache.super.destroy();
    }

    public void handleListChanged() {
        this.setupCache();
    }

    synchronized List<FontListEntry> getFontList() {
        ArrayList<FontListEntry> fontList = new ArrayList<FontListEntry>();
        Iterator<String> i$ = this.fontMap.keySet().iterator();
        while (i$.hasNext()) {
            int style;
            String name = i$.next();
            int zeroInd = name.indexOf(48);
            if (zeroInd > 0) {
                style = AbstractFont.stringToStyle(name.substring(zeroInd + 1));
                name = name.substring(0, zeroInd);
                if (style == 0) {
                    style = 255;
                }
            } else {
                style = 255;
            }
            fontList.add(new FontListEntry("ResourceFont", name, 0, style));
        }
        return fontList;
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    synchronized String getFontHandle(String fontName) {
        Map<String, String> map = this.fontMap;
        synchronized (map) {
            return this.fontMap.get(fontName);
        }
    }

    @Override
    public void onEvent(EventIterator events) {
        while (events.hasNext()) {
            String path;
            Event event = events.nextEvent();
            try {
                path = event.getPath();
            }
            catch (RepositoryException re) {
                this.log.info("onEvent: Cannot get path for event " + (Object)event, (Throwable)re);
                continue;
            }
            if (!path.endsWith("/jcr:data/jcr:content")) continue;
            String fontHandle = path.substring(0, path.length() - "/jcr:data/jcr:content".length());
            String mapPageHandle = ResourceUtil.getParent((String)fontHandle);
            Resource fontMapPage = this.getFontMapPage(mapPageHandle);
            if (fontMapPage == null) {
                this.log.debug("pageModified: No fontmap support for folder {}. Ignoring modification of {}", (Object)mapPageHandle, (Object)fontHandle);
                continue;
            }
            if (event.getType() == 4) {
                this.addFont(fontMapPage, fontHandle);
                continue;
            }
            if (event.getType() == 16) {
                this.removeFont(fontMapPage, fontHandle);
                this.addFont(fontMapPage, fontHandle);
                continue;
            }
            if (event.getType() != 8) continue;
            this.removeFont(fontMapPage, fontHandle);
        }
    }

    private Map<String, String> syncFontMappings(String[] fontPath) {
        HashMap<String, String> fontMap = new HashMap<String, String>();
        for (String fontHandle : fontPath) {
            this.log.debug("syncFontMappings: Testing path entry {}", (Object)fontHandle);
            Resource fontMapPage = this.getFontMapPage(fontHandle);
            if (fontMapPage == null) {
                this.log.info("syncFontMappings: Missing .fontlist in {}. Ignoring", (Object)fontHandle);
                continue;
            }
            Map<String, String> fileFontMap = this.getFileFontMap(fontMapPage);
            this.log.debug("syncFontMappings: Loaded {} entries from fontmap", (Object)String.valueOf(fileFontMap.size()));
            Resource parent = this.systemTicket.getResource(fontHandle);
            Iterator pi = ResourceUtil.listChildren((Resource)parent);
            while (pi.hasNext()) {
                Resource page = (Resource)pi.next();
                String handle = page.getPath();
                this.log.debug("syncFontMappings: Testing page {}", (Object)handle);
                if (!handle.endsWith(".ttf") && !handle.endsWith(".TTF")) {
                    this.log.debug("syncFontMappings: {} not a TrueType page", (Object)handle);
                    continue;
                }
                String hint = "Old";
                String fontName = fileFontMap.remove(handle);
                if (fontName == null) {
                    this.log.debug("syncFontMappings: Checking possible new entry");
                    fontName = this.addFont(fontMapPage, handle);
                    hint = "New";
                }
                if (fontName == null) continue;
                this.log.debug("syncFontMappings: {} entry {} added", (Object)hint, (Object)handle);
                fontMap.put(fontName, handle);
            }
            if (!fileFontMap.isEmpty()) {
                this.log.debug("syncFontMappings: Some fonts removed");
                for (String fontFileName : fileFontMap.values()) {
                    this.log.debug("syncFontMappings: Removing {} from font map", (Object)fontFileName);
                    this.removeFontMapEntry(fontMapPage, fontFileName);
                }
                fileFontMap.clear();
            }
            this.log.debug("syncFontMappings: Commit changes to the font map");
        }
        return fontMap;
    }

    private String addFont(Resource fontMapPage, String fontHandle) {
        this.log.debug("addFont: Checking page {}", (Object)fontHandle);
        try {
            Resource fontResource = this.systemTicket.getResource(fontHandle);
            InputStream is = (InputStream)fontResource.adaptTo(InputStream.class);
            if (is == null) {
                throw new IOException("Resource does not adapt to InputStream:" + this.fontPath);
            }
            File fontFile = this.fontFileProvider.getFileForStream(is);
            Font af = Font.createFont(0, fontFile);
            int style = 0;
            String psName = af.getPSName();
            if (psName.indexOf("Bold") >= 0) {
                style |= true;
            }
            if (psName.indexOf("Italic") >= 0) {
                style |= 2;
            }
            String faceName = af.getFamily();
            String fontFileName = AbstractFont.createFontFileName(faceName, 0, style);
            this.log.info("addFont: Using {} as font {}", (Object)fontHandle, (Object)fontFileName);
            this.addFontMapEntry(fontMapPage, fontFileName, faceName, psName, fontHandle, fontFile.getAbsolutePath());
            if (this.fontMap != null) {
                this.fontMap.put(fontFileName, fontHandle);
            }
            return fontFileName;
        }
        catch (IOException ioe) {
            this.log.error("addFont: Cannot access font page {}", (Object)fontHandle, (Object)ioe);
        }
        catch (FontFormatException ffe) {
            this.log.error("addFont: Cannot read font from {}", (Object)fontHandle, (Object)ffe);
        }
        return null;
    }

    private boolean removeFont(Resource fontMapPage, String fontHandle) {
        String fontName = null;
        for (Map.Entry<String, String> entry : this.fontMap.entrySet()) {
            if (!entry.getValue().equals(fontHandle)) continue;
            fontName = entry.getKey();
            break;
        }
        if (fontName != null) {
            this.log.info("removeFont: Removing {} from font map", (Object)fontHandle);
            this.fontMap.remove(fontName);
            this.removeFontMapEntry(fontMapPage, fontName);
        } else {
            this.log.info("removeFont: No mapping for {} found.", (Object)fontHandle);
        }
        return true;
    }

    private Map<String, String> getFileFontMap(Resource fontMap) {
        this.log.debug("getFileFontMap: Loading map from {}", (Object)fontMap.getPath());
        HashMap<String, String> fileFontMap = new HashMap<String, String>();
        Iterator fi = ResourceUtil.listChildren((Resource)fontMap);
        while (fi.hasNext()) {
            Resource fontMapEntry = (Resource)fi.next();
            Map entry = (Map)fontMapEntry.adaptTo(Map.class);
            Object handleObject = entry.get("fontPath");
            if (handleObject == null) continue;
            String fontName = ResourceUtil.getName((Resource)fontMapEntry);
            this.log.debug("getFileFontMap: Adding {} => {}", (Object)fontName, handleObject);
            fileFontMap.put(handleObject.toString(), fontName);
        }
        return fileFontMap;
    }

    private Resource getFontMapPage(String path) {
        String pageName = path + "/" + ".fontlist";
        this.log.debug("getFontMapPage: fontlist Page is {}", (Object)pageName);
        Resource fontMapResource = this.systemTicket.getResource(pageName);
        if (fontMapResource == null) {
            this.log.info("getFontMapPage: Creating fontlist page");
            return this.addFontMapResource(path);
        }
        this.log.debug("getFontMapPage: Returning existing page");
        return fontMapResource;
    }

    private void setupCache() {
        this.fontMap = this.syncFontMappings(this.fontPath);
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private Resource addFontMapResource(String location) {
        Session session = (Session)this.systemTicket.adaptTo(Session.class);
        if (session != null) {
            try {
                Node locationNode = this.getOrCreateNode(session, location);
                Node fontMapNode = locationNode.addNode(".fontlist", "nt:unstructured");
                session.save();
                Resource resource = this.systemTicket.getResource(fontMapNode.getPath());
                return resource;
            }
            catch (RepositoryException re) {
                this.log.error("addFontMapResource: Cannot create font map", (Throwable)re);
            }
            finally {
                try {
                    if (session.hasPendingChanges()) {
                        session.refresh(false);
                    }
                }
                catch (RepositoryException re2) {
                    this.log.warn("addFontMapResource: Failed reverting failed changes", (Throwable)re2);
                }
            }
        }
        return null;
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private void addFontMapEntry(Resource fontMapPage, String fontFileName, String faceName, String psName, String fontPath, String fontFilePath) {
        Node fontMapNode = (Node)fontMapPage.adaptTo(Node.class);
        if (fontMapNode != null) {
            try {
                Node entryNode = fontMapNode.addNode(fontFileName, "nt:unstructured");
                entryNode.setProperty("family", faceName);
                entryNode.setProperty("psName", psName);
                entryNode.setProperty("fontPath", fontPath);
                entryNode.setProperty("fontFilePath", fontFilePath);
                fontMapNode.save();
            }
            catch (RepositoryException re) {
                this.log.error("createFontMapEntry: Cannot store the entry for " + fontFileName, (Throwable)re);
            }
            finally {
                if (fontMapNode.isModified()) {
                    try {
                        fontMapNode.refresh(false);
                    }
                    catch (RepositoryException re2) {
                        this.log.error("createFontMapEntry: Cannot revert failed changes for " + fontFileName, (Throwable)re2);
                    }
                }
            }
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private void removeFontMapEntry(Resource fontMapPage, String fontFileName) {
        Node fontMapNode = (Node)fontMapPage.adaptTo(Node.class);
        if (fontMapNode != null) {
            try {
                if (fontMapNode.hasNode(fontFileName)) {
                    fontMapNode.getNode(fontFileName).remove();
                }
                fontMapNode.save();
            }
            catch (RepositoryException re) {
                this.log.error("removeFontMapEntry: Cannot remove the entry for " + fontFileName, (Throwable)re);
            }
            finally {
                if (fontMapNode.isModified()) {
                    try {
                        fontMapNode.refresh(false);
                    }
                    catch (RepositoryException re2) {
                        this.log.error("removeFontMapEntry: Cannot revert failed changes for " + fontFileName, (Throwable)re2);
                    }
                }
            }
        }
    }

    private Node getOrCreateNode(Session session, String path) throws RepositoryException {
        if (session.itemExists(path)) {
            return (Node)session.getItem(path);
        }
        Node parent = this.getOrCreateNode(session, ResourceUtil.getParent((String)path));
        return parent.addNode(ResourceUtil.getName((String)path), "sling:Folder");
    }
}