net.sf.nmedit.jtheme.store.DefaultStorageContext.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.nmedit.jtheme.store.DefaultStorageContext.java

Source

/* Copyright (C) 2006 Christian Schneider
 * 
 * This file is part of Nomad.
 * 
 * Nomad is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * Nomad is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Nomad; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package net.sf.nmedit.jtheme.store;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StringReader;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.nmedit.jtheme.JTContext;
import net.sf.nmedit.jtheme.JTException;
import net.sf.nmedit.jtheme.image.ImageCache;
import net.sf.nmedit.jtheme.image.ImageResource;
import net.sf.nmedit.jtheme.store2.ButtonElement;
import net.sf.nmedit.jtheme.store2.ComponentElement;
import net.sf.nmedit.jtheme.store2.ConnectorElement;
import net.sf.nmedit.jtheme.store2.ImageElement;
import net.sf.nmedit.jtheme.store2.LabelElement;
import net.sf.nmedit.jtheme.store2.LightElement;
import net.sf.nmedit.jtheme.store2.ModuleElement;
import net.sf.nmedit.jtheme.store2.SliderElement;
import net.sf.nmedit.jtheme.store2.TextDisplayElement;
import net.sf.nmedit.nmutils.PluginObjectInputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.w3c.dom.css.CSSStyleSheet;
import org.xml.sax.InputSource;

import com.steadystate.css.parser.CSSOMParser;

public class DefaultStorageContext extends StorageContext {

    private static final Log log = LogFactory.getLog(DefaultStorageContext.class);

    private static final boolean DEBUG = false;

    private Map<Object, ModuleElement> moduleStoreMap = new HashMap<Object, ModuleElement>();
    private ClassLoader classLoader;
    private CSSStyleSheet styleSheet;

    private Map<String, ImageResource> imageResourceMap = new HashMap<String, ImageResource>();

    private ImageCache imageCache = new ImageCache();

    private static transient Log _logger;

    private static Log getLogger() {
        if (_logger == null)
            _logger = LogFactory.getLog(DefaultStorageContext.class);
        return _logger;
    }

    public ImageCache getImageCache() {
        return imageCache;
    }

    public DefaultStorageContext(JTContext context, ClassLoader classLoader) {
        this.classLoader = classLoader;
        this.context = context;
        installDefaults();
    }

    private JTContext context;

    public JTContext getContext() {
        return context;
    }

    public ImageResource getCachedImage(URL source) {
        if (source != null) {
            return imageResourceMap.get(source.toString());
        }
        return null;
    }

    public ImageResource getCachedImage(String source) {
        ImageResource ir = imageResourceMap.get(source);
        if (ir == null) {
            ClassLoader loader = classLoader != null ? classLoader : getClass().getClassLoader();
            URL url = loader.getResource(source);
            ir = getCachedImage(url);
        }
        return ir;
    }
    /*
    public void putImage(URL url, ImageResource ir)
    {
    if (url != null)
    {
        if (ir.getImageCache() != null)
            ir.setImageCache(imageCache);
        imageResourceMap.put(url, ir);
    }
    }*/

    public void putImage(String key, ImageResource ir) {
        if (key != null) {
            if (ir.getImageCache() != null)
                ir.setImageCache(imageCache);
            imageResourceMap.put(key, ir);
        }
    }

    public CSSStyleSheet getStyleSheet() {
        return styleSheet;
    }

    public ClassLoader getContextClassLoader() {
        return classLoader;
    }

    protected void installDefaults() {
        installStore("module", ModuleElement.class);
        installStore("label", LabelElement.class);
        installStore("image", ImageElement.class);
        installStore("connector", ConnectorElement.class);
        installStore("button", ButtonElement.class);
        installStore("slider", SliderElement.class);
        installStore("textDisplay", TextDisplayElement.class);
        installStore("light", LightElement.class);
    }

    @Override
    public ModuleElement getModuleStoreById(Object id) {
        return moduleStoreMap.get(id);
    }

    private File cacheDir = null;

    private File getElementCacheFile() {
        if (cacheDir != null)
            return new File(cacheDir, "data.cache");
        return null;
    }

    private File getImageCacheFile() {
        if (cacheDir != null)
            return new File(cacheDir, "image.cache");
        return null;
    }

    public void setCacheDir(File cacheDir) {
        this.cacheDir = cacheDir;

        if (cacheDir != null && (!cacheDir.exists())) {
            boolean ok = cacheDir.mkdir();
            // TODO handle ok==false
        }
    }

    public File getCacheDir() {
        return cacheDir;
    }

    public void parseStore(InputSource source) throws JTException {
        parseStore(source, null);
    }

    public void parseStore(InputSource source, ClassLoader loader) throws JTException {
        final boolean DEBUG_DISABLE_CACHE = false;

        if (loader == null)
            loader = getClass().getClassLoader();

        long t = 0; // for timing stuff

        boolean imageCacheRead = false;
        boolean elementCacheRead = false;

        File imageCacheFile = getImageCacheFile();
        if (imageCacheFile != null && imageCacheFile.exists() && (!DEBUG_DISABLE_CACHE)) {
            if (DEBUG)
                System.out.println(this + ": image cache file " + imageCacheFile + " (exists)");

            try {
                if (DEBUG)
                    t = System.currentTimeMillis();
                imageCache.readCacheFile(imageCacheFile);
                imageCacheRead = true;
                if (DEBUG)
                    System.out.println(this + ": image cache read in " + (System.currentTimeMillis() - t) + "ms");
            } catch (Throwable et) {
                if (log.isTraceEnabled())
                    log.trace("loading images from cache failed", et);
            }
        }

        File cacheFile = getElementCacheFile();

        try {

            if (cacheFile != null && (!DEBUG_DISABLE_CACHE)) {
                if (DEBUG)
                    System.out.println(
                            this + ": element cache file " + cacheFile + " (exists:" + cacheFile.exists() + ")");

                if (cacheFile.exists()) {
                    if (DEBUG)
                        t = System.currentTimeMillis();
                    if (initializeFromCache(cacheFile, loader)) {
                        elementCacheRead = true;
                        if (DEBUG)
                            System.out.println(this + ": elements initialized from cache in "
                                    + (System.currentTimeMillis() - t) + "ms");
                    } else {
                        if (DEBUG)
                            System.out.println(this + ": initialization of elements from cache failed");
                    }
                }
            }
        } catch (Exception e) {
            if (log.isTraceEnabled())
                log.trace("loading elements from cache failed", e);
        }

        if (imageCacheRead && elementCacheRead)
            return;

        if (!elementCacheRead) {
            SAXBuilder saxBuilder = new SAXBuilder();
            try {
                if (DEBUG)
                    t = System.currentTimeMillis();
                Document document = saxBuilder.build(source);
                buildStore(document);
                if (DEBUG)
                    System.out.println(this + ": built store in " + (System.currentTimeMillis() - t) + "ms");
            } catch (JDOMException e) {
                throw new JTException(e);
            } catch (IOException e) {
                throw new JTException(e);
            }

            if (cacheFile != null && (!DEBUG_DISABLE_CACHE)) {
                if (DEBUG)
                    System.out.println(this + ": writing element cache");
                writeCache(cacheFile);
            }
        }

        if (!imageCacheRead) {
            if (imageCacheFile != null) {
                // render images
                if (DEBUG)
                    System.out.println(this + ": render images...");

                if (DEBUG)
                    t = System.currentTimeMillis();
                for (ModuleElement m : moduleStoreMap.values()) {
                    for (ComponentElement e : m) {
                        if (e instanceof ImageElement)
                            ((ImageElement) e).renderImage(this);
                    }
                }
                if (DEBUG)
                    System.out.println(this + ": rendered in " + (System.currentTimeMillis() - t) + "ms");

                try {
                    if (!DEBUG_DISABLE_CACHE) {
                        if (DEBUG)
                            System.out.println(this + ": write image cache...");
                        imageCache.writeCacheFile(imageCacheFile);
                    }
                } catch (Exception e) {
                    if (log.isWarnEnabled())
                        log.warn("could not write image cache to: " + imageCacheFile, e);
                }
            }
        }

    }

    private void writeCache(File cacheFile) {
        try {
            __writeCache(cacheFile);
        } catch (Exception e) {
            if (log.isErrorEnabled())
                log.error("writeCache(" + (cacheFile == null ? null : cacheFile.getAbsolutePath()) + ") failed", e);
        }
    }

    private void __writeCache(File cacheFile) throws Exception {
        ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(cacheFile)));
        try {
            // css
            out.writeObject(cssStyleSheet);

            // defs
            out.writeInt(imageResourceMap.size());
            for (Object key : imageResourceMap.keySet()) {
                out.writeObject(key);
                Object ir = imageResourceMap.get(key);
                out.writeObject(ir);
            }
            // modules
            out.writeInt(moduleStoreMap.size());
            for (ModuleElement e : moduleStoreMap.values()) {
                out.writeObject(e);
            }
        } finally {
            out.flush();
            out.close();
        }
    }

    private boolean initializeFromCache(File cacheFile, ClassLoader loader) throws Exception {
        ObjectInputStream in = new PluginObjectInputStream(loader,
                new BufferedInputStream(new FileInputStream(cacheFile)));
        try {
            {
                // css
                cssStyleSheet = (String) in.readObject();
                try {
                    buildCssFromString(cssStyleSheet);
                } finally {
                    cssStyleSheet = null;
                }
            }
            {
                // defs
                ClassLoader cl = getContextClassLoader();
                if (cl == null)
                    cl = loader;
                int size = in.readInt();

                imageResourceMap = new HashMap<String, ImageResource>(size * 2);
                for (int i = 0; i < size; i++) {
                    String key = (String) in.readObject();
                    ImageResource ir = (ImageResource) in.readObject();
                    ir.setCustomClassLoader(cl);
                    ir.setImageCache(imageCache);

                    imageResourceMap.put(key, ir);
                }
            }
            {
                // module elements
                int size = in.readInt();
                moduleStoreMap = new HashMap<Object, ModuleElement>(size);
                for (int i = 0; i < size; i++) {
                    ModuleElement e = (ModuleElement) in.readObject();
                    moduleStoreMap.put(e.getId(), e);
                    e.initializeElement(this);
                }
            }
        } finally {
            in.close();
        }
        return true;
    }

    /*  
        public static DefaultStorageContext parseStore(ClassLoader classLoader, InputSource source)
          throws JTException
        {
    DefaultStorageContext dsc = new DefaultStorageContext(classLoader); 
    dsc.parseStore(source);
    return dsc;
        }
    */

    protected void buildStore(Document document) throws JTException {
        Element root = document.getRootElement();

        buildDefs(root);
        buildCss(root);
        buildModules(root);
    }

    private void buildDefs(Element root) {
        Element defs = root.getChild("defs");
        if (defs == null)
            return;

        List imageList = defs.getChildren("image");

        for (int i = imageList.size() - 1; i >= 0; i--) {
            buildDefsImage((Element) imageList.get(i));
        }
    }

    private void buildDefsImage(Element element) {
        String id = element.getAttributeValue("id");
        if (id.length() == 0)
            return;

        ImageResource is = ImageElement.getImageResource(this, element);
        if (is != null) {
            is.setImageCache(getImageCache());
            imageResourceMap.put(id, is);
        }
    }

    public ImageResource getImageResourceById(String id) {
        return imageResourceMap.get(id);
    }

    protected transient String cssStyleSheet;

    private void buildCss(Element root) throws JTException {
        Element styleElement = null;

        List<?> children = root.getChildren();
        for (int i = 0; i < children.size(); i++) {
            Element e = (Element) children.get(i);
            String name = e.getName();

            if (name.equals("style")) {
                styleElement = e;
                break;
            } else if (!name.equals("defs")) {
                break;
            }
        }

        cssStyleSheet = styleElement != null ? styleElement.getText() : "";
        buildCssFromString(cssStyleSheet);
    }

    private void buildCssFromString(String cssText) throws JTException {
        CSSOMParser cssParser = CSSUtils.getCSSOMParser();
        try {
            // TODO set uri ???
            //source.setURI(arg0)
            if (cssText == null)
                return;

            org.w3c.css.sac.InputSource source = new org.w3c.css.sac.InputSource(new StringReader(cssText));

            styleSheet = cssParser.parseStyleSheet(source, null, null);
        } catch (NullPointerException e) {
            Log log = getLogger();
            if (log.isWarnEnabled()) {
                log.warn("buildCssFromString", e);
            }
        } catch (IOException e) {
            Log log = getLogger();
            if (log.isWarnEnabled()) {
                log.warn("buildCssFromString", e);
            }
            return;
            // throw new JTException(e);
        }
    }

    private void buildModules(Element root) throws JTException {
        for (Object moduleElement : root.getChildren("module")) {
            buildModuleStore((Element) moduleElement);
        }
    }

    private void buildModuleStore(Element moduleElement) throws JTException {
        ModuleElement moduleStore = (ModuleElement) buildComponentStore(moduleElement);

        for (Object uchild : moduleElement.getChildren()) {
            Element child = (Element) uchild;
            String name = child.getName();

            boolean dontLoad = name.equals("name") || name.startsWith("select-");

            if (!dontLoad) {
                ComponentElement childStore = tryBuildComponentStore(moduleElement, child);

                if (childStore != null) {
                    moduleStore.add(childStore);
                }
            }
        }

        moduleStoreMap.put(moduleStore.getId(), moduleStore);
    }

    private ComponentElement tryBuildComponentStore(Element moduleElement, Element element) {
        try {
            return buildComponentStore(element);
        } catch (JTException e) {
            Log log = getLogger();
            if (log.isWarnEnabled()) {
                log.warn("could not create component store for element " + element.getName() + " (parent "
                        + moduleElement.getAttributeValue("component-id") + ")", e);
            }
            return null;
        }
    }

    private ComponentElement buildComponentStore(Element element) throws JTException {
        // TODO not all elements can be handled ????
        try {
            return createStore(element);
        } catch (JTException e) {
            // TODO find a better solution for unsupported elements
            if (e.getMessage().startsWith("No store for element")) {
                Log log = getLogger();
                if (log.isWarnEnabled()) {
                    log.warn(this, e);
                }
                return null;
            }
            throw e;
        }
    }

}