⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 template.java

📁 Ftp服务1.0
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
package ranab.tpl;

import java.io.*;
import java.util.*;


/** 
 * This class is used to load files into <code>OutputStream</code> 
 * after parsing the template file. It supports variables, 
 * for block, if-then-else block and iterator block. It has
 * only one public method - <code>loadFile(OutputStream, Map)</code>.
 * It also supports vector indexing. It stores the file data in a 
 * byte array. We may face some problems later due to character 
 * encoding. But for the time being it works fine.
 * <a href="syntax.html">Template syntax.</a>
 *
 * @author <a href="mailto:rana_b@yahoo.com">Rana Bhattacharyya</a>
 */
public 
class Template {

    // whitespaces
    private static final String mstWhitespaces = " \t\r\n\f";

    // keywords
    private static final String[] mstKeywords = { "IF",
        "FOR",
        "ITR",
        "VARKEY",
        "NULL"
    };

    // keyword index
    private static final int IF     = 0;
    private static final int FOR    = 1;
    private static final int ITR    = 2;
    private static final int VARKEY = 3;
    private static final int NULL   = 4;
    private static final int VAR    = 5;

    private static final String SIZE = ".size"; 
    private static final String LAST = ".last";
    private static final String THRU = "THRU";
    private static final String EQ   = "==";
    private static final String NE   = "!=";
    private static final String IN   = "IN";

    private File   mFile;
    private long   mModifiedTime = 0;
    private byte[] mbyContent;


    /**
     * Constructor.
     */
    public Template(File file) {
        mFile = file;
    }


    /**
     * Read file (if modified) into a byte array.
     * This function is <code>Synchronized</code> to make
     * this class thread safe. 
     */
    private synchronized void readFile() throws IOException {

        // file check
        if (!mFile.exists())
            throw new IOException(toString() + " : does not exist.");
        if (!mFile.canRead())
            throw new IOException(toString() + " : no read permission.");
        if (!mFile.isFile())
            throw new IOException(toString() + " : not a file.");

        // file modified
        boolean bNeeded = false;
        long modTime = mFile.lastModified();
        if (modTime > mModifiedTime) {
            mModifiedTime = modTime;
            bNeeded = true;
        }

        if (bNeeded) {
            mbyContent = new byte[(int)mFile.length()];
            FileInputStream fis = new FileInputStream(mFile);
            fis.read(mbyContent);
            fis.close();
        }
    }


    /**
     * Process block. First find the block type and then process.
     */
    private int processBlock(OutputStream out, Map hash, Block block) 
    throws IOException {

        // get keyword type or var
        int type = VAR; 
        for (int i=0; i<mstKeywords.length; i++) {
            if ( block.equals(mstKeywords[i]) ) {
                type = i;
                break;
            }
        }

        return processBlock(out, hash, block, type);
    }


    /**
     * Process block - call respective functions. Each of these 
     * functions returns the next index from where the next
     * processing starts.
     */
    private int processBlock(OutputStream out, Map hash,
                             Block block, int type)
    throws IOException {

        int index;

        switch (type) {
        
        case VAR:
            index = processVarBlock(out, hash, block);
            break;

        case IF:
            index = processIfBlock(out, hash, block.nextIndex());
            break;

        case FOR:
            index = processForBlock(out, hash, block.nextIndex());
            break;

        case VARKEY:
            index = processVarkeyBlock(out, block);
            break;

        case NULL:
            index = processNullBlock(out, block);
            break;

        case ITR:
            index = processItrBlock(out, hash, block.nextIndex());
            break;

        default:
            throw new IOException("Unknown keyword index=" + type);
        }   

        return index;
    }


    /**
     * Process null block - returns nothing
     */
    private int processNullBlock(OutputStream out, Block block) {
        return block.nextIndex();
    }


    /**
     * Process varkey.
     * It is used to write ${ in the <code>OutputStream</code>.
     */
    private int processVarkeyBlock(OutputStream out, Block block) 
    throws IOException {

        out.write('$');
        out.write('{');
        return block.nextIndex();
    }


    /**
     * Process normal block. Normal block may contain other variables,
     * keywords and other normal blocks. Search for "${". If found,
     * get the block and process it.
     */
    private int processNormalBlock(OutputStream out, Map hash, Block block)
    throws IOException {

        int ind = block.miStart;
        int finalIndex = ind + block.miLength;
        char c, c1;
        while (ind < finalIndex) {
            c = (char)mbyContent[ind++];

            if (c == '$') {
                c1 = (char)mbyContent[ind++];

                // not a variable
                if (c1 != '{') {
                    out.write(c);
                    out.write(c1);
                    continue;
                }

                // variable and/or keyword
                Block nextBlock = getBlock(ind);
                ind = processBlock(out, hash, nextBlock);   
            } else {
                out.write(c);   
            }
        }

        return block.nextIndex();
    }


    /**
     * Process variable block. Get variable object from the 
     * <code>Map</code> and write the string representation 
     * of the object. 
     */
    private int processVarBlock(OutputStream out, Map hash, Block block)
    throws IOException {

        // get variable value and send it
        String sb = block.toString();
        Object val = getVarObject(hash, sb);

        if (val != null)
            out.write(val.toString().getBytes());

        return block.nextIndex();
    }


    /**
     * Get variable object. 
     * Returns null if not available in the Map
     */
    private Object getVarObject(Map hash, String var) 
    throws IOException {

        // get actual variable string
        String sb = getActualVarString(hash, var);

        // get vector size
        if (sb.endsWith(SIZE)) {
            return getVarSize(hash, var);
        }

        // get last element of a vector
        if (sb.endsWith(LAST)) {
            return getLastVar(hash, var);
        }

        // get vector element at a particular index
        int startIndex = sb.indexOf('[');
        int endIndex = sb.indexOf(']');
        if (startIndex != -1 && endIndex != -1) {
            if (endIndex < endIndex)
                throw new IOException("List indexing error");

            String indexBlock = sb.substring(startIndex+1, endIndex);       
            String vectVar = sb.substring(0, startIndex);
            Object obj = getVarObject(hash, vectVar);
            return getIndexedObject(obj, indexBlock);
        }

        // null variable
        if (sb.equals(mstKeywords[NULL])) {
            return null;
        }

        // return other values
        return hash.get(sb);
    }


    /**
     * Get conditional variable object. If not a variable returns 
     * the string itself. Else returns the equivalent object from
     * the hashtable. If it is not available in the hashtable
     * returns null.
     */
    private Object getCondVarObject(Map hash, String str) 
    throws IOException{

        Object obj = null;

        // variable
        if (str.charAt(0) == '$' && str.charAt(1) == '{') {
            String var1 = str.substring(2, str.length() - 1);
            String var2 = getBlock(str, 2);

            if (var1.equals(var2))
                obj = getVarObject(hash, var1);
            else
                obj = getActualVarString(hash, str);
        } else
            obj = getActualVarString(hash, str);

        return obj;
    }


    /**
     * Returns the size of a variable as an <code>Integer</code> 
     * object. In case of Scalar returns 1. If object is null,
     * returns 0 and in case of <code>List</code>
     * returns the list size.
     */
    private Integer getVarSize(Map hash, String sb) 
    throws IOException {

        // get object form hashtable
        String vectName = sb.substring(0, sb.length()-SIZE.length());
        Object obj = getVarObject(hash, vectName);

        if (obj == null)
            return new Integer(0);

        if (obj instanceof java.util.List)
            return new Integer(((List)obj).size());

        return new Integer(1);
    }


    /**
     * Returns the last element of a vector. In case of scalar,
     * returns the object itself. In case of null returns null
     * and in case of vector returns null if size is zero or the 
     * last element. 
     */
    private Object getLastVar(Map hash, String sb) 
    throws IOException {

        String vectName = sb.substring(0, sb.length()-LAST.length());
        Object obj = getVarObject(hash, vectName);

        if (obj == null)
            return null;

        if (obj instanceof java.util.List) {
            List v = (List)obj;
            if (v.size() == 0)
                return null;
            else
                return v.get(v.size() - 1);
        }

        return obj;
    }


    /**
     * Get vector element at a particular index. Tokenize  
     * <code>indexBlock</code> string and returns the element.
     */
    private Object getIndexedObject(Object obj, String indexBlock) {

        if (obj == null)
            return null;

        StringTokenizer st = new StringTokenizer(indexBlock, ",");
        while (st.hasMoreTokens()) {
            String initVar = st.nextToken().trim();
            int ind = Integer.parseInt(initVar);
            obj = elementAt(obj, ind); 
        }

        st = null;
        return obj;
    }


    /**
     * Returns an element at a particular element. If the object
     * is null, returns null. If the object is a <code>List</code>
     * returns null if the index is out of range or the element at
     * that index. 
     */
    private Object elementAt(Object obj, int index) {

        if (obj == null)
            return null;

        if (obj instanceof java.util.List) {

            int size = ((List)obj).size();
            if (index >= size || index < 0)
                return null;

            return((List)obj).get(index);
        }

        if (index == 0)
            return obj;

        return null;
    }


    /**
     * Variable name can be formed dynamically. This function is
     * used to get the actual variable name - by resolving inner
     * variable name. Keywords will be treated as variables. The
     * variable within '{' and '}' will be replaced by its string
     * representation.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -