package jfun.yan.xml;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import jfun.util.Misc;
import jfun.util.dict.Dict;
import jfun.yan.Component;
import jfun.yan.Components;
import jfun.yan.Creator;
import jfun.yan.ParameterBinder;
import jfun.yan.PropertyBinder;
import jfun.yan.function.Signature;
import jfun.yan.util.Utils;
import jfun.yan.util.resource.ResourceLoader;
import org.xml.sax.Locator;
class MyUtil {
static boolean isRefName(String name){
if(name.length()>0){
if(name.charAt(0)!='$') return false;
if(name.length()>1){
final char c1 = name.charAt(1);
return c1!='$' && Character.isJavaIdentifierPart(c1);
}
else return true;
}
return false;
}
static Location toLocation(Locator loc){
return new Location(loc.getSystemId(), loc.getLineNumber(), loc.getColumnNumber());
}
static Set getNameSet(String[] names){
final HashSet result = new HashSet(names.length);
for(int i=0; i<names.length; i++){
result.add(names[i]);
}
return result;
}
private static final HashMap primitives = getPrimitiveTypes();
private static HashMap getPrimitiveTypes(){
final HashMap types = new HashMap();
types.put("int", int.class);
types.put("short", short.class);
types.put("byte", byte.class);
types.put("char", char.class);
types.put("boolean", boolean.class);
types.put("long", long.class);
types.put("float", float.class);
types.put("double", double.class);
return types;
}
static Class getArrayType(Class type){
return Misc.getArrayType(type);
}
static void assertAttributes(Tag tag, Set table){
final Attributes attrs = tag.getAttributes();
for(int i=0;i<attrs.size();i++){
final String name = attrs.getKey(i);
if(!table.contains(name)){
throw new ConfigurationException("attribute "+name+" not supported for "
+tag.getName(),
tag.getLocation());
}
}
}
static Class getClass(ClassLoader cloader, String typename)
throws ClassNotFoundException{
if(typename.endsWith("[]")){
return getArrayType(
getClass(cloader, typename.substring(0, typename.length()-2))
);
}
Class type = (Class)primitives.get(typename);
if(type!=null) return type;
return cloader.loadClass(typename);
}
private static Class getCastType(ClassLoader cloader, Attributes attrs, Location loc){
final String typename = attrs.getVal(Constants.TYPE);
if(typename != null){
try{
final Class type = getClass(cloader, typename.trim());
return type;
}
catch(ClassNotFoundException e){
throw new ConfigurationException("class " + typename+" not found",
loc);
}
}
return null;
}
static SingletonMode getSingletonStrategy(
String singleton, Location loc, SingletonMode def){
if(singleton==null){
return def;
}
else{
singleton = singleton.trim().toLowerCase(Locale.US);
if(singleton.equals("thread")){
return Modes.thread_local_singleton;
}
else{
Boolean yesno = NutsUtils.toBoolean(singleton);
if(yesno==null){
throw new ConfigurationException("unrecognized value for singleton: "+singleton,
loc);
}
if(yesno.booleanValue()){
return Modes.simple_singleton;
}
else return null;
}
}
}
/*
static ComponentDecorator getSingletonStrategy(
Attributes attrs,
Location loc, ComponentDecorator def){
String singleton = attrs.getVal(Constants.SINGLETON);
}*/
/*
private static void assertMethodName(Component c, String mname,
Location loc){
final Class type = c.getType();
if(type!=null){
try{
type.getMethod(mname, null);
}
catch(NoSuchMethodException e){
throw new ConfigurationException("lifecycle method "
+ mname + " not defined by "+ Misc.getTypeName(type),
loc);
}
}
}*/
private static Set wirenames = getNameSet(new String[]{
Constants.BYNAME, Constants.BYTYPE, Constants.BYQUALIFIEDNAME,
Constants.TRUE, Constants.FALSE, Constants.YES, Constants.NO,
Constants.ON, Constants.OFF, Constants.AUTODETECT,
});
private static Set propmodes = getNameSet(new String[]{
Constants.BYNAME, Constants.BYQUALIFIEDNAME
});
static ParameterBinder getParamWiring(String autowire, AutoWiringMap custom_wirings,
Location loc, ParameterBinder def){
if(autowire!=null){
autowire = autowire.trim().toLowerCase(Locale.US);
ParameterBinder custom = custom_wirings.getParameterWiringMode(autowire);
if(custom!=null) return custom;
if(propmodes.contains(autowire)){
//this is byname or byqualified name, we skip.
return Modes.params_bytype;
}
if(Constants.BYTYPE.equals(autowire) || Constants.AUTODETECT.equals(autowire)){
return Modes.params_bytype;
}
else{
final Boolean tmp = NutsUtils.toBoolean(autowire);
if(tmp!=null){
if(tmp.booleanValue()){
return Modes.params_bytype;
}
else return null;
}
else if(custom_wirings.getPropertyWiringMode(autowire)==null){
throw new ConfigurationException("unrecognized autowire mode: "+autowire,
loc);
}
}
}
return def;
}
private static final HashMap auto_resolutions = getResolutionNames();
private static final HashMap manual_names = getManualNames();
private static HashMap getManualNames(){
final HashMap result = new HashMap();
result.put(Constants.OFF, Boolean.valueOf(false));
result.put(Constants.FALSE, Boolean.valueOf(false));
result.put(Constants.NO, Boolean.valueOf(false));
result.put(Constants.NONE, Boolean.valueOf(false));
return result;
}
private static HashMap getResolutionNames(){
final HashMap result = new HashMap();
final PropertyBinder bytype = Modes.props_bytype;
result.put(Constants.BYNAME, Modes.props_byname);
result.put(Constants.BYTYPE, bytype);
result.put(Constants.AUTODETECT, Modes.props_autodetect);
//result.put(Constants.ON, bytype);
//result.put(Constants.TRUE, bytype);
//result.put(Constants.YES, bytype);
result.put(Constants.BYQUALIFIEDNAME, Modes.props_byqualifiedname);
return result;
}
public static PropertyBinder getPropWiring(String autowire,
AutoWiringMap custom_wirings, Location loc, PropertyBinder def){
if(autowire!=null){
autowire = autowire.trim().toLowerCase(Locale.US);
PropertyBinder custom = custom_wirings.getPropertyWiringMode(autowire);
if(custom!=null) return custom;
if(manual_names.containsKey(autowire)){
return null;
}
final PropertyBinder result = (PropertyBinder)auto_resolutions.get(autowire);
if(result != null) return result;
else if(custom_wirings.getParameterWiringMode(autowire)!=null){
throw new ConfigurationException("unrecognized autowire mode: "+autowire,
loc);
}
}
return def;
}
static ParameterBinder autocast(final ParameterBinder binder,
final Location loc, final Converter conv){
if(binder==null) return null;
return new ParameterBinder(){
public String toString(){
return binder.toString();
}
public Creator bind(Signature src, int ind, Class type) {
return cast(type, Components.adapt(binder.bind(src, ind, type)),
loc, conv);
}
};
}
static PropertyBinder autocast(final PropertyBinder binder,
final Location loc, final Converter conv){
if(binder==null) return null;
return new PropertyBinder(){
public String toString(){
return binder.toString();
}
public Creator bind(Class component_type, Object key, Class type) {
return cast(type, Components.adapt(binder.bind(component_type, key, type)),
loc, conv);
}
};
}
static ComponentDecorator getComponentDecorator(
Runtime runtime,
final Location loc,
final Class castto, final ComponentDecorator singleton,
final ParameterBinder wiring, final boolean sync,
final Converter conv){
/*
final Class castto = getCastType(runtime.getClassloader(), attrs, loc);
final String wirename = attrs.getVal(Constants.AUTOWIRE);
if(wirename!=null && !wirenames.contains(wirename)){
throw new ConfigurationException("unknown autowire strategy: "+wirename,
loc);
}
final ParameterBinder wiring = getParamWiring(wirename,
loc, def_strategy.getParameterWiring());
//final boolean sealed = isSeal(autowire);
final ComponentDecorator singleton = getSingletonStrategy(attrs, loc,
def_strategy.getSingletonMode());
//final DefaultLifecycleManager manager = runtime.getLifecycleManager();
*/
return new SingletonMode(){
/*
public Class transform(Class type){
if(castto!=null) return castto;
else return type;
}*/
public Component decorate(Component c){
if(sync){
c = c.synchronize();
}
if(castto!=null)
c = cast(castto, c, loc, conv);//c.subsume(castto);
if(wiring!=null){
c = c.bindArguments(autocast(wiring, loc, conv));
}
if(singleton!=null){
c = singleton.decorate(c);
}
/*
final String initializer = attrs.getVal(Constants.INITIALIZER);
if(initializer != null){
assertMethodName(c, initializer, loc);
Class realtype = c.isConcrete()?c.getType():null;
c = c.followedBy(
Components.invokingMethod(realtype, initializer, null, false));
}
//we do initialization before wiring. So skip the default lifecycle manager
//for initializers.
final DefaultLifecycleManager.DefaultLifecycle lifecycle = manager.newLifecycle();
final String disposer = attrs.getVal(Constants.DISPOSER);
if(disposer != null){
assertMethodName(c, disposer, loc);
lifecycle.disposer(disposer);
}
final String starter = attrs.getVal(Constants.STARTER);
if(starter != null){
assertMethodName(c, starter, loc);
lifecycle.starter(starter);
}
final String stopper = attrs.getVal(Constants.STOPPER);
if(stopper != null){
assertMethodName(c, stopper, loc);
lifecycle.stopper(stopper);
}
c = lifecycle.manage(c);*/
return c;
}
};
}
static Component wrapComponent(Component c, Runtime runtime,
final Location loc, Class casttype, ComponentDecorator singleton,
ParameterBinder autowire, boolean sync,
Converter conv){
return getComponentDecorator(runtime, loc, casttype, singleton, autowire, sync,
conv)
.decorate(c).label(loc);
}
static InputStream readResource(ResourceLoader loader, String resourcename)
throws IOException{
final InputStream in = loader.getResourceAsStream(resourcename);
if(in == null){
throw new IllegalArgumentException("cannot find resuorce: "+resourcename);
}
return in;
}
static String getMandatory(Tag tag, String name){
final String result = tag.getAttribute(name);
if(result==null)
throw new ConfigurationException("<"+tag.getName()+"> - missing mandatory attribute: "
+ name
,tag.getLocation());
return result;
}
static String getAttribute(Tag tag, String name1, String name2){
final String val1 = tag.getAttribute(name1);
final String val2 = tag.getAttribute(name2);
if(val1!=null && val2!=null){
throw new ConfigurationException("<"+tag.getName()+"> - "
+name1 + " and " + name2 + " are both specified, while only one is expected."
,tag.getLocation());
}
return val1==null?val2:val1;
}
static String getEagerMode(Tag tag){
return getAttribute(tag, Constants.EAGER_INSTANTIATED,
Constants.EAGER_INSTANTIATED2);
}
/*
static ComponentBinder wrapBinder(final ComponentBinder binder, Runtime runtime, final Attributes attrs,
final Location loc){
final ComponentTransformer trans = getComponentTransformer(runtime, attrs, loc);
return new ComponentBinder(){
public Creator bind(Object v)
throws Throwable{
return trans.transform(Components.adapt(binder.bind(v)));
}
public Class bindType(Class type){
return trans.transform(binder.bindType(type));
}
public Verifiable verify(Class type){
final Verifiable veri = binder.verify(type);
return new Verifiable(){
public Class verify(Dependency dep)
throws IrresolveableArgumentException, ParameterTypeMismatchException, AmbiguousComponentResolutionException, YanException {
return trans.transform(veri.verify(dep));
}
};
}
};
}
static Binder wrapBinder(final Binder binder,Runtime runtime, final Attributes attrs,
final Location loc){
if(binder instanceof ComponentBinder){
return wrapBinder((ComponentBinder)binder, runtime, attrs, loc);
}
else{
final ComponentTransformer trans = getComponentTransformer(runtime, attrs, loc);
return new Binder(){
public Creator bind(Object v)
throws Throwable{
return trans.transform(Components.adapt(binder.bind(v)));
}
};
}
}
private static boolean isSeal(String autowire){
if(autowire==null) return true;
autowire = autowire.toLowerCase(Locale.US);
final Boolean is_autowire = StringUtil.toBoolean(autowire);
if(is_autowire!=null){
return !is_autowire.booleanValue();
}
else return false;
}*/
static Stmt typedValue(final Class type, final Object val, final Location loc,
final Converter converter){
return new Stmt(){
public Object run(Dict frame, Runtime runtime){
return converter.convert(type, val, loc);
}
public Class getType(){
return type;
}
public Location getLocation(){
return loc;
}
public String toString(){return ""+val;}
};
}
static Stmt value(final Object v, final Location loc){
final Class type = v==null?Object.class:v.getClass();
return new Stmt(){
public Object run(Dict frame, Runtime runtime){
return v;
}
public Class getType(){
return type;
}
public Location getLocation(){
return loc;
}
public String toString(){return ""+v;}
};
}
static ContinuationEscapeException getEscapeException(Throwable e){
for(Throwable cur = e;;){
if(cur instanceof ContinuationEscapeException){
return (ContinuationEscapeException)cur;
}
final Throwable cause = cur.getCause();
if(cause==null || cause==cur) return null;
cur = cause;
}
}
private static Component convert(final Class target_type, Component c,
final Location loc, final Converter converter){
return c.map(new jfun.yan.Map(){
public Object map(Object v){
return converter.convert(target_type, v, loc);
}
}).cast(target_type);
}
static Component cast(final Class target_type, Component c,
final Location loc, final Converter converter){
final Class type = c.getType();
if(type==null || Literal.class.isAssignableFrom(type)){
return convert(target_type, c, loc, converter);
}
else if(String.class.equals(type)){
if(target_type.isAssignableFrom(type)){
return c;
}
else{
return convert(target_type, c, loc, converter);
}
}
else return c.cast(target_type);
}
/**
* Convert a 1-element set.
* @param impltype the set implementation type.
* @param obj the only one element in the set.
* @return the set.
* @throws IllegalAccessException
* when the constructor of the implementation class is not public.
* @throws InstantiationException
* when the constructor fails.
*/
public static Set toSet(Class impltype, Object obj)
throws IllegalAccessException, InstantiationException{
final Set set = Utils.createSet(impltype, 1);
set.add(obj);
return set;
}
/**
* Convert a 1-element list.
* @param impltype the list implementation type.
* @param obj the only one element in the list.
* @return the list.
* @throws IllegalAccessException
* when the constructor of the implementation class is not public.
* @throws InstantiationException
* when the constructor fails.
*/
public static List toList(Class impltype, Object obj)
throws IllegalAccessException, InstantiationException{
final List list = Utils.createList(impltype, 1);
list.add(obj);
return list;
}
/**
* Create a 1-element array.
* @param elem_type the array element type.
* @param obj the actual element value.
* @return the array object.
*/
public static Object toArray(Class elem_type, Object obj){
final Object arr = Array.newInstance(elem_type, 1);
Array.set(arr, 0, obj);
return arr;
}
}