All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javolution.text.internal.TextContextImpl Maven / Gradle / Ivy

/*
 * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
 * Copyright (C) 2012 - Javolution (http://javolution.org/)
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software is
 * freely granted, provided that this notice is preserved.
 */
package javolution.text.internal;

import java.io.IOException;
import javolution.context.LogContext;
import javolution.text.CharSet;
import javolution.text.Cursor;
import javolution.text.DefaultTextFormat;
import javolution.text.TextContext;
import javolution.text.TextFormat;
import javolution.text.TypeFormat;
import javolution.util.FastMap;

/**
 * Holds the default implementation of TextContext.
 * 
 * @author  Jean-Marie Dautelle
 * @version 6.0, July 21, 2013
 */
public final class TextContextImpl extends TextContext {

    // Holds class->format mapping. 
    private final FastMap, TextFormat> classToFormat = new FastMap, TextFormat>()
            .shared();

    // Holds parent (null if root).
    private final TextContextImpl parent;

    /** Default constructor for root */
    public TextContextImpl() {
        parent = null;
        classToFormat.put(Boolean.class, BOOLEAN_FORMAT);
        classToFormat.put(Byte.class, BYTE_FORMAT);
        classToFormat.put(Character.class, CHARACTER_FORMAT);
        classToFormat.put(Class.class, CLASS_FORMAT);
        classToFormat.put(Double.class, DOUBLE_FORMAT);
        classToFormat.put(Float.class, FLOAT_FORMAT);
        classToFormat.put(Integer.class, INTEGER_FORMAT);
        classToFormat.put(Long.class, LONG_FORMAT);
        classToFormat.put(Short.class, SHORT_FORMAT);
        classToFormat.put(String.class, STRING_FORMAT);
    }

    /** Inner constructor */
    public TextContextImpl(TextContextImpl parent) {
        this.parent = parent;
    }

    @Override
    protected TextContext inner() {
        return new TextContextImpl(this);
    }

    @SuppressWarnings("unchecked")
    @Override
    protected  TextFormat searchFormat(Class type) {
        TextFormat format = (TextFormat) classToFormat.get(type);
        if (format != null) return format;
        if (parent != null) { // Searches parent.
            format = parent.searchFormat(type);
            classToFormat.put(type, format);
            return format;
        }
        // Root context (search inheritable annotations).
        DefaultTextFormat annotation = type
                .getAnnotation(DefaultTextFormat.class);
        if (annotation != null) { // Found it.
            try {
                format = (TextFormat) annotation.value().newInstance();
                classToFormat.put(type, format);
                return format;
            } catch (Throwable error) {
                LogContext.warning(error);
            }
        }
        classToFormat.put(type, OBJECT_FORMAT);
        return (TextFormat) OBJECT_FORMAT;
    }

    @Override
    public  void setFormat(Class type, TextFormat format) {
        classToFormat.put(type, format);
    }

    ////////////////////////
    // PREDEFINED FORMATS //
    ////////////////////////

    private static final TextFormat OBJECT_FORMAT = new TextFormat() {
        ThreadLocal objToString = new ThreadLocal();

        @Override
        public Appendable format(Object obj, Appendable dest)
                throws IOException {
            if (obj == null) return dest.append("null");
            if (objToString.get() == obj) return TypeFormat.format(
                    System.identityHashCode(obj), dest.append("Object#")); // Circularity in toString !
            objToString.set(obj);
            try {
                String str = obj.toString();
                return dest.append(str);
            } finally {
                objToString.set(null);
            }
        }

        @Override
        public Object parse(CharSequence csq, Cursor cursor) {
            throw new UnsupportedOperationException(
                    "Generic object parsing not supported.");
        }

    };

    private static TextFormat BOOLEAN_FORMAT = new TextFormat() {

        @Override
        public Appendable format(Boolean obj, Appendable dest)
                throws IOException {
            return TypeFormat.format(obj.booleanValue(), dest);
        }

        @Override
        public Boolean parse(CharSequence csq, Cursor cursor) {
            return TypeFormat.parseBoolean(csq, cursor);
        }
    };

    private static TextFormat CHARACTER_FORMAT = new TextFormat() {

        @Override
        public Appendable format(Character obj, Appendable dest)
                throws IOException {
            return dest.append(obj.charValue());
        }

        @Override
        public Character parse(CharSequence csq, Cursor cursor) {
            return Character.valueOf(cursor.nextChar(csq));
        }

    };

    private static TextFormat BYTE_FORMAT = new TextFormat() {

        @Override
        public Appendable format(Byte obj, Appendable dest) throws IOException {
            return TypeFormat.format(obj.byteValue(), dest);
        }

        @Override
        public Byte parse(CharSequence csq, Cursor cursor) {
            return Byte.valueOf(TypeFormat.parseByte(csq, 10, cursor));
        }

    };

    private static TextFormat SHORT_FORMAT = new TextFormat() {

        @Override
        public Appendable format(Short obj, Appendable dest) throws IOException {
            return TypeFormat.format(obj.shortValue(), dest);
        }

        @Override
        public Short parse(CharSequence csq, Cursor cursor) {
            return Short.valueOf(TypeFormat.parseShort(csq, 10, cursor));
        }

    };

    private static TextFormat INTEGER_FORMAT = new TextFormat() {

        @Override
        public Appendable format(Integer obj, Appendable dest)
                throws IOException {
            return TypeFormat.format(obj.intValue(), dest);
        }

        @Override
        public Integer parse(CharSequence csq, Cursor cursor) {
            return Integer.valueOf(TypeFormat.parseInt(csq, 10, cursor));
        }

    };

    private static TextFormat LONG_FORMAT = new TextFormat() {

        @Override
        public Appendable format(Long obj, Appendable dest) throws IOException {
            return TypeFormat.format(obj.longValue(), dest);
        }

        @Override
        public Long parse(CharSequence csq, Cursor cursor) {
            return Long.valueOf(TypeFormat.parseLong(csq, 10, cursor));
        }

    };

    private static TextFormat FLOAT_FORMAT = new TextFormat() {

        @Override
        public Appendable format(Float obj, Appendable dest) throws IOException {
            return TypeFormat.format(obj.floatValue(), dest);
        }

        @Override
        public Float parse(CharSequence csq, Cursor cursor) {
            return new Float(TypeFormat.parseFloat(csq, cursor));
        }

    };

    private static TextFormat DOUBLE_FORMAT = new TextFormat() {

        @Override
        public Appendable format(Double obj, Appendable dest)
                throws IOException {
            return TypeFormat.format(obj.doubleValue(), dest);
        }

        @Override
        public Double parse(CharSequence csq, Cursor cursor) {
            return new Double(TypeFormat.parseDouble(csq, cursor));
        }

    };

    private static TextFormat STRING_FORMAT = new TextFormat() {

        @Override
        public Appendable format(String obj, Appendable dest)
                throws IOException {
            return dest.append(obj);
        }

        @Override
        public String parse(CharSequence csq, Cursor cursor) {
            CharSequence tmp = csq.subSequence(cursor.getIndex(), csq.length());
            cursor.setIndex(csq.length());
            return tmp.toString();
        }

    };

    private static TextFormat> CLASS_FORMAT = new TextFormat>() {

        @Override
        public Appendable format(Class obj, Appendable dest)
                throws IOException {
            return dest.append(obj.getName());
        }

        @Override
        public Class parse(CharSequence csq, Cursor cursor) {
            CharSequence name = cursor.nextToken(csq, CharSet.WHITESPACES);
            try {
                return Class.forName(name.toString());
            } catch (ClassNotFoundException e) {
                throw new IllegalArgumentException("Class " + name
                        + " Not Found");
            }
        }

    };

}