Package com.jetdrone.vertx.yoke.engine

Source Code of com.jetdrone.vertx.yoke.engine.AbstractEngine

/**
* Copyright 2011-2014 the original author or authors.
*/
package com.jetdrone.vertx.yoke.engine;

import com.jetdrone.vertx.yoke.Engine;
import com.jetdrone.vertx.yoke.core.impl.LRUCache;
import com.jetdrone.vertx.yoke.core.YokeAsyncResult;
import org.vertx.java.core.AsyncResult;
import org.vertx.java.core.AsyncResultHandler;
import org.vertx.java.core.Handler;
import org.vertx.java.core.Vertx;
import org.vertx.java.core.buffer.Buffer;
import org.vertx.java.core.file.FileProps;
import org.vertx.java.core.file.FileSystem;

import java.util.Date;
import java.util.Map;

/**
* # AbstractEngine
*
* Engine represents a Template Engine that can be registered with Yoke. Any template engine just needs to
* extend this abstract class. The class provides access to the Vertx object so the engine might do I/O
* operations in the context of the module.
*/
public abstract class AbstractEngine<T> implements Engine {

    protected Vertx vertx;

    private final LRUCache<String, T> cache = new LRUCache<>(1024);

    @Override
    public void setVertx(Vertx vertx) {
        this.vertx = vertx;
    }

    @Override
    public String contentType() {
        return "text/html";
    }

    @Override
    public String contentEncoding() {
        return "UTF-8";
    }

    /**
     * Verifies if a file in the filesystem is still fresh against the cache. Errors are treated as not fresh.
     *
     * @param filename File to look for
     * @param next next asynchronous handler
     */
    public void isFresh(final String filename, final Handler<Boolean> next) {
        final FileSystem fileSystem = vertx.fileSystem();

        fileSystem.props(filename, new AsyncResultHandler<FileProps>() {
            @Override
            public void handle(AsyncResult<FileProps> asyncResult) {
                if (asyncResult.failed()) {
                    next.handle(false);
                } else {
                    LRUCache.CacheEntry<String, T> cacheEntry = cache.get(filename);
                    final Date lastModified = asyncResult.result().lastModifiedTime();

                    if (cacheEntry == null) {
                        next.handle(false);
                    } else {
                        if (cacheEntry.isFresh(lastModified)) {
                            next.handle(true);
                        } else {
                            // not fresh anymore, purge it
                            cache.remove(filename);
                            next.handle(false);
                        }
                    }
                }
            }
        });
    }

    private void loadToCache(final String filename, final Handler<Throwable> next) {
        final FileSystem fileSystem = vertx.fileSystem();

        fileSystem.props(filename, new AsyncResultHandler<FileProps>() {
            @Override
            public void handle(AsyncResult<FileProps> asyncResult) {
                if (asyncResult.failed()) {
                    next.handle(asyncResult.cause());
                } else {
                    final Date lastModified = asyncResult.result().lastModifiedTime();
                    // load from the file system
                    fileSystem.readFile(filename, new AsyncResultHandler<Buffer>() {
                        @Override
                        public void handle(AsyncResult<Buffer> asyncResult) {
                            if (asyncResult.failed()) {
                                next.handle(asyncResult.cause());
                            } else {
                                // cache the result
                                String result = asyncResult.result().toString(contentEncoding());
                                cache.put(filename, new LRUCache.CacheEntry<String, T>(lastModified, result));
                                next.handle(null);
                            }
                        }
                    });
                }
            }
        });
    }

    /**
     * Loads a resource from the filesystem into a string.
     *
     * Verifies if the file last modified date is newer than on the cache
     * if it is loads into a string
     * returns the string or the cached value
     *
     * @param filename File to read
     * @param handler Async handler
     */
    public void read(final String filename, final AsyncResultHandler<String> handler) {
        isFresh(filename, new Handler<Boolean>() {
            @Override
            public void handle(Boolean fresh) {
                if (fresh) {
                    String cachedValue = getFileFromCache(filename);
                    if (cachedValue != null) {
                        handler.handle(new YokeAsyncResult<>(null, cachedValue));
                        return;
                    }
                }
                // either fresh is false or cachedValue is null
                loadToCache(filename, new Handler<Throwable>() {
                    @Override
                    public void handle(Throwable error) {
                        if (error != null) {
                            handler.handle(new YokeAsyncResult<String>(error, null));
                            return;
                        }
                        // no error
                        handler.handle(new YokeAsyncResult<>(null, getFileFromCache(filename)));
                    }
                });
            }
        });
    }

    /**
     * Returns the last modified time for the cache entry
     *
     * @param filename File to look for
     * @return last modified time in millis
     */
    public long lastModified(final String filename) {
        LRUCache.CacheEntry<String, T> cacheEntry = cache.get(filename);
        return cacheEntry.lastModified;
    }

    /**
     * Gets the content of the file from cache this is a synchronous operation since there is no blocking or I/O
     */
    private String getFileFromCache(String filename) {
        return cache.get(filename).raw;
    }

    /**
     * Gets the compiled value from cache this is a synchronous operation since there is no blocking or I/O
     */
    public T getTemplateFromCache(String filename) {
     
      LRUCache.CacheEntry<String, T> cachedTemplate = cache.get(filename);
     
      // this is to avoid null pointer exception in case of the layout composite template
      if (cachedTemplate == null) return null;
     
        return cachedTemplate.compiled;
    }

    /**
     * Gets the compiled value from cache this is a synchronous operation since there is no blocking or I/O
     */
    public void putTemplateToCache(String filename, T template) {
        cache.putCompiled(filename, template);
    }
   
    /**
     * Removes an entry from cache
     */
    public void removeFromCache(String filename) {
        cache.remove(filename);
    }
}
TOP

Related Classes of com.jetdrone.vertx.yoke.engine.AbstractEngine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.