felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mccu...@apache.org
Subject svn commit: r1347815 [10/19] - in /felix/trunk/bundleplugin: ./ src/main/java/aQute/ src/main/java/aQute/bnd/ src/main/java/aQute/bnd/annotation/ src/main/java/aQute/bnd/annotation/component/ src/main/java/aQute/bnd/annotation/metatype/ src/main/java/a...
Date Thu, 07 Jun 2012 21:57:43 GMT
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/JSONCodec.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/JSONCodec.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/JSONCodec.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/JSONCodec.java Thu Jun  7 21:57:32
2012
@@ -0,0 +1,481 @@
+package aQute.lib.json;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.regex.*;
+
+/**
+ * This is a simple JSON Coder and Encoder that uses the Java type system to
+ * convert data objects to JSON and JSON to (type safe) Java objects. The
+ * conversion is very much driven by classes and their public fields. Generic
+ * information, when present is taken into account. </p> Usage patterns to
+ * encode:
+ * 
+ * <pre>
+ *  JSONCoder codec = new JSONCodec(); // 
+ * 	assert "1".equals( codec.enc().to().put(1).toString());
+ * 	assert "[1,2,3]".equals( codec.enc().to().put(Arrays.asList(1,2,3).toString());
+ * 
+ *  Map m = new HashMap();
+ *  m.put("a", "A");
+ * 	assert "{\"a\":\"A\"}".equals( codec.enc().to().put(m).toString());
+ * 
+ *  static class D { public int a; }
+ *  D d = new D();
+ *  d.a = 41;
+ *  assert "{\"a\":41}".equals( codec.enc().to().put(d).toString());
+ * </pre>
+ * 
+ * It is possible to redirect the encoder to another output (default is a
+ * string). See {@link Encoder#to()},{@link Encoder#to(File))},
+ * {@link Encoder#to(OutputStream)}, {@link Encoder#to(Appendable))}. To reset
+ * the string output call {@link Encoder#to()}.
+ * <p/>
+ * This Codec class can be used in a concurrent environment. The Decoders and
+ * Encoders, however, must only be used in a single thread.
+ */
+public class JSONCodec {
+	final static String								START_CHARACTERS	= "[{\"-0123456789tfn";
+
+	// Handlers
+	private final static WeakHashMap<Type, Handler>	handlers			= new WeakHashMap<Type,
Handler>();
+	private static StringHandler					sh					= new StringHandler();
+	private static BooleanHandler					bh					= new BooleanHandler();
+	private static CharacterHandler					ch					= new CharacterHandler();
+	private static CollectionHandler				dch					= new CollectionHandler(
+																				ArrayList.class,
+																				Object.class);
+	private static SpecialHandler					sph					= new SpecialHandler(
+																				Pattern.class,
+																				null, null);
+	private static DateHandler						sdh					= new DateHandler();
+	private static FileHandler						fh					= new FileHandler();
+	private static ByteArrayHandler					byteh				= new ByteArrayHandler();
+
+	/**
+	 * Create a new Encoder with the state and appropriate API.
+	 * 
+	 * @return an Encoder
+	 */
+	public Encoder enc() {
+		return new Encoder(this);
+	}
+
+	/**
+	 * Create a new Decoder with the state and appropriate API.
+	 * 
+	 * @return a Decoder
+	 */
+	public Decoder dec() {
+		return new Decoder(this);
+	}
+
+	/*
+	 * Work horse encode methods, all encoding ends up here.
+	 */
+	void encode(Encoder app, Object object, Type type, Map<Object, Type> visited) throws
Exception {
+
+		// Get the null out of the way
+
+		if (object == null) {
+			app.append("null");
+			return;
+		}
+
+		// If we have no type or the type is Object.class
+		// we take the type of the object itself. Normally types
+		// come from declaration sites (returns, fields, methods, etc)
+		// and contain generic info.
+
+		if (type == null || type == Object.class)
+			type = object.getClass();
+
+		// Dispatch to the handler who knows how to handle the given type.
+		Handler h = getHandler(type);
+		h.encode(app, object, visited);
+	}
+
+	/*
+	 * This method figures out which handler should handle the type specific
+	 * stuff. It returns a handler for each type. If no appropriate handler
+	 * exists, it will create one for the given type. There are actually quite a
+	 * lot of handlers since Java is not very object oriented.
+	 * 
+	 * @param type
+	 * 
+	 * @return
+	 * 
+	 * @throws Exception
+	 */
+	Handler getHandler(Type type) throws Exception {
+
+		// First the static hard coded handlers for the common types.
+
+		if (type == String.class)
+			return sh;
+
+		if (type == Boolean.class || type == boolean.class)
+			return bh;
+
+		if (type == byte[].class)
+			return byteh;
+
+		if (Character.class == type || char.class == type)
+			return ch;
+
+		if (Pattern.class == type)
+			return sph;
+
+		if (Date.class == type)
+			return sdh;
+
+		if (File.class == type)
+			return fh;
+
+		Handler h;
+		synchronized (handlers) {
+			h = handlers.get(type);
+		}
+
+		if (h != null)
+			return h;
+
+		if (type instanceof Class) {
+
+			Class<?> clazz = (Class<?>) type;
+
+			if (Enum.class.isAssignableFrom(clazz))
+				h = new EnumHandler(clazz);
+			else if (Collection.class.isAssignableFrom(clazz)) // A Non Generic
+																// collection
+
+				h = dch;
+			else if (clazz.isArray()) // Non generic array
+				h = new ArrayHandler(clazz, clazz.getComponentType());
+			else if (Map.class.isAssignableFrom(clazz)) // A Non Generic map
+				h = new MapHandler(clazz, Object.class, Object.class);
+			else if (Number.class.isAssignableFrom(clazz) || clazz.isPrimitive())
+				h = new NumberHandler(clazz);
+			else {
+				Method valueOf = null;
+				Constructor<?> constructor = null;
+
+				try {
+					constructor = clazz.getConstructor(String.class);
+				} catch (Exception e) {
+					// Ignore
+				}
+				try {
+					valueOf = clazz.getMethod("valueOf", String.class);
+				} catch (Exception e) {
+					// Ignore
+				}
+				if (constructor != null || valueOf != null)
+					h = new SpecialHandler(clazz, constructor, valueOf);
+				else
+					h = new ObjectHandler(this, clazz); // Hmm, might not be a
+														// data class ...
+			}
+
+		} else {
+
+			// We have generic information available
+			// We only support generics on Collection, Map, and arrays
+
+			if (type instanceof ParameterizedType) {
+				ParameterizedType pt = (ParameterizedType) type;
+				Type rawType = pt.getRawType();
+				if (rawType instanceof Class) {
+					Class<?> rawClass = (Class<?>) rawType;
+					if (Collection.class.isAssignableFrom(rawClass))
+						h = new CollectionHandler(rawClass, pt.getActualTypeArguments()[0]);
+					else if (Map.class.isAssignableFrom(rawClass))
+						h = new MapHandler(rawClass, pt.getActualTypeArguments()[0],
+								pt.getActualTypeArguments()[1]);
+					else
+						throw new IllegalArgumentException(
+								"Found a parameterized type that is not a map or collection");
+				}
+			} else if (type instanceof GenericArrayType) {
+				GenericArrayType gat = (GenericArrayType) type;
+				h = new ArrayHandler(getRawClass(type), gat.getGenericComponentType());
+			} else
+				throw new IllegalArgumentException(
+						"Found a parameterized type that is not a map or collection");
+		}
+		synchronized (handlers) {
+			// We might actually have duplicates
+			// but who cares? They should be identical
+			handlers.put(type, h);
+		}
+		return h;
+	}
+
+	Object decode(Type type, Decoder isr) throws Exception {
+		int c = isr.skipWs();
+		Handler h;
+
+		if (type == null || type == Object.class) {
+
+			// Establish default behavior when we run without
+			// type information
+
+			switch (c) {
+			case '{':
+				type = LinkedHashMap.class;
+				break;
+
+			case '[':
+				type = ArrayList.class;
+				break;
+
+			case '"':
+				return parseString(isr);
+
+			case 'n':
+				isr.expect("ull");
+				return null;
+
+			case 't':
+				isr.expect("rue");
+				return true;
+
+			case 'f':
+				isr.expect("alse");
+				return false;
+
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+			case '9':
+			case '-':
+				return parseNumber(isr);
+
+			default:
+				throw new IllegalArgumentException("Invalid character at begin of token: "
+						+ (char) c);
+			}
+		}
+
+		h = getHandler(type);
+
+		switch (c) {
+		case '{':
+			return h.decodeObject(isr);
+
+		case '[':
+			return h.decodeArray(isr);
+
+		case '"':
+			return h.decode(parseString(isr));
+
+		case 'n':
+			isr.expect("ull");
+			return h.decode();
+
+		case 't':
+			isr.expect("rue");
+			return h.decode(Boolean.TRUE);
+
+		case 'f':
+			isr.expect("alse");
+			return h.decode(Boolean.FALSE);
+
+		case '0':
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9':
+		case '-':
+			return h.decode(parseNumber(isr));
+
+		default:
+			throw new IllegalArgumentException("Unexpected character in input stream: " + (char) c);
+		}
+	}
+
+	String parseString(Decoder r) throws Exception {
+		assert r.current() == '"';
+
+		int c = r.next(); // skip first "
+
+		StringBuilder sb = new StringBuilder();
+		while (c != '"') {
+			if (c < 0 || Character.isISOControl(c))
+				throw new IllegalArgumentException(
+						"JSON strings may not contain control characters: " + r.current());
+
+			if (c == '\\') {
+				c = r.read();
+				switch (c) {
+				case '"':
+				case '\\':
+				case '/':
+					sb.append((char)c);
+					break;
+
+				case 'b':
+					sb.append('\b');
+					break;
+
+				case 'f':
+					sb.append('\f');
+					break;
+				case 'n':
+					sb.append('\n');
+					break;
+				case 'r':
+					sb.append('\r');
+					break;
+				case 't':
+					sb.append('\t');
+					break;
+				case 'u':
+					int a3 = hexDigit(r.read()) << 12;
+					int a2 = hexDigit(r.read()) << 8;
+					int a1 = hexDigit(r.read()) << 4;
+					int a0 = hexDigit(r.read()) << 0;
+					c = a3 + a2 + a1 + a0;
+					sb.append((char) c);
+					break;
+
+				default:
+					throw new IllegalArgumentException(
+							"The only characters after a backslash are \", \\, b, f, n, r, t, and u but got "
+									+ c);
+				}
+			} else
+				sb.append((char) c);
+
+			c = r.read();
+		}
+		assert c == '"';
+		r.read(); // skip quote
+		return sb.toString();
+	}
+
+	private int hexDigit(int c) throws EOFException {
+		if (c >= '0' && c <= '9')
+			return c - '0';
+
+		if (c >= 'A' && c <= 'F')
+			return c - 'A' + 10;
+
+		if (c >= 'a' && c <= 'f')
+			return c - 'a' + 10;
+
+		throw new IllegalArgumentException("Invalid hex character: " + c);
+	}
+
+	private Number parseNumber(Decoder r) throws Exception {
+		StringBuilder sb = new StringBuilder();
+		boolean d = false;
+
+		if (r.current() == '-') {
+			sb.append('-');
+			r.read();
+		}
+
+		int c = r.current();
+		if (c == '0') {
+			sb.append('0');
+			c = r.read();
+		} else if (c >= '1' && c <= '9') {
+			sb.append((char) c);
+			c = r.read();
+
+			while (c >= '0' && c <= '9') {
+				sb.append((char) c);
+				c = r.read();
+			}
+		} else
+			throw new IllegalArgumentException("Expected digit");
+
+		if (c == '.') {
+			d = true;
+			sb.append('.');
+			c = r.read();
+			while (c >= '0' && c <= '9') {
+				sb.append((char) c);
+				c = r.read();
+			}
+		}
+		if (c == 'e' || c == 'E') {
+			d = true;
+			sb.append('e');
+			c = r.read();
+			if (c == '+') {
+				sb.append('+');
+				c = r.read();
+			} else if (c == '-') {
+				sb.append('-');
+				c = r.read();
+			}
+			while (c >= '0' && c <= '9') {
+				sb.append((char) c);
+				c = r.read();
+			}
+		}
+		if (d)
+			return Double.parseDouble(sb.toString());
+		long l = Long.parseLong(sb.toString());
+		if (l > Integer.MAX_VALUE || l < Integer.MIN_VALUE)
+			return l;
+		return (int) l;
+	}
+
+	void parseArray(Collection<Object> list, Type componentType, Decoder r) throws Exception
{
+		assert r.current() == '[';
+		int c = r.next();
+		while (START_CHARACTERS.indexOf(c) >= 0) {
+			Object o = decode(componentType, r);
+			list.add(o);
+
+			c = r.skipWs();
+			if (c == ']')
+				break;
+
+			if (c == ',') {
+				c = r.next();
+				continue;
+			}
+
+			throw new IllegalArgumentException(
+					"Invalid character in parsing list, expected ] or , but found " + (char) c);
+		}
+		assert r.current() == ']';
+		r.read(); // skip closing
+	}
+
+	@SuppressWarnings("rawtypes")
+	Class<?> getRawClass(Type type) {
+		if (type instanceof Class)
+			return (Class) type;
+
+		if (type instanceof ParameterizedType)
+			return getRawClass(((ParameterizedType) type).getRawType());
+
+		if (type instanceof GenericArrayType) {
+			Type subType = ((GenericArrayType) type).getGenericComponentType();
+			Class c = getRawClass(subType);
+			return Array.newInstance(c, 0).getClass();
+		}
+
+		throw new IllegalArgumentException(
+				"Does not support generics beyond Parameterized Type  and GenericArrayType, got "
+						+ type);
+	}
+
+}
\ No newline at end of file

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/JSONCodec.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/JSONCodec.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/MapHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/MapHandler.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/MapHandler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/MapHandler.java Thu Jun  7 21:57:32
2012
@@ -0,0 +1,91 @@
+package aQute.lib.json;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+public class MapHandler extends Handler {
+	final Class<?>	rawClass;
+	final Type		keyType;
+	final Type		valueType;
+
+	MapHandler(Class<?> rawClass, Type keyType, Type valueType) {
+		this.keyType = keyType;
+		this.valueType = valueType;
+		if (rawClass.isInterface()) {
+			if (rawClass.isAssignableFrom(HashMap.class))
+				rawClass = HashMap.class;
+			else if (rawClass.isAssignableFrom(TreeMap.class))
+				rawClass = TreeMap.class;
+			else if (rawClass.isAssignableFrom(Hashtable.class))
+				rawClass = Hashtable.class;
+			else if (rawClass.isAssignableFrom(LinkedHashMap.class))
+				rawClass = LinkedHashMap.class;
+			else
+				throw new IllegalArgumentException("Unknown map interface: " + rawClass);
+		}
+		this.rawClass = rawClass;
+	}
+
+	@Override void encode(Encoder app, Object object, Map<Object, Type> visited)
+			throws IOException, Exception {
+		Map<?, ?> map = (Map<?, ?>) object;
+
+		app.append("{");
+		String del = "";
+		for (Map.Entry<?, ?> e : map.entrySet()) {
+			app.append(del);
+			String key;
+			if (e.getKey() != null && (keyType == String.class || keyType == Object.class))
+				key = e.getKey().toString();
+			else {
+				key = app.codec.enc().put(e.getKey()).toString();
+			}
+			StringHandler.string(app, key);
+			app.append(":");
+			app.encode(e.getValue(), valueType, visited);
+			del = ",";
+		}
+		app.append("}");
+	}
+
+	@SuppressWarnings("unchecked") @Override Object decodeObject(Decoder r) throws Exception
{
+		assert r.current() == '{';
+		
+		Map<Object, Object> map = (Map<Object, Object>) rawClass.newInstance();
+		
+		int c = r.next();
+		while (JSONCodec.START_CHARACTERS.indexOf(c) >= 0) {
+			Object key = r.codec.parseString(r);
+			if ( !(keyType == null || keyType == Object.class)) {
+				Handler h = r.codec.getHandler(keyType);
+				key = h.decode((String)key);
+			}
+			
+			c = r.skipWs();
+			if ( c != ':')
+				throw new IllegalArgumentException("Expected ':' but got " + (char) c);
+
+			c = r.next();
+			Object value = r.codec.decode(valueType, r);
+			map.put(key, value);
+
+			c = r.skipWs();
+			
+			if (c == '}') 
+				break;
+
+			if (c == ',') {
+				c = r.next();
+				continue;
+			}
+
+			throw new IllegalArgumentException(
+					"Invalid character in parsing list, expected } or , but found " + (char) c);
+		}
+		assert r.current() == '}';
+		r.read(); // skip closing
+		return map;
+	}
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/MapHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/MapHandler.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/NumberHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/NumberHandler.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/NumberHandler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/NumberHandler.java Thu Jun  7 21:57:32
2012
@@ -0,0 +1,71 @@
+package aQute.lib.json;
+
+import java.lang.reflect.*;
+import java.math.*;
+import java.util.*;
+
+public class NumberHandler extends Handler {
+	final Class<?>	type;
+
+	NumberHandler(Class<?> clazz) {
+		this.type = clazz;
+	}
+
+	@Override void encode(Encoder app, Object object, Map<Object, Type> visited)
+			throws Exception {
+		String s = object.toString();
+		if ( s.endsWith(".0"))
+			s  = s.substring(0,s.length()-2);
+		
+		app.append(s);
+	}
+
+	@Override Object decode(boolean s) {
+		return decode(s ? 1d : 0d);
+	}
+
+	@Override Object decode(String s) {
+		double d = Double.parseDouble(s);
+		return decode(d);
+	}
+
+	@Override Object decode() {
+		return decode(0d);
+	}
+
+	@Override Object decode(Number s) {
+		double dd = s.doubleValue();
+		
+		if (type == double.class || type == Double.class)
+			return s.doubleValue();
+
+		if ((type == int.class || type == Integer.class)
+				&& within(dd, Integer.MIN_VALUE, Integer.MAX_VALUE))
+			return s.intValue();
+
+		if ((type == long.class || type == Long.class) && within(dd, Long.MIN_VALUE, Long.MAX_VALUE))
+			return s.longValue();
+
+		if ((type == byte.class || type == Byte.class) && within(dd, Byte.MIN_VALUE, Byte.MAX_VALUE))
+			return s.byteValue();
+
+		if ((type == short.class || type == Short.class)
+				&& within(dd, Short.MIN_VALUE, Short.MAX_VALUE))
+			return s.shortValue();
+
+		if (type == float.class || type == Float.class)
+			return s.floatValue();
+
+		if (type == BigDecimal.class)
+			return BigDecimal.valueOf(dd);
+
+		if (type == BigInteger.class)
+			return BigInteger.valueOf(s.longValue());
+
+		throw new IllegalArgumentException("Unknown number format: " + type);
+	}
+
+	private boolean within(double s, double minValue, double maxValue) {
+		return s >= minValue && s <= maxValue;
+	}
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/NumberHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/NumberHandler.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ObjectHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ObjectHandler.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ObjectHandler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ObjectHandler.java Thu Jun  7 21:57:32
2012
@@ -0,0 +1,147 @@
+package aQute.lib.json;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+public class ObjectHandler extends Handler {
+	@SuppressWarnings("rawtypes")
+	final Class		rawClass;
+	final Field		fields[];
+	final Type		types[];
+	final Object	defaults[];
+	final Field		extra;
+
+	ObjectHandler(JSONCodec codec, Class<?> c) throws Exception {
+		rawClass = c;
+		fields = c.getFields();
+
+		// Sort the fields so the output is canonical
+		Arrays.sort(fields, new Comparator<Field>() {
+			public int compare(Field o1, Field o2) {
+				return o1.getName().compareTo(o2.getName());
+			}
+		});
+
+		types = new Type[fields.length];
+		defaults = new Object[fields.length];
+
+		Field x = null;
+		for (int i = 0; i < fields.length; i++) {
+			if (fields[i].getName().equals("__extra"))
+				x = fields[i];
+			types[i] = fields[i].getGenericType();
+		}
+		if (x != null && Map.class.isAssignableFrom(x.getType()))
+			extra = x;
+		else
+			extra = null;
+		
+		try {
+			Object template = c.newInstance();
+
+			for (int i = 0; i < fields.length; i++) {
+				defaults[i] = fields[i].get(template);
+			}
+		} catch (Exception e) {
+			// Ignore
+		}
+	}
+
+	@Override void encode(Encoder app, Object object, Map<Object, Type> visited) throws
Exception {
+		app.append("{");
+		String del = "";
+		for (int i = 0; i < fields.length; i++) {
+			if (fields[i].getName().startsWith("__"))
+				continue;
+
+			Object value = fields[i].get(object);
+			if (!app.writeDefaults) {
+				if (value == defaults[i])
+					continue;
+
+				if (value != null && value.equals(defaults[i]))
+					continue;
+			}
+
+			app.append(del);
+			StringHandler.string(app, fields[i].getName());
+			app.append(":");
+			app.encode(value, types[i], visited);
+			del = ",";
+		}
+		app.append("}");
+	}
+
+	@SuppressWarnings("unchecked") @Override Object decodeObject(Decoder r) throws Exception
{
+		assert r.current() == '{';
+		Object targetObject = rawClass.newInstance();
+
+		int c = r.next();
+		while (JSONCodec.START_CHARACTERS.indexOf(c) >= 0) {
+
+			// Get key
+			String key = r.codec.parseString(r);
+
+			// Get separator
+			c = r.skipWs();
+			if (c != ':')
+				throw new IllegalArgumentException("Expected ':' but got " + (char) c);
+
+			c = r.next();
+
+			// Get value
+
+			Field f = getField(key);
+			if (f != null) {
+				// We have a field and thus a type
+				Object value = r.codec.decode(f.getGenericType(), r);
+				f.set(targetObject, value);
+			} else {
+				// No field, but may extra is defined
+				if (extra == null) {
+					if (r.strict)
+						throw new IllegalArgumentException("No such field " + key);
+					Object value = r.codec.decode(null, r);
+					r.getExtra().put(rawClass.getName() + "." + key, value);
+				} else {
+
+					Map<String, Object> map = (Map<String, Object>) extra.get(targetObject);
+					if (map == null) {
+						map = new LinkedHashMap<String, Object>();
+						extra.set(targetObject, map);
+					}
+					Object value = r.codec.decode(null, r);
+					map.put(key, value);
+				}
+			}
+
+			c = r.skipWs();
+
+			if (c == '}')
+				break;
+
+			if (c == ',') {
+				c = r.next();
+				continue;
+			}
+
+			throw new IllegalArgumentException(
+					"Invalid character in parsing object, expected } or , but found " + (char) c);
+		}
+		assert r.current() == '}';
+		r.read(); // skip closing
+		return targetObject;
+	}
+
+	private Field getField(String key) {
+		for (int i = 0; i < fields.length; i++) {
+			int n = key.compareTo(fields[i].getName());
+			if (n == 0)
+				return fields[i];
+			if (n < 0)
+				return null;
+		}
+		return null;
+	}
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ObjectHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ObjectHandler.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/SpecialHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/SpecialHandler.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/SpecialHandler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/SpecialHandler.java Thu Jun  7 21:57:32
2012
@@ -0,0 +1,44 @@
+package aQute.lib.json;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.text.*;
+import java.util.*;
+import java.util.regex.*;
+
+public class SpecialHandler extends Handler {
+	@SuppressWarnings("rawtypes")
+	final Class						type;
+	final Method					valueOf;
+	final Constructor< ? >			constructor;
+	final static SimpleDateFormat	sdf	= new SimpleDateFormat();
+
+	public SpecialHandler(Class< ? > type, Constructor< ? > constructor,
+			Method valueOf) {
+		this.type = type;
+		this.constructor = constructor;
+		this.valueOf = valueOf;
+	}
+
+	@Override
+	void encode(Encoder app, Object object, Map<Object, Type> visited)
+			throws IOException, Exception {
+		StringHandler.string(app, object.toString());
+	}
+
+	@Override
+	Object decode(String s) throws Exception {
+		if (type == Pattern.class)
+			return Pattern.compile(s);
+
+		if (constructor != null)
+			return constructor.newInstance(s);
+
+		if (valueOf != null)
+			return valueOf.invoke(null, s);
+
+		throw new IllegalArgumentException("Do not know how to convert a "
+				+ type + " from a string");
+	}
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/SpecialHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/SpecialHandler.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/StringHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/StringHandler.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/StringHandler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/StringHandler.java Thu Jun  7 21:57:32
2012
@@ -0,0 +1,146 @@
+package aQute.lib.json;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+public class StringHandler extends Handler {
+
+	@Override void encode(Encoder app, Object object, Map<Object, Type> visited)
+			throws IOException {
+		string(app, object.toString());
+	}
+
+	static void string(Appendable app, String s) throws IOException {
+
+		app.append('"');
+		for (int i = 0; i < s.length(); i++) {
+			char c = s.charAt(i);
+			switch (c) {
+			case '"':
+				app.append("\\\"");
+				break;
+
+			case '\\':
+				app.append("\\\\");
+				break;
+
+			case '\b':
+				app.append("\\b");
+				break;
+
+			case '\f':
+				app.append("\\f");
+				break;
+
+			case '\n':
+				app.append("\\n");
+				break;
+
+			case '\r':
+				app.append("\\r");
+				break;
+
+			case '\t':
+				app.append("\\t");
+				break;
+
+			default:
+				if (Character.isISOControl(c)) {
+					app.append("\\u");
+					app.append("0123456789ABCDEF".charAt(0xF & (c >> 12)));
+					app.append("0123456789ABCDEF".charAt(0xF & (c >> 8)));
+					app.append("0123456789ABCDEF".charAt(0xF & (c >> 4)));
+					app.append("0123456789ABCDEF".charAt(0xF & (c >> 0)));
+				} else
+					app.append(c);
+			}
+		}
+		app.append('"');
+	}
+
+	Object decode(String s) throws Exception {
+		return s;
+	}
+
+	Object decode(Number s) {
+		return s.toString();
+	}
+
+	Object decode(boolean s) {
+		return Boolean.toString(s);
+	}
+
+	Object decode() {
+		return null;
+	}
+
+	/**
+	 * An object can be assigned to a string. This means that the stream is
+	 * interpreted as the object but stored in its complete in the string.
+	 */
+	Object decodeObject(Decoder r) throws Exception {
+		return collect(r, '}');
+	}
+
+	/**
+	 * An array can be assigned to a string. This means that the stream is
+	 * interpreted as the array but stored in its complete in the string.
+	 */
+	Object decodeArray(Decoder r) throws Exception {
+		return collect(r, ']');
+	}
+
+	/**
+	 * Gather the input until you find the the closing character making sure
+	 * that new blocks are are take care of.
+	 * <p>
+	 * This method parses the input for a complete block so that it can be
+	 * stored in a string. This allows envelopes.
+	 * 
+	 * @param isr
+	 * @param c
+	 * @return
+	 * @throws Exception
+	 */
+	private Object collect(Decoder isr, char close) throws Exception {
+		boolean instring = false;
+		int level = 1;
+		StringBuilder sb = new StringBuilder();
+
+		int c = isr.current();
+		while (c > 0 && level > 0) {
+			sb.append((char) c);
+			if (instring)
+				switch (c) {
+				case '"':
+					instring = true;
+					break;
+
+				case '[':
+				case '{':
+					level++;
+					break;
+
+				case ']':
+				case '}':
+					level--;
+					break;
+				}
+			else
+				switch (c) {
+				case '"':
+					instring = false;
+					break;
+
+				case '\\':
+					sb.append((char) isr.read());
+					break;
+				}
+
+			c = isr.read();
+		}
+		return sb.toString();
+	}
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/StringHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/StringHandler.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/packageinfo?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/packageinfo (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/packageinfo Thu Jun  7 21:57:32
2012
@@ -0,0 +1 @@
+version 2.4.0

Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/justif/Justif.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/justif/Justif.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/justif/Justif.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/justif/Justif.java Thu Jun  7 21:57:32
2012
@@ -0,0 +1,104 @@
+package aQute.lib.justif;
+
+import java.util.*;
+
+
+public class Justif {
+	int []tabs;
+	
+	public Justif(int width, int ... tabs) {
+		this.tabs = tabs;
+	}
+
+	/**
+	 * Routine to wrap a stringbuffer. Basically adds line endings but has the
+	 * following control characters:
+	 * <ul>
+	 * <li>Space at the beginnng of a line is repeated when wrapped for indent.</li>
+	 * <li>A tab will mark the current position and wrapping will return to that
+	 * position</li>
+	 * <li>A form feed in a tabbed colum will break but stay in the column</li>
+	 * </ul>
+	 * 
+	 * @param sb
+	 */
+	public void wrap(StringBuilder sb) {
+		List<Integer> indents = new ArrayList<Integer>();
+		
+		int indent = 0;
+		int linelength = 0;
+		int lastSpace = 0;
+		int r = 0;
+		boolean begin = true;
+
+		while (r < sb.length()) {
+			switch (sb.charAt(r++)) {
+			case '\n':
+				linelength = 0;
+				
+				indent = indents.isEmpty() ? 0 : indents.remove(0);
+				begin = true;
+				lastSpace = 0;
+				break;
+
+			case ' ':
+				if (begin)
+					indent++;
+				lastSpace = r - 1;
+				linelength++;
+				break;
+
+			case '\t':
+				indents.add(indent);
+				indent = linelength;
+				sb.deleteCharAt(--r);
+				
+				if (r < sb.length()) {
+					char digit = sb.charAt(r);
+					if (Character.isDigit(digit)) {
+						sb.deleteCharAt(r--);
+
+						int column = (digit - '0');
+						if (column < tabs.length)
+							indent = tabs[column];
+						else
+							indent = column * 8;
+
+						int diff = indent - linelength;
+						if (diff > 0) {
+							for (int i=0; i<diff; i++) {
+								sb.insert(r, ' ');
+							}
+							r += diff;
+							linelength += diff;
+						}
+					}
+				}
+				break;
+
+			case '\f':
+				linelength = 100000; // force a break
+				lastSpace = r-1;
+
+				//$FALL-THROUGH$
+
+			default:
+				linelength++;
+				begin = false;
+				if (lastSpace != 0 && linelength > 60) {
+					sb.setCharAt(lastSpace, '\n');
+					linelength = 0;
+
+					for (int i = 0; i < indent; i++) {
+						sb.insert(lastSpace + 1, ' ');
+						linelength++;
+					}
+					r += indent;
+					lastSpace = 0;
+				}
+			}
+		}
+	}
+
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/justif/Justif.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/justif/Justif.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/justif/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/justif/packageinfo?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/justif/packageinfo (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/justif/packageinfo Thu Jun  7 21:57:32
2012
@@ -0,0 +1 @@
+version 1.0.0

Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/About.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/About.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/About.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/About.java Thu Jun  7 21:57:32 2012
@@ -0,0 +1,51 @@
+package aQute.lib.osgi;
+
+import aQute.libg.header.*;
+
+/**
+ * This package contains a number of classes that assists by analyzing JARs and
+ * constructing bundles.
+ * 
+ * The Analyzer class can be used to analyze an existing bundle and can create a
+ * manifest specification from proposed (wildcard) Export-Package,
+ * Bundle-Includes, and Import-Package headers.
+ * 
+ * The Builder class can use the headers to construct a JAR from the classpath.
+ * 
+ * The Verifier class can take an existing JAR and verify that all headers are
+ * correctly set. It will verify the syntax of the headers, match it against the
+ * proper contents, and verify imports and exports.
+ * 
+ * A number of utility classes are available.
+ * 
+ * Jar, provides an abstraction of a Jar file. It has constructors for creating
+ * a Jar from a stream, a directory, or a jar file. A Jar, keeps a collection
+ * Resource's. There are Resource implementations for File, from ZipFile, or
+ * from a stream (which copies the data). The Jar tries to minimize the work
+ * during build up so that it is cheap to use. The Resource's can be used to
+ * iterate over the names and later read the resources when needed.
+ * 
+ * Clazz, provides a parser for the class files. This will be used to define the
+ * imports and exports.
+ * 
+ * Headers are translated to {@link Parameters} that contains all headers (the
+ * order is maintained). The attribute of each header are maintained in an
+ * {@link Attrs}. Each additional file in a header definition will have its own
+ * entry (only native code does not work this way). The ':' of directives is
+ * considered part of the name. This allows attributes and directives to be
+ * maintained in the Attributes map.
+ * 
+ * An important aspect of the specification is to allow the use of wildcards.
+ * Wildcards select from a set and can decorate the entries with new attributes.
+ * This functionality is implemented in Instructions.
+ * 
+ * Much of the information calculated is in packages. A package is identified
+ * by a PackageRef (and a type by a TypeRef). The namespace is maintained
+ * by {@link Descriptors}, which here is owned by {@link Analyzer}. A special
+ * class, {@link Packages} maintains the attributes that are found in the code.
+ * 
+ * @version $Revision$
+ */
+public class About {
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/About.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/About.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/About.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/AbstractResource.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/AbstractResource.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/AbstractResource.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/AbstractResource.java Thu Jun  7
21:57:32 2012
@@ -0,0 +1,54 @@
+package aQute.lib.osgi;
+
+import java.io.*;
+
+public abstract class AbstractResource implements Resource {
+    String extra;
+    byte[] calculated;
+    long   lastModified;
+
+    protected AbstractResource(long modified) {
+        lastModified = modified;
+    }
+
+    public String getExtra() {
+        return extra;
+    }
+
+    public long lastModified() {
+        return lastModified;
+    }
+
+    public InputStream openInputStream() throws IOException {
+        return new ByteArrayInputStream(getLocalBytes());
+    }
+
+    private byte[] getLocalBytes() throws IOException {
+        try {
+            if (calculated != null)
+                return calculated;
+
+            return calculated = getBytes();
+        } catch (IOException e) {
+            throw e;
+        } catch (Exception e) {
+            IOException ee = new IOException("Opening resource");
+            ee.initCause(e);
+            throw ee;
+        }
+    }
+
+    public void setExtra(String extra) {
+        this.extra = extra;
+    }
+
+    public void write(OutputStream out) throws IOException {
+        out.write(getLocalBytes());
+    }
+
+    abstract protected byte[] getBytes() throws Exception;
+    
+    public long size() throws IOException {
+    	return getLocalBytes().length;
+    }
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/AbstractResource.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/AbstractResource.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision



Mime
View raw message