/*
* 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 <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
* @version 6.0, July 21, 2013
*/
public final class TextContextImpl extends TextContext {
// Holds class->format mapping.
private final FastMap<Class<?>, TextFormat<?>> classToFormat = new FastMap<Class<?>, 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 <T> TextFormat<T> searchFormat(Class<? extends T> type) {
TextFormat<T> format = (TextFormat<T>) 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<T>) annotation.value().newInstance();
classToFormat.put(type, format);
return format;
} catch (Throwable error) {
LogContext.warning(error);
}
}
classToFormat.put(type, OBJECT_FORMAT);
return (TextFormat<T>) OBJECT_FORMAT;
}
@Override
public <T> void setFormat(Class<? extends T> type, TextFormat<T> format) {
classToFormat.put(type, format);
}
////////////////////////
// PREDEFINED FORMATS //
////////////////////////
private static final TextFormat<?> OBJECT_FORMAT = new TextFormat<Object>() {
ThreadLocal<Object> objToString = new ThreadLocal<Object>();
@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> BOOLEAN_FORMAT = new TextFormat<Boolean>() {
@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> CHARACTER_FORMAT = new TextFormat<Character>() {
@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> BYTE_FORMAT = new TextFormat<Byte>() {
@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> SHORT_FORMAT = new TextFormat<Short>() {
@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> INTEGER_FORMAT = new TextFormat<Integer>() {
@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> LONG_FORMAT = new TextFormat<Long>() {
@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> FLOAT_FORMAT = new TextFormat<Float>() {
@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> DOUBLE_FORMAT = new TextFormat<Double>() {
@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> STRING_FORMAT = new TextFormat<String>() {
@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<?>> CLASS_FORMAT = new TextFormat<Class<?>>() {
@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");
}
}
};
}