| 1 | |
package org.webslinger.resolver; |
| 2 | |
|
| 3 | |
import java.util.HashMap; |
| 4 | |
import java.util.HashSet; |
| 5 | |
import java.util.Iterator; |
| 6 | |
import java.util.ListIterator; |
| 7 | |
import java.util.Map; |
| 8 | |
import java.util.Set; |
| 9 | |
import java.util.WeakHashMap; |
| 10 | |
import java.util.concurrent.ConcurrentHashMap; |
| 11 | |
import javax.imageio.spi.ServiceRegistry; |
| 12 | |
|
| 13 | |
public final class ObjectWalker { |
| 14 | 1 | private final ConcurrentHashMap<String, ObjectResolver<?>> registry = new ConcurrentHashMap<String, ObjectResolver<?>>(); |
| 15 | |
|
| 16 | 1 | public ObjectWalker() { |
| 17 | 1 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); |
| 18 | 1 | if (loader == null) loader = ObjectWalker.class.getClassLoader(); |
| 19 | 1 | Iterator<ObjectResolverInfo> it = ServiceRegistry.lookupProviders(ObjectResolverInfo.class, loader); |
| 20 | 36 | while (it.hasNext()) { |
| 21 | |
try { |
| 22 | 35 | ObjectResolverInfo info = it.next(); |
| 23 | 35 | register(info.getType(), info.getResolver()); |
| 24 | 0 | } catch (RuntimeException e) { |
| 25 | 0 | } catch (UnsupportedClassVersionError e) { |
| 26 | 35 | } |
| 27 | |
} |
| 28 | 1 | } |
| 29 | |
|
| 30 | |
public void register(String name, ObjectResolver<?> resolver) { |
| 31 | 35 | registry.put(name, resolver); |
| 32 | 35 | } |
| 33 | |
|
| 34 | |
public Object get(Object object, ListIterator<String> it) { |
| 35 | 0 | return get(object, it, false); |
| 36 | |
} |
| 37 | |
|
| 38 | |
private Object get(Object object, ListIterator<String> it, boolean leaveEnding) { |
| 39 | 0 | while (object != null && it.hasNext()) { |
| 40 | 0 | String token = it.next(); |
| 41 | 0 | if (!it.hasNext() && leaveEnding) { |
| 42 | 0 | it.previous(); |
| 43 | 0 | return object; |
| 44 | |
} |
| 45 | |
Object newObject; |
| 46 | 0 | if (object instanceof ObjectLookup) { |
| 47 | 0 | ObjectLookup lookup = (ObjectLookup) object; |
| 48 | 0 | newObject = lookup.objectGet(token); |
| 49 | 0 | } else { |
| 50 | 0 | newObject = doGet(object.getClass(), object, token); |
| 51 | |
} |
| 52 | 0 | if (newObject == null) { |
| 53 | 0 | it.previous(); |
| 54 | 0 | return object; |
| 55 | |
} |
| 56 | 0 | object = newObject; |
| 57 | 0 | } |
| 58 | 0 | return object; |
| 59 | |
} |
| 60 | |
|
| 61 | |
private <T> Object doGet(Class<T> type, Object object, String part) { |
| 62 | 0 | ObjectResolver<T> resolver = getResolver(type); |
| 63 | 0 | if (resolver == null) return null; |
| 64 | 0 | return resolver.get(type.cast(object), part); |
| 65 | |
} |
| 66 | |
|
| 67 | |
public String[] list(Object object, ListIterator<String> it) { |
| 68 | 0 | object = get(object, it); |
| 69 | 0 | if (object == null || it.hasNext()) return null; |
| 70 | 0 | if (object instanceof ObjectLookup) { |
| 71 | 0 | return ((ObjectLookup) object).objectList(); |
| 72 | |
} |
| 73 | 0 | return doList(object.getClass(), object); |
| 74 | |
} |
| 75 | |
|
| 76 | |
private <T> String[] doList(Class<T> type, Object object) { |
| 77 | 0 | ObjectResolver<T> resolver = getResolver(type); |
| 78 | 0 | return resolver.list(type.cast(object)); |
| 79 | |
} |
| 80 | |
|
| 81 | |
public boolean hasChildren(Object object, ListIterator<String> it) { |
| 82 | 0 | object = get(object, it); |
| 83 | 0 | if (object == null || it.hasNext()) return false; |
| 84 | 0 | if (object instanceof ObjectLookup) { |
| 85 | 0 | return ((ObjectLookup) object).objectHasChildren(); |
| 86 | |
} |
| 87 | 0 | return doHasChildren(object.getClass(), object); |
| 88 | |
} |
| 89 | |
|
| 90 | |
private <T> boolean doHasChildren(Class<T> type, Object object) { |
| 91 | 0 | ObjectResolver<T> resolver = getResolver(type); |
| 92 | 0 | return resolver.hasChildren(type.cast(object)); |
| 93 | |
} |
| 94 | |
|
| 95 | |
public ObjectResolver<?> getResolver(String name) { |
| 96 | 0 | return registry.get(name); |
| 97 | |
} |
| 98 | |
|
| 99 | |
public <T> ObjectResolver<T> getResolver(Class<T> clz) { |
| 100 | 897 | return getResolver(clz, null); |
| 101 | |
} |
| 102 | |
|
| 103 | |
public Class getType(Object object, ListIterator<String> it) { |
| 104 | 0 | object = get(object, it, true); |
| 105 | 0 | if (object == null || !it.hasNext()) return Void.TYPE; |
| 106 | 0 | String part = it.next(); |
| 107 | 0 | if (it.hasNext()) return Void.TYPE; |
| 108 | 0 | if (object instanceof ObjectLookup) { |
| 109 | 0 | return ((ObjectLookup) object).getType(part); |
| 110 | |
} |
| 111 | 0 | return doGetType(object.getClass(), object, part); |
| 112 | |
} |
| 113 | |
|
| 114 | |
private <T> Class doGetType(Class<T> type, Object object, String part) { |
| 115 | 0 | ObjectResolver<T> resolver = getResolver(type); |
| 116 | 0 | return resolver.getType(type.cast(object), part); |
| 117 | |
} |
| 118 | |
|
| 119 | |
public char[] getChars(Object object, ListIterator<String> it) throws Exception { |
| 120 | 0 | object = get(object, it, false); |
| 121 | 0 | if (object == null || it.hasNext()) return null; |
| 122 | |
|
| 123 | |
|
| 124 | |
|
| 125 | 0 | return getChars(object); |
| 126 | |
} |
| 127 | |
|
| 128 | |
public char[] getChars(Object object) throws Exception { |
| 129 | 0 | return doGetChars(object.getClass(), object); |
| 130 | |
} |
| 131 | |
|
| 132 | |
private <T> char[] doGetChars(Class<T> type, Object object) throws Exception { |
| 133 | 0 | ObjectResolver<T> resolver = getResolver(type); |
| 134 | 0 | if (resolver == null) return null; |
| 135 | 0 | return resolver.getChars(type.cast(object)); |
| 136 | |
} |
| 137 | |
|
| 138 | |
public void setChars(Object object, ListIterator<String> it, char[] chars) throws Exception { |
| 139 | 0 | setChars(object, it, chars, 0, chars.length); |
| 140 | 0 | } |
| 141 | |
|
| 142 | |
public void setChars(Object object, ListIterator<String> it, char[] chars, int offset, int length) throws Exception { |
| 143 | 0 | object = get(object, it, true); |
| 144 | 0 | if (object == null || !it.hasNext()) return; |
| 145 | 0 | String part = it.next(); |
| 146 | 0 | if (it.hasNext()) return; |
| 147 | |
|
| 148 | |
|
| 149 | |
|
| 150 | 0 | doSetChars(object.getClass(), object, part, chars, offset, length); |
| 151 | 0 | } |
| 152 | |
|
| 153 | |
private <T, P> void doSetChars(Class<T> type, Object object, String part, char[] chars, int offset, int length) throws Exception { |
| 154 | 0 | ObjectResolver<T> resolver = getResolver(type); |
| 155 | 0 | Class<P> partType = resolver.getType(type.cast(object), part); |
| 156 | 0 | ObjectResolver<P> typeResolver = getResolver(partType); |
| 157 | 0 | if (typeResolver == null) return; |
| 158 | 0 | Object value = typeResolver.newObject(partType, chars, offset, length); |
| 159 | 0 | resolver.set(type.cast(object), part, value); |
| 160 | 0 | } |
| 161 | |
|
| 162 | |
public Object getObject(String type, char[] chars) throws Exception { |
| 163 | 0 | return getObject(type, chars, 0, chars.length); |
| 164 | |
} |
| 165 | |
|
| 166 | |
public Object getObject(String type, char[] chars, int offset, int length) throws Exception { |
| 167 | 1 | return getObject(Class.forName(type), chars, offset, length); |
| 168 | |
} |
| 169 | |
|
| 170 | |
public Object getObject(Class<?> type, char[] chars) throws Exception { |
| 171 | 0 | return getObject(type, chars, 0, chars.length); |
| 172 | |
} |
| 173 | |
|
| 174 | |
public <T> Object getObject(Class<T> type, char[] chars, int offset, int length) throws Exception { |
| 175 | 839 | ObjectResolver<T> typeResolver = getResolver(type); |
| 176 | 839 | if (typeResolver == null) return null; |
| 177 | 839 | return typeResolver.newObject(type, chars, offset, length); |
| 178 | |
} |
| 179 | |
|
| 180 | |
private <T> ArrayResolver<T> getArrayResolver(Class<T> componentType) { |
| 181 | 0 | return new ArrayResolver<T>(componentType); |
| 182 | |
} |
| 183 | |
|
| 184 | |
private <T> ObjectResolver<T> getResolver(Class<T> clz, Set<Class> seen) { |
| 185 | 913 | if (clz == null || clz.equals(Object.class)) return null; |
| 186 | 910 | if (seen == null) seen = new HashSet<Class>(); |
| 187 | 910 | ObjectResolver resolver = registry.get(clz.getName()); |
| 188 | 910 | if (clz.isArray()) { |
| 189 | 0 | resolver = getArrayResolver(clz.getComponentType()); |
| 190 | |
} else { |
| 191 | 910 | if (resolver == null) { |
| 192 | 13 | seen.add(clz); |
| 193 | 16 | for (Class<?> intf: clz.getInterfaces()) { |
| 194 | 4 | resolver = getResolver(intf, seen); |
| 195 | 4 | if (resolver != null) break; |
| 196 | |
} |
| 197 | 13 | if (resolver == null) resolver = getResolver(clz.getSuperclass(), seen); |
| 198 | |
} |
| 199 | |
} |
| 200 | 910 | return resolver; |
| 201 | |
} |
| 202 | |
} |