You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by mc...@apache.org on 2012/06/07 23:57:43 UTC
svn commit: r1347815 [9/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/aQ...
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,333 @@
+package aQute.lib.deployer;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+import java.util.regex.*;
+
+import aQute.bnd.service.*;
+import aQute.lib.io.*;
+import aQute.lib.osgi.*;
+import aQute.libg.header.*;
+import aQute.libg.reporter.*;
+import aQute.libg.version.*;
+
+public class FileRepo implements Plugin, RepositoryPlugin, Refreshable, RegistryPlugin {
+ public final static String LOCATION = "location";
+ public final static String READONLY = "readonly";
+ public final static String NAME = "name";
+
+ File[] EMPTY_FILES = new File[0];
+ protected File root;
+ Registry registry;
+ boolean canWrite = true;
+ Pattern REPO_FILE = Pattern
+ .compile("([-a-zA-z0-9_\\.]+)-([0-9\\.]+|latest)\\.(jar|lib)");
+ Reporter reporter;
+ boolean dirty;
+ String name;
+
+ public FileRepo() {
+ }
+
+ public FileRepo(String name, File location, boolean canWrite) {
+ this.name = name;
+ this.root = location;
+ this.canWrite = canWrite;
+ }
+
+ protected void init() throws Exception {
+ // for extensions
+ }
+
+ public void setProperties(Map<String, String> map) {
+ String location = map.get(LOCATION);
+ if (location == null)
+ throw new IllegalArgumentException("Location must be set on a FileRepo plugin");
+
+ root = new File(location);
+ if (!root.isDirectory())
+ throw new IllegalArgumentException("Repository is not a valid directory " + root);
+
+ String readonly = map.get(READONLY);
+ if (readonly != null && Boolean.valueOf(readonly).booleanValue())
+ canWrite = false;
+
+ name = map.get(NAME);
+ }
+
+ /**
+ * Get a list of URLs to bundles that are constrained by the bsn and
+ * versionRange.
+ */
+ public File[] get(String bsn, String versionRange) throws Exception {
+ init();
+
+ // If the version is set to project, we assume it is not
+ // for us. A project repo will then get it.
+ if (versionRange != null && versionRange.equals("project"))
+ return null;
+
+ //
+ // Check if the entry exists
+ //
+ File f = new File(root, bsn);
+ if (!f.isDirectory())
+ return null;
+
+ //
+ // The version range we are looking for can
+ // be null (for all) or a version range.
+ //
+ VersionRange range;
+ if (versionRange == null || versionRange.equals("latest")) {
+ range = new VersionRange("0");
+ } else
+ range = new VersionRange(versionRange);
+
+ //
+ // Iterator over all the versions for this BSN.
+ // Create a sorted map over the version as key
+ // and the file as URL as value. Only versions
+ // that match the desired range are included in
+ // this list.
+ //
+ File instances[] = f.listFiles();
+ SortedMap<Version, File> versions = new TreeMap<Version, File>();
+ for (int i = 0; i < instances.length; i++) {
+ Matcher m = REPO_FILE.matcher(instances[i].getName());
+ if (m.matches() && m.group(1).equals(bsn)) {
+ String versionString = m.group(2);
+ Version version;
+ if (versionString.equals("latest"))
+ version = new Version(Integer.MAX_VALUE);
+ else
+ version = new Version(versionString);
+
+ if (range.includes(version) || versionString.equals(versionRange))
+ versions.put(version, instances[i]);
+ }
+ }
+
+ File[] files = versions.values().toArray(EMPTY_FILES);
+ if ("latest".equals(versionRange) && files.length > 0) {
+ return new File[] { files[files.length - 1] };
+ }
+ return files;
+ }
+
+ public boolean canWrite() {
+ return canWrite;
+ }
+
+ public File put(Jar jar) throws Exception {
+ init();
+ dirty = true;
+
+ Manifest manifest = jar.getManifest();
+ if (manifest == null)
+ throw new IllegalArgumentException("No manifest in JAR: " + jar);
+
+ String bsn = manifest.getMainAttributes().getValue(Analyzer.BUNDLE_SYMBOLICNAME);
+ if (bsn == null)
+ throw new IllegalArgumentException("No Bundle SymbolicName set");
+
+ Parameters b = Processor.parseHeader(bsn, null);
+ if (b.size() != 1)
+ throw new IllegalArgumentException("Multiple bsn's specified " + b);
+
+ for (String key : b.keySet()) {
+ bsn = key;
+ if (!Verifier.SYMBOLICNAME.matcher(bsn).matches())
+ throw new IllegalArgumentException("Bundle SymbolicName has wrong format: " + bsn);
+ }
+
+ String versionString = manifest.getMainAttributes().getValue(Analyzer.BUNDLE_VERSION);
+ Version version;
+ if (versionString == null)
+ version = new Version();
+ else
+ version = new Version(versionString);
+
+ reporter.trace("bsn=%s version=%s",bsn,version);
+
+ File dir = new File(root, bsn);
+ dir.mkdirs();
+ String fName = bsn + "-" + version.getWithoutQualifier() + ".jar";
+ File file = new File(dir, fName);
+
+ reporter.trace("updating %s ", file.getAbsolutePath());
+ if (!file.exists() || file.lastModified() < jar.lastModified()) {
+ jar.write(file);
+ reporter.progress("updated " + file.getAbsolutePath());
+ fireBundleAdded(jar, file);
+ } else {
+ reporter.progress("Did not update " + jar + " because repo has a newer version");
+ reporter.trace("NOT Updating " + fName + " (repo is newer)");
+ }
+
+ File latest = new File(dir, bsn + "-latest.jar");
+ if (latest.exists() && latest.lastModified() < jar.lastModified()) {
+ jar.write(latest);
+ file = latest;
+ }
+
+ return file;
+ }
+
+ protected void fireBundleAdded(Jar jar, File file) {
+ if (registry == null)
+ return;
+ List<RepositoryListenerPlugin> listeners = registry
+ .getPlugins(RepositoryListenerPlugin.class);
+ for (RepositoryListenerPlugin listener : listeners) {
+ try {
+ listener.bundleAdded(this, jar, file);
+ } catch (Exception e) {
+ if (reporter != null)
+ reporter.warning("Repository listener threw an unexpected exception: %s", e);
+ }
+ }
+ }
+
+ public void setLocation(String string) {
+ root = new File(string);
+ if (!root.isDirectory())
+ throw new IllegalArgumentException("Invalid repository directory");
+ }
+
+ public void setReporter(Reporter reporter) {
+ this.reporter = reporter;
+ }
+
+ public List<String> list(String regex) throws Exception {
+ init();
+ Instruction pattern = null;
+ if (regex != null)
+ pattern = new Instruction(regex);
+
+ List<String> result = new ArrayList<String>();
+ if (root == null) {
+ if (reporter != null)
+ reporter.error("FileRepo root directory is not set.");
+ } else {
+ File[] list = root.listFiles();
+ if (list != null) {
+ for (File f : list) {
+ if (!f.isDirectory())
+ continue; // ignore non-directories
+ String fileName = f.getName();
+ if (fileName.charAt(0) == '.')
+ continue; // ignore hidden files
+ if (pattern == null || pattern.matches(fileName))
+ result.add(fileName);
+ }
+ } else if (reporter != null)
+ reporter.error("FileRepo root directory (%s) does not exist", root);
+ }
+
+ return result;
+ }
+
+ public List<Version> versions(String bsn) throws Exception {
+ init();
+ File dir = new File(root, bsn);
+ if (dir.isDirectory()) {
+ String versions[] = dir.list();
+ List<Version> list = new ArrayList<Version>();
+ for (String v : versions) {
+ Matcher m = REPO_FILE.matcher(v);
+ if (m.matches()) {
+ String version = m.group(2);
+ if (version.equals("latest"))
+ version = Integer.MAX_VALUE + "";
+ list.add(new Version(version));
+ }
+ }
+ return list;
+ }
+ return null;
+ }
+
+ public String toString() {
+ return String.format("%-40s r/w=%s", root.getAbsolutePath(), canWrite());
+ }
+
+ public File getRoot() {
+ return root;
+ }
+
+ public boolean refresh() {
+ if (dirty) {
+ dirty = false;
+ return true;
+ } else
+ return false;
+ }
+
+ public String getName() {
+ if (name == null) {
+ return toString();
+ }
+ return name;
+ }
+
+ public Jar get(String bsn, Version v) throws Exception {
+ init();
+ File bsns = new File(root, bsn);
+ File version = new File(bsns, bsn + "-" + v.getMajor() + "." + v.getMinor() + "."
+ + v.getMicro() + ".jar");
+ if ( version.exists())
+ return new Jar(version);
+ else
+ return null;
+ }
+
+ public File get(String bsn, String version, Strategy strategy, Map<String, String> properties)
+ throws Exception {
+ if (version == null)
+ version = "0.0.0";
+
+ if (strategy == Strategy.EXACT) {
+ VersionRange vr = new VersionRange(version);
+ if (vr.isRange())
+ return null;
+
+ if (vr.getHigh().getMajor() == Integer.MAX_VALUE)
+ version = "latest";
+
+ File file = IO.getFile(root, bsn + "/" + bsn + "-" + version + ".jar");
+ if (file.isFile())
+ return file;
+ else {
+ file = IO.getFile(root, bsn + "/" + bsn + "-" + version + ".lib");
+ if (file.isFile())
+ return file;
+ }
+ return null;
+
+ }
+ File[] files = get(bsn, version);
+ if (files == null || files.length == 0)
+ return null;
+
+ if (files.length >= 0) {
+ switch (strategy) {
+ case LOWEST:
+ return files[0];
+ case HIGHEST:
+ return files[files.length - 1];
+ }
+ }
+ return null;
+ }
+
+ public void setRegistry(Registry registry) {
+ this.registry = registry;
+ }
+
+ public String getLocation() {
+ return root.toString();
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/Filter.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/Filter.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/Filter.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/Filter.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,343 @@
+/**
+ * Copyright (c) 2000 Gatespace AB. All Rights Reserved.
+ *
+ * Gatespace grants Open Services Gateway Initiative (OSGi) an irrevocable,
+ * perpetual, non-exclusive, worldwide, paid-up right and license to
+ * reproduce, display, perform, prepare and have prepared derivative works
+ * based upon and distribute and sublicense this material and derivative
+ * works thereof as set out in the OSGi MEMBER AGREEMENT as of January 24
+ * 2000, for use in accordance with Section 2.2 of the BY-LAWS of the
+ * OSGi MEMBER AGREEMENT.
+ */
+
+package aQute.lib.filter;
+
+import java.lang.reflect.*;
+import java.math.*;
+import java.util.*;
+
+public class Filter {
+ final char WILDCARD = 65535;
+
+ final static int EQ = 0;
+ final static int LE = 1;
+ final static int GE = 2;
+ final static int APPROX = 3;
+
+ private String filter;
+
+ abstract class Query {
+ static final String GARBAGE = "Trailing garbage";
+ static final String MALFORMED = "Malformed query";
+ static final String EMPTY = "Empty list";
+ static final String SUBEXPR = "No subexpression";
+ static final String OPERATOR = "Undefined operator";
+ static final String TRUNCATED = "Truncated expression";
+ static final String EQUALITY = "Only equality supported";
+
+ private String tail;
+
+ boolean match() throws IllegalArgumentException {
+ tail = filter;
+ boolean val = doQuery();
+ if (tail.length() > 0)
+ error(GARBAGE);
+ return val;
+ }
+
+ private boolean doQuery() throws IllegalArgumentException {
+ if (tail.length() < 3 || !prefix("("))
+ error(MALFORMED);
+ boolean val;
+
+ switch (tail.charAt(0)) {
+ case '&':
+ val = doAnd();
+ break;
+ case '|':
+ val = doOr();
+ break;
+ case '!':
+ val = doNot();
+ break;
+ default:
+ val = doSimple();
+ break;
+ }
+
+ if (!prefix(")"))
+ error(MALFORMED);
+ return val;
+ }
+
+ private boolean doAnd() throws IllegalArgumentException {
+ tail = tail.substring(1);
+ boolean val = true;
+ if (!tail.startsWith("("))
+ error(EMPTY);
+ do {
+ if (!doQuery())
+ val = false;
+ } while (tail.startsWith("("));
+ return val;
+ }
+
+ private boolean doOr() throws IllegalArgumentException {
+ tail = tail.substring(1);
+ boolean val = false;
+ if (!tail.startsWith("("))
+ error(EMPTY);
+ do {
+ if (doQuery())
+ val = true;
+ } while (tail.startsWith("("));
+ return val;
+ }
+
+ private boolean doNot() throws IllegalArgumentException {
+ tail = tail.substring(1);
+ if (!tail.startsWith("("))
+ error(SUBEXPR);
+ return !doQuery();
+ }
+
+ private boolean doSimple() throws IllegalArgumentException {
+ int op = 0;
+ Object attr = getAttr();
+
+ if (prefix("="))
+ op = EQ;
+ else if (prefix("<="))
+ op = LE;
+ else if (prefix(">="))
+ op = GE;
+ else if (prefix("~="))
+ op = APPROX;
+ else
+ error(OPERATOR);
+
+ return compare(attr, op, getValue());
+ }
+
+ private boolean prefix(String pre) {
+ if (!tail.startsWith(pre))
+ return false;
+ tail = tail.substring(pre.length());
+ return true;
+ }
+
+ private Object getAttr() {
+ int len = tail.length();
+ int ix = 0;
+ label: for (; ix < len; ix++) {
+ switch (tail.charAt(ix)) {
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '=':
+ case '~':
+ case '*':
+ case '\\':
+ break label;
+ }
+ }
+ String attr = tail.substring(0, ix).toLowerCase();
+ tail = tail.substring(ix);
+ return getProp(attr);
+ }
+
+ abstract Object getProp(String key);
+
+ private String getValue() {
+ StringBuilder sb = new StringBuilder();
+ int len = tail.length();
+ int ix = 0;
+ label: for (; ix < len; ix++) {
+ char c = tail.charAt(ix);
+ switch (c) {
+ case '(':
+ case ')':
+ break label;
+ case '*':
+ sb.append(WILDCARD);
+ break;
+ case '\\':
+ if (ix == len - 1)
+ break label;
+ sb.append(tail.charAt(++ix));
+ break;
+ default:
+ sb.append(c);
+ break;
+ }
+ }
+ tail = tail.substring(ix);
+ return sb.toString();
+ }
+
+ private void error(String m) throws IllegalArgumentException {
+ throw new IllegalArgumentException(m + " " + tail);
+ }
+
+ private boolean compare(Object obj, int op, String s) {
+ if (obj == null)
+ return false;
+ try {
+ Class<?> numClass = obj.getClass();
+ if (numClass == String.class) {
+ return compareString((String) obj, op, s);
+ } else if (numClass == Character.class) {
+ return compareString(obj.toString(), op, s);
+ } else if (numClass == Long.class) {
+ return compareSign(op, Long.valueOf(s).compareTo((Long) obj));
+ } else if (numClass == Integer.class) {
+ return compareSign(op, Integer.valueOf(s).compareTo((Integer) obj));
+ } else if (numClass == Short.class) {
+ return compareSign(op, Short.valueOf(s).compareTo((Short) obj));
+ } else if (numClass == Byte.class) {
+ return compareSign(op, Byte.valueOf(s).compareTo((Byte) obj));
+ } else if (numClass == Double.class) {
+ return compareSign(op, Double.valueOf(s).compareTo((Double) obj));
+ } else if (numClass == Float.class) {
+ return compareSign(op, Float.valueOf(s).compareTo((Float) obj));
+ } else if (numClass == Boolean.class) {
+ if (op != EQ)
+ return false;
+ int a = Boolean.valueOf(s).booleanValue() ? 1 : 0;
+ int b = ((Boolean) obj).booleanValue() ? 1 : 0;
+ return compareSign(op, a - b);
+ } else if (numClass == BigInteger.class) {
+ return compareSign(op, new BigInteger(s).compareTo((BigInteger) obj));
+ } else if (numClass == BigDecimal.class) {
+ return compareSign(op, new BigDecimal(s).compareTo((BigDecimal) obj));
+ } else if (obj instanceof Collection<?>) {
+ for (Object x : (Collection<?>) obj)
+ if (compare(x, op, s))
+ return true;
+ } else if (numClass.isArray()) {
+ int len = Array.getLength(obj);
+ for (int i = 0; i < len; i++)
+ if (compare(Array.get(obj, i), op, s))
+ return true;
+ }
+ } catch (Exception e) {
+ }
+ return false;
+ }
+ }
+
+ class DictQuery extends Query {
+ private Dictionary<?, ?> dict;
+
+ DictQuery(Dictionary<?, ?> dict) {
+ this.dict = dict;
+ }
+
+ Object getProp(String key) {
+ return dict.get(key);
+ }
+ }
+
+ public Filter(String filter) throws IllegalArgumentException {
+ // NYI: Normalize the filter string?
+ this.filter = filter;
+ if (filter == null || filter.length() == 0)
+ throw new IllegalArgumentException("Null query");
+ }
+
+ public boolean match(Dictionary<?, ?> dict) {
+ try {
+ return new DictQuery(dict).match();
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+
+ public String verify() {
+ try {
+ new DictQuery(new Hashtable<Object, Object>()).match();
+ } catch (IllegalArgumentException e) {
+ return e.getMessage();
+ }
+ return null;
+ }
+
+ public String toString() {
+ return filter;
+ }
+
+ public boolean equals(Object obj) {
+ return obj != null && obj instanceof Filter && filter.equals(((Filter) obj).filter);
+ }
+
+ public int hashCode() {
+ return filter.hashCode();
+ }
+
+ boolean compareString(String s1, int op, String s2) {
+ switch (op) {
+ case EQ:
+ return patSubstr(s1, s2);
+ case APPROX:
+ return fixupString(s2).equals(fixupString(s1));
+ default:
+ return compareSign(op, s2.compareTo(s1));
+ }
+ }
+
+ boolean compareSign(int op, int cmp) {
+ switch (op) {
+ case LE:
+ return cmp >= 0;
+ case GE:
+ return cmp <= 0;
+ case EQ:
+ return cmp == 0;
+ default: /* APPROX */
+ return cmp == 0;
+ }
+ }
+
+ String fixupString(String s) {
+ StringBuilder sb = new StringBuilder();
+ int len = s.length();
+ boolean isStart = true;
+ boolean isWhite = false;
+ for (int i = 0; i < len; i++) {
+ char c = s.charAt(i);
+ if (Character.isWhitespace(c)) {
+ isWhite = true;
+ } else {
+ if (!isStart && isWhite)
+ sb.append(' ');
+ if (Character.isUpperCase(c))
+ c = Character.toLowerCase(c);
+ sb.append(c);
+ isStart = false;
+ isWhite = false;
+ }
+ }
+ return sb.toString();
+ }
+
+ boolean patSubstr(String s, String pat) {
+ if (s == null)
+ return false;
+ if (pat.length() == 0)
+ return s.length() == 0;
+ if (pat.charAt(0) == WILDCARD) {
+ pat = pat.substring(1);
+ for (;;) {
+ if (patSubstr(s, pat))
+ return true;
+ if (s.length() == 0)
+ return false;
+ s = s.substring(1);
+ }
+ }
+ if (s.length() == 0 || s.charAt(0) != pat.charAt(0))
+ return false;
+ return patSubstr(s.substring(1), pat.substring(1));
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/Filter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/Filter.java
------------------------------------------------------------------------------
svn:executable = *
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/Filter.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/packageinfo?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/packageinfo (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/packageinfo Thu Jun 7 21:57:32 2012
@@ -0,0 +1 @@
+version 1.0
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Arguments.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Arguments.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Arguments.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Arguments.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,8 @@
+package aQute.lib.getopt;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Arguments {
+ String[] arg();
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Arguments.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Arguments.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/CommandLine.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/CommandLine.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/CommandLine.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/CommandLine.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,472 @@
+package aQute.lib.getopt;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.regex.*;
+
+import aQute.configurable.*;
+import aQute.lib.justif.*;
+import aQute.libg.generics.*;
+import aQute.libg.reporter.*;
+
+/**
+ * Helps parsing command lines. This class takes target object, a primary
+ * command, and a list of arguments. It will then find the command in the target
+ * object. The method of this command must start with a "_" and take an
+ * parameter of Options type. Usually this is an interface that extends Options.
+ * The methods on this interface are options or flags (when they return
+ * boolean).
+ *
+ */
+@SuppressWarnings("unchecked") public class CommandLine {
+ static int LINELENGTH = 60;
+ static Pattern ASSIGNMENT = Pattern.compile("(\\w[\\w\\d]*+)\\s*=\\s*([^\\s]+)\\s*");
+ Reporter reporter;
+ Justif justif = new Justif(60);
+
+ public CommandLine(Reporter reporter) {
+ this.reporter = reporter;
+ }
+
+ /**
+ * Execute a command in a target object with a set of options and arguments
+ * and returns help text if something fails. Errors are reported.
+ */
+
+ public String execute(Object target, String cmd, List<String> input) throws Exception {
+
+ if (cmd.equals("help")) {
+ StringBuilder sb = new StringBuilder();
+ Formatter f = new Formatter(sb);
+ if (input.isEmpty())
+ help(f, target);
+ else {
+ for (String s : input) {
+ help(f, target, s);
+ }
+ }
+ f.flush();
+ justif.wrap(sb);
+ return sb.toString();
+ }
+
+ //
+ // Find the appropriate method
+ //
+
+ List<String> arguments = new ArrayList<String>(input);
+ Map<String, Method> commands = getCommands(target);
+
+ Method m = commands.get(cmd);
+ if (m == null) {
+ reporter.error("No such command %s\n", cmd);
+ return help(target, null, null);
+ }
+
+ //
+ // Parse the options
+ //
+
+ Class<? extends Options> optionClass = (Class<? extends Options>) m.getParameterTypes()[0];
+ Options options = getOptions(optionClass, arguments);
+ if (options == null) {
+ // had some error, already reported
+ return help(target, cmd, null);
+ }
+
+ // Check if we have an @Arguments annotation that
+ // provides patterns for the remainder arguments
+
+ Arguments argumentsAnnotation = optionClass.getAnnotation(Arguments.class);
+ if (argumentsAnnotation != null) {
+ String[] patterns = argumentsAnnotation.arg();
+
+ // Check for commands without any arguments
+
+ if (patterns.length == 0 && arguments.size() > 0) {
+ reporter.error("This command takes no arguments but found %s\n", arguments);
+ return help(target, cmd, null);
+ }
+
+ // Match the patterns to the given command line
+
+ int i = 0;
+ for (; i < patterns.length; i++) {
+ String pattern = patterns[i];
+
+ boolean optional = pattern.matches("\\[.*\\]");
+
+ // Handle vararg
+
+ if (pattern.equals("...")) {
+ i = Integer.MAX_VALUE;
+ break;
+ }
+
+ // Check if we're running out of args
+
+ if (i > arguments.size()) {
+ if (!optional)
+ reporter.error("Missing argument %s\n", patterns[i]);
+ return help(target, cmd, optionClass);
+ }
+ }
+
+ // Check if we have unconsumed arguments left
+
+ if (i < arguments.size()) {
+ reporter.error("Too many arguments specified %s, expecting %s\n", arguments,
+ Arrays.asList(patterns));
+ return help(target, cmd, optionClass);
+ }
+ }
+ if (reporter.getErrors().size() == 0) {
+ m.setAccessible(true);
+ m.invoke(target, options);
+ return null;
+ }
+ return help(target, cmd, optionClass);
+ }
+
+ private String help(Object target, String cmd, Class<? extends Options> type) throws Exception {
+ StringBuilder sb = new StringBuilder();
+ Formatter f = new Formatter(sb);
+ if (cmd == null)
+ help(f, target);
+ else if (type == null)
+ help(f, target, cmd);
+ else
+ help(f, target, cmd, type);
+
+ f.flush();
+ justif.wrap(sb);
+ return sb.toString();
+ }
+
+ /**
+ * Parse the options in a command line and return an interface that provides
+ * the options from this command line. This will parse up to (and including)
+ * -- or an argument that does not start with -
+ *
+ */
+ public <T extends Options> T getOptions(Class<T> specification, List<String> arguments)
+ throws Exception {
+ Map<String, String> properties = Create.map();
+ Map<String, Object> values = new HashMap<String, Object>();
+ Map<String, Method> options = getOptions(specification);
+
+ argloop: while (arguments.size() > 0) {
+
+ String option = arguments.get(0);
+
+ if (option.startsWith("-")) {
+
+ arguments.remove(0);
+
+ if (option.startsWith("--")) {
+
+ if ("--".equals(option))
+ break argloop;
+
+ // Full named option, e.g. --output
+ String name = option.substring(2);
+ Method m = options.get(name);
+ if (m == null)
+ reporter.error("Unrecognized option %s\n", name);
+ else
+ assignOptionValue(values, m, arguments, true);
+
+ } else {
+
+ // Set of single character named options like -a
+
+ charloop: for (int j = 1; j < option.length(); j++) {
+
+ char optionChar = option.charAt(j);
+
+ for (Entry<String, Method> entry : options.entrySet()) {
+ if (entry.getKey().charAt(0) == optionChar) {
+ boolean last = (j + 1) >= option.length();
+ assignOptionValue(values, entry.getValue(),
+ arguments, last);
+ continue charloop;
+ }
+ }
+ reporter.error("No such option -%s\n", optionChar);
+ }
+ }
+ } else {
+ Matcher m = ASSIGNMENT.matcher(option);
+ if (m.matches()) {
+ properties.put(m.group(1), m.group(2));
+ }
+ break;
+ }
+ }
+
+ // check if all required elements are set
+
+ for (Entry<String, Method> entry : options.entrySet()) {
+ Method m = entry.getValue();
+ String name = entry.getKey();
+ if (!values.containsKey(name) && isMandatory(m))
+ reporter.error("Required option --%s not set", name);
+ }
+
+ values.put(".", arguments);
+ values.put(".command", this);
+ values.put(".properties", properties);
+ return Configurable.createConfigurable(specification, values);
+ }
+
+ /**
+ * Answer a list of the options specified in an options interface
+ */
+ private Map<String, Method> getOptions(Class<? extends Options> interf) {
+ Map<String, Method> map = new TreeMap<String, Method>();
+
+ for (Method m : interf.getMethods()) {
+ if (m.getName().startsWith("_"))
+ continue;
+
+ String name;
+
+ Config cfg = m.getAnnotation(Config.class);
+ if (cfg == null || cfg.id() == null || cfg.id().equals(Config.NULL))
+ name = m.getName();
+ else
+ name = cfg.id();
+
+ map.put(name, m);
+ }
+ return map;
+ }
+
+ /**
+ * Assign an option, must handle flags, parameters, and parameters that can
+ * happen multiple times.
+ *
+ * @param options
+ * The command line map
+ * @param args
+ * the args input
+ * @param i
+ * where we are
+ * @param m
+ * the selected method for this option
+ * @param last
+ * if this is the last in a multi single character option
+ * @return
+ */
+ public void assignOptionValue(Map<String, Object> options, Method m, List<String> args,
+ boolean last) {
+ String name = m.getName();
+ Type type = m.getGenericReturnType();
+
+ if (isOption(m)) {
+
+ // The option is a simple flag
+
+ options.put(name, true);
+ } else {
+
+ // The option is followed by an argument
+
+ if (!last) {
+ reporter.error(
+ "Option --%s not last in a set of 1-letter options (%s) but it requires an argument of type ",
+ name, name.charAt(0), getTypeDescriptor(type));
+ return;
+ }
+
+ if (args.isEmpty()) {
+ reporter.error("Missing argument %s for option --%s, -%s ",
+ getTypeDescriptor(type), name, name.charAt(0));
+ return;
+ }
+
+ String parameter = args.remove(0);
+
+ if (Collection.class.isAssignableFrom(m.getReturnType())) {
+
+ Collection<Object> optionValues = (Collection<Object>) options.get(m.getName());
+
+ if (optionValues == null) {
+ optionValues = new ArrayList<Object>();
+ options.put(name, optionValues);
+ }
+
+ optionValues.add(parameter);
+ } else {
+
+ if (options.containsKey(name)) {
+ reporter.error("The option %s can only occur once", name);
+ return;
+ }
+
+ options.put(name, parameter);
+ }
+ }
+ }
+
+ /**
+ * Provide a help text.
+ */
+
+ public void help(Formatter f, Object target, String cmd, Class<? extends Options> specification) {
+ Description descr = specification.getAnnotation(Description.class);
+ Arguments patterns = specification.getAnnotation(Arguments.class);
+ Map<String, Method> options = getOptions(specification);
+
+ String description = descr == null ? "" : descr.value();
+
+ f.format("NAME\n %s - %s\n\n", cmd, description);
+ f.format("SYNOPSIS\n %s [options] ", cmd);
+
+ if (patterns == null)
+ f.format(" ...\n\n");
+ else {
+ String del = " ";
+ for (String pattern : patterns.arg()) {
+ if (pattern.equals("..."))
+ f.format("%s...", del);
+ else
+ f.format("%s<%s>", del, pattern);
+ del = " ";
+ }
+ f.format("\n\n");
+ }
+
+ f.format("OPTIONS\n");
+ for (Entry<String, Method> entry : options.entrySet()) {
+ String optionName = entry.getKey();
+ Method m = entry.getValue();
+
+ Config cfg = m.getAnnotation(Config.class);
+ Description d = m.getAnnotation(Description.class);
+ boolean required = isMandatory(m);
+
+ String methodDescription = cfg != null ? cfg.description() : (d == null ? "" : d
+ .value());
+
+ f.format(" %s -%s, --%s %s%s - %s\n", required ? " " : "[", //
+ optionName.charAt(0), //
+ optionName, //
+ getTypeDescriptor(m.getGenericReturnType()), //
+ required ? " " : "]",//
+ methodDescription);
+ }
+ f.format("\n");
+ }
+
+ static Pattern LAST_PART = Pattern.compile(".*[\\$\\.]([^\\$\\.]+)");
+
+ private static String lastPart(String name) {
+ Matcher m = LAST_PART.matcher(name);
+ if (m.matches())
+ return m.group(1);
+ return name;
+ }
+
+ /**
+ * Show all commands in a target
+ */
+ public void help(Formatter f, Object target) throws Exception {
+ // TODO get help from the class
+ Description descr = target.getClass().getAnnotation(Description.class);
+ if (descr != null) {
+ f.format("%s\n\n", descr.value());
+ }
+ f.format("Available commands: ");
+
+ String del = "";
+ for (String name : getCommands(target).keySet()) {
+ f.format("%s%s", del, name);
+ del = ", ";
+ }
+ f.format("\n");
+
+ }
+
+ /**
+ * Show the full help for a given command
+ */
+ public void help(Formatter f, Object target, String cmd) {
+
+ Method m = getCommands(target).get(cmd);
+ if (m == null)
+ f.format("No such command: %s\n", cmd);
+ else {
+ Class<? extends Options> options = (Class<? extends Options>) m.getParameterTypes()[0];
+ help(f, target, cmd, options);
+ }
+ }
+
+ /**
+ * Parse a class and return a list of command names
+ *
+ * @param target
+ * @return
+ */
+ public Map<String, Method> getCommands(Object target) {
+ Map<String, Method> map = new TreeMap<String, Method>();
+
+ for (Method m : target.getClass().getMethods()) {
+
+ if (m.getParameterTypes().length == 1 && m.getName().startsWith("_")) {
+ Class<?> clazz = m.getParameterTypes()[0];
+ if (Options.class.isAssignableFrom(clazz)) {
+ String name = m.getName().substring(1);
+ map.put(name, m);
+ }
+ }
+ }
+ return map;
+ }
+
+ /**
+ * Answer if the method is marked mandatory
+ */
+ private boolean isMandatory(Method m) {
+ Config cfg = m.getAnnotation(Config.class);
+ if (cfg == null)
+ return false;
+
+ return cfg.required();
+ }
+
+ /**
+ * @param m
+ * @return
+ */
+ private boolean isOption(Method m) {
+ return m.getReturnType() == boolean.class || m.getReturnType() == Boolean.class;
+ }
+
+ /**
+ * Show a type in a nice way
+ */
+
+ private String getTypeDescriptor(Type type) {
+ if (type instanceof ParameterizedType) {
+ ParameterizedType pt = (ParameterizedType) type;
+ Type c = pt.getRawType();
+ if (c instanceof Class) {
+ if (Collection.class.isAssignableFrom((Class<?>) c)) {
+ return getTypeDescriptor(pt.getActualTypeArguments()[0]) + "*";
+ }
+ }
+ }
+ if (!(type instanceof Class))
+ return "<>";
+
+ Class<?> clazz = (Class<?>) type;
+
+ if (clazz == Boolean.class || clazz == boolean.class)
+ return ""; // Is a flag
+
+ return "<" + lastPart(clazz.getName().toLowerCase()) + ">";
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/CommandLine.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/CommandLine.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Description.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Description.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Description.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Description.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,8 @@
+package aQute.lib.getopt;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Description {
+ String value();
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Description.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Description.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/OptionArgument.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/OptionArgument.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/OptionArgument.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/OptionArgument.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,8 @@
+package aQute.lib.getopt;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface OptionArgument {
+ String value();
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/OptionArgument.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/OptionArgument.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Options.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Options.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Options.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Options.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,11 @@
+package aQute.lib.getopt;
+
+import java.util.*;
+
+public interface Options {
+ List<String> _();
+ CommandLine _command();
+ Map<String,String> _properties();
+ boolean _ok();
+ boolean _help();
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Options.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/Options.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/packageinfo?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/packageinfo (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/getopt/packageinfo Thu Jun 7 21:57:32 2012
@@ -0,0 +1 @@
+version 1.0.0
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/hex/Hex.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/hex/Hex.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/hex/Hex.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/hex/Hex.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,60 @@
+package aQute.lib.hex;
+
+import java.io.*;
+
+
+/*
+ * Hex converter.
+ *
+ * TODO Implement string to byte[]
+ */
+public class Hex {
+ final static char[] HEX = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+ public final static byte[] toByteArray(String string) {
+ string = string.trim();
+ if ( (string.length() & 1) != 0)
+ throw new IllegalArgumentException("a hex string must have an even length");
+
+ byte[]out = new byte[ string.length()/2];
+ for ( int i=0; i < out.length; i++) {
+ int high = nibble(string.charAt(i*2))<<4;
+ int low = nibble(string.charAt(i*2+1));
+ out[i] = (byte) (high + low);
+ }
+ return out;
+ }
+
+
+ public final static int nibble( char c) {
+ 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("Not a hex digit: " + c);
+ }
+
+ public final static String toHexString(byte data[]) {
+ StringBuilder sb = new StringBuilder();
+ try {
+ append(sb,data);
+ } catch (IOException e) {
+ // cannot happen with sb
+ }
+ return sb.toString();
+ }
+
+ public final static void append( Appendable sb, byte [] data ) throws IOException {
+ for ( int i =0; i<data.length; i++) {
+ sb.append( nibble( data[i] >> 4));
+ sb.append( nibble( data[i]));
+ }
+ }
+
+ private final static char nibble(int i) {
+ return HEX[i & 0xF];
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/hex/Hex.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/hex/Hex.java
------------------------------------------------------------------------------
svn:executable = *
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/hex/Hex.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/hex/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/hex/packageinfo?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/hex/packageinfo (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/hex/packageinfo Thu Jun 7 21:57:32 2012
@@ -0,0 +1 @@
+version 1.0
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/index/Index.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/index/Index.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/index/Index.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/index/Index.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,349 @@
+package aQute.lib.index;
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.nio.channels.FileChannel.MapMode;
+import java.util.*;
+
+/**
+ * <pre>
+ * 0 -> 0, 122 -> 1
+ * 123 -> 123, 244 -> 2
+ * 245 -> 245, ...
+ * </pre>
+ *
+ *
+ */
+public class Index implements Iterable<byte[]> {
+ final static int LEAF = 0;
+ final static int INDEX = 1;
+
+ final static int SIGNATURE = 0;
+ final static int MAGIC = 0x494C4458;
+ final static int KEYSIZE = 4;
+
+ private FileChannel file;
+ final int pageSize = 4096;
+ final int keySize;
+ final int valueSize = 8;
+ final int capacity;
+ public Page root;
+ final LinkedHashMap<Integer, Page> cache = new LinkedHashMap<Integer, Index.Page>();
+ final MappedByteBuffer settings;
+
+ private int nextPage;
+
+ class Page {
+ final static int TYPE_OFFSET = 0;
+ final static int COUNT_OFFSET = 2;
+ final static int START_OFFSET = 4;
+ final int number;
+ boolean leaf;
+ final MappedByteBuffer buffer;
+ int n = 0;
+ boolean dirty;
+
+ Page(int number) throws IOException {
+ this.number = number;
+ buffer = file.map(MapMode.READ_WRITE, ((long) number) * pageSize, pageSize);
+ n = buffer.getShort(COUNT_OFFSET);
+ int type = buffer.getShort(TYPE_OFFSET);
+ leaf = type != 0;
+ }
+
+ Page(int number, boolean leaf) throws IOException {
+ this.number = number;
+ this.leaf = leaf;
+ this.n = 0;
+ buffer = file.map(MapMode.READ_WRITE, ((long) number) * pageSize, pageSize);
+ }
+
+ Iterator<byte[]> iterator() {
+ return new Iterator<byte[]>() {
+ Iterator<byte[]> i;
+ int rover = 0;
+
+ public byte[] next() {
+ if (leaf) {
+ return k(rover++);
+ }
+
+ return i.next();
+ }
+
+ public boolean hasNext() {
+ try {
+ if (leaf)
+ return rover < n;
+ while (i == null || i.hasNext() == false) {
+ int c = (int) c(rover++);
+ i = getPage(c).iterator();
+ }
+ return i.hasNext();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ };
+ }
+
+ void write() throws IOException {
+ buffer.putShort(COUNT_OFFSET, (short) n);
+ buffer.put(TYPE_OFFSET, (byte) (leaf ? 1 : 0));
+ buffer.force();
+ }
+
+ int compare(byte[] key, int i) {
+ int index = pos(i);
+ for (int j = 0; j < keySize; j++, index++) {
+ int a = 0;
+ if (j < key.length)
+ a = key[j] & 0xFF;
+
+ int b = buffer.get(index) & 0xFF;
+ if (a == b)
+ continue;
+
+ return a > b ? 1 : -1;
+ }
+ return 0;
+ }
+
+ int pos(int i) {
+ return START_OFFSET + size(i);
+ }
+
+ int size(int n) {
+ return n * (keySize + valueSize);
+ }
+
+ void copyFrom(Page page, int start, int length) {
+ copy(page.buffer, pos(start), buffer, pos(0), size(length));
+ }
+
+ void copy(ByteBuffer src, int srcPos, ByteBuffer dst, int dstPos, int length) {
+ if (srcPos < dstPos) {
+ while (length-- > 0)
+ dst.put(dstPos + length, src.get(srcPos + length));
+
+ } else {
+ while (length-- > 0)
+ dst.put(dstPos++, src.get(srcPos++));
+ }
+ }
+
+ long search(byte[] k) throws Exception {
+ int cmp = 0;
+ int i = n - 1;
+ while (i >= 0 && (cmp = compare(k, i)) < 0)
+ i--;
+
+ if (leaf) {
+ if (cmp != 0)
+ return -1;
+ return c(i);
+ }
+ long value = c(i);
+ Page child = getPage((int) value);
+ return child.search(k);
+ }
+
+ void insert(byte[] k, long v) throws IOException {
+ if (n == capacity) {
+ int t = capacity / 2;
+ Page left = allocate(leaf);
+ Page right = allocate(leaf);
+ left.copyFrom(this, 0, t);
+ left.n = t;
+ right.copyFrom(this, t, capacity - t);
+ right.n = capacity - t;
+ leaf = false;
+ set(0, left.k(0), left.number);
+ set(1, right.k(0), right.number);
+ n = 2;
+ left.write();
+ right.write();
+ }
+ insertNonFull(k, v);
+ }
+
+ byte[] k(int i) {
+ buffer.position(pos(i));
+ byte[] key = new byte[keySize];
+ buffer.get(key);
+ return key;
+ }
+
+ long c(int i) {
+ if (i < 0) {
+ System.err.println("Arghhh");
+ }
+ int index = pos(i) + keySize;
+ return buffer.getLong(index);
+ }
+
+ void set(int i, byte[] k, long v) {
+ int index = pos(i);
+ for (int j = 0; j < keySize; j++) {
+ byte a = 0;
+ if (j < k.length)
+ a = k[j];
+ buffer.put(index + j, a);
+ }
+ buffer.putLong(index + keySize, v);
+ }
+
+ void insertNonFull(byte[] k, long v) throws IOException {
+ int cmp = 0;
+ int i = n - 1;
+ while (i >= 0 && (cmp = compare(k, i)) < 0)
+ i--;
+
+ if (leaf) {
+ if (cmp != 0) {
+ i++;
+ if (i != n)
+ copy(buffer, pos(i), buffer, pos(i + 1), size(n - i));
+ }
+ set(i, k, v);
+ n++;
+ dirty = true;
+ } else {
+ long value = c(i);
+ Page child = getPage((int) value);
+
+ if (child.n == capacity) {
+ Page left = child;
+ int t = capacity / 2;
+ Page right = allocate(child.leaf);
+ right.copyFrom(left, t, capacity - t);
+ right.n = capacity - t;
+ left.n = t;
+ i++; // place to insert
+ if (i < n) // ok if at end
+ copy(buffer, pos(i), buffer, pos(i + 1), size(n - i));
+ set(i, right.k(0), right.number);
+ n++;
+ assert i < n;
+ child = right.compare(k, 0) >= 0 ? right : left;
+ left.dirty = true;
+ right.dirty = true;
+ this.dirty = true;
+ }
+ child.insertNonFull(k, v);
+ }
+ write();
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ try {
+ toString(sb, "");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return sb.toString();
+ }
+
+ public void toString(StringBuilder sb, String indent) throws IOException {
+ for (int i = 0; i < n; i++) {
+ sb.append(String.format("%s %02d:%02d %20s %s %d\n", indent, number, i,
+ hex(k(i), 0, 4), leaf ? "==" : "->", c(i)));
+ if (!leaf) {
+ long c = c(i);
+ Page sub = getPage((int) c);
+ sub.toString(sb, indent + " ");
+ }
+ }
+ }
+
+ private String hex(byte[] k, int i, int j) {
+ StringBuilder sb = new StringBuilder();
+
+ while (i < j) {
+ int b = 0xFF & k[i];
+ sb.append(nibble(b >> 4));
+ sb.append(nibble(b));
+ i++;
+ }
+ return sb.toString();
+ }
+
+ private char nibble(int i) {
+ i = i & 0xF;
+ return (char) (i >= 10 ? i + 'A' - 10 : i + '0');
+ }
+
+ }
+
+ public Index(File file, int keySize) throws IOException {
+ capacity = (pageSize - Page.START_OFFSET) / (keySize + valueSize);
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+ this.file = raf.getChannel();
+ settings = this.file.map(MapMode.READ_WRITE, 0, pageSize);
+ if (this.file.size() == pageSize) {
+ this.keySize = keySize;
+ settings.putInt(SIGNATURE, MAGIC);
+ settings.putInt(KEYSIZE, keySize);
+ nextPage = 1;
+ root = allocate(true);
+ root.n = 1;
+ root.set(0, new byte[KEYSIZE], 0);
+ root.write();
+ } else {
+ if (settings.getInt(SIGNATURE) != MAGIC)
+ throw new IllegalStateException("No Index file, magic is not " + MAGIC);
+
+ this.keySize = settings.getInt(KEYSIZE);
+ if (keySize != 0 && this.keySize != keySize)
+ throw new IllegalStateException("Invalid key size for Index file. The file is "
+ + this.keySize + " and was expected to be " + this.keySize);
+
+ root = getPage(1);
+ nextPage = (int) (this.file.size() / pageSize);
+ }
+ }
+
+ public void insert(byte[] k, long v) throws Exception {
+ root.insert(k, v);
+ }
+
+ public long search(byte[] k) throws Exception {
+ return root.search(k);
+ }
+
+ Page allocate(boolean leaf) throws IOException {
+ Page page = new Page(nextPage++, leaf);
+ cache.put(page.number, page);
+ return page;
+ }
+
+ Page getPage(int number) throws IOException {
+ Page page = cache.get(number);
+ if (page == null) {
+ page = new Page(number);
+ cache.put(number, page);
+ }
+ return page;
+ }
+
+ public String toString() {
+ return root.toString();
+ }
+
+ public void close() throws IOException {
+ file.close();
+ cache.clear();
+ }
+
+ public Iterator<byte[]> iterator() {
+ return root.iterator();
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/index/Index.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/index/Index.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/index/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/index/packageinfo?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/index/packageinfo (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/index/packageinfo Thu Jun 7 21:57:32 2012
@@ -0,0 +1 @@
+version 1.0
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/io/IO.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/io/IO.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/io/IO.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/io/IO.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,388 @@
+package aQute.lib.io;
+
+import java.io.*;
+import java.net.*;
+import java.nio.*;
+import java.security.*;
+import java.util.*;
+
+public class IO {
+
+ public static void copy(Reader r, Writer w) throws IOException {
+ try {
+ char buffer[] = new char[8000];
+ int size = r.read(buffer);
+ while (size > 0) {
+ w.write(buffer, 0, size);
+ size = r.read(buffer);
+ }
+ } finally {
+ r.close();
+ w.flush();
+ }
+ }
+
+ public static void copy(InputStream r, Writer w) throws IOException {
+ copy(r, w, "UTF-8");
+ }
+
+ public static void copy(byte []r, Writer w) throws IOException {
+ copy( new ByteArrayInputStream(r), w, "UTF-8");
+ }
+
+ public static void copy(byte []r, OutputStream w) throws IOException {
+ copy( new ByteArrayInputStream(r), w);
+ }
+
+ public static void copy(InputStream r, Writer w, String charset) throws IOException {
+ try {
+ InputStreamReader isr = new InputStreamReader(r, charset);
+ copy(isr, w);
+ } finally {
+ r.close();
+ }
+ }
+
+ public static void copy(Reader r, OutputStream o) throws IOException {
+ copy(r, o, "UTF-8");
+ }
+
+ public static void copy(Reader r, OutputStream o, String charset) throws IOException {
+ try {
+ OutputStreamWriter osw = new OutputStreamWriter(o, charset);
+ copy(r, osw);
+ } finally {
+ r.close();
+ }
+ }
+
+ public static void copy(InputStream in, OutputStream out) throws IOException {
+ DataOutputStream dos = new DataOutputStream(out);
+ copy(in, (DataOutput) dos);
+ out.flush();
+ }
+
+ public static void copy(InputStream in, DataOutput out) throws IOException {
+ byte[] buffer = new byte[10000];
+ try {
+ int size = in.read(buffer);
+ while (size > 0) {
+ out.write(buffer, 0, size);
+ size = in.read(buffer);
+ }
+ } finally {
+ in.close();
+ }
+ }
+
+ public static void copy(InputStream in, ByteBuffer bb) throws IOException {
+ byte[] buffer = new byte[10000];
+ try {
+ int size = in.read(buffer);
+ while (size > 0) {
+ bb.put(buffer, 0, size);
+ size = in.read(buffer);
+ }
+ } finally {
+ in.close();
+ }
+ }
+
+ public static void copy(URL in, MessageDigest md) throws IOException {
+ copy(in.openStream(), md);
+ }
+
+ public static void copy(File in, MessageDigest md) throws IOException {
+ copy(new FileInputStream(in), md);
+ }
+
+ public static void copy(URLConnection in, MessageDigest md) throws IOException {
+ copy(in.getInputStream(), md);
+ }
+
+
+ public static void copy(InputStream in, MessageDigest md) throws IOException {
+ byte[] buffer = new byte[10000];
+ try {
+ int size = in.read(buffer);
+ while (size > 0) {
+ md.update(buffer, 0, size);
+ size = in.read(buffer);
+ }
+ } finally {
+ in.close();
+ }
+ }
+
+ public static void copy(URL url, File file) throws IOException {
+ URLConnection c = url.openConnection();
+ copy(c, file);
+ }
+
+ public static void copy(URLConnection c, File file) throws IOException {
+ copy(c.getInputStream(), file);
+ }
+
+ public static void copy(InputStream in, URL out) throws IOException {
+ copy(in, out, null);
+ }
+
+ public static void copy(InputStream in, URL out, String method) throws IOException {
+ URLConnection c = out.openConnection();
+ if (c instanceof HttpURLConnection && method != null) {
+ HttpURLConnection http = (HttpURLConnection) c;
+ http.setRequestMethod(method);
+ }
+ c.setDoOutput(true);
+ copy(in, c.getOutputStream());
+ }
+
+ public static void copy(File a, File b) throws IOException {
+ if (a.isFile()) {
+ FileOutputStream out = new FileOutputStream(b);
+ try {
+ copy(new FileInputStream(a), out);
+ } finally {
+ out.close();
+ }
+ } else if (a.isDirectory()) {
+ b.mkdirs();
+ if (!b.isDirectory())
+ throw new IllegalArgumentException(
+ "target directory for a directory must be a directory: " + b);
+ File subs[] = a.listFiles();
+ for (File sub : subs) {
+ copy(sub, new File(b, sub.getName()));
+ }
+ } else
+ throw new FileNotFoundException("During copy: " + a.toString());
+ }
+
+ public static void copy(InputStream a, File b) throws IOException {
+ FileOutputStream out = new FileOutputStream(b);
+ try {
+ copy(a, out);
+ } finally {
+ out.close();
+ }
+ }
+
+ public static void copy(File a, OutputStream b) throws IOException {
+ copy(new FileInputStream(a), b);
+ }
+
+ public static String collect(File a, String encoding) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copy(a, out);
+ return new String(out.toByteArray(), encoding);
+ }
+
+ public static String collect(URL a, String encoding) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copy(a.openStream(), out);
+ return new String(out.toByteArray(), encoding);
+ }
+
+ public static String collect(URL a) throws IOException {
+ return collect(a, "UTF-8");
+ }
+
+ public static String collect(File a) throws IOException {
+ return collect(a, "UTF-8");
+ }
+
+ public static String collect(String a) throws IOException {
+ return collect(new File(a), "UTF-8");
+ }
+
+ public static String collect(InputStream a, String encoding) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copy(a, out);
+ return new String(out.toByteArray(), encoding);
+ }
+
+ public static String collect(InputStream a) throws IOException {
+ return collect(a, "UTF-8");
+ }
+
+ public static String collect(Reader a) throws IOException {
+ StringWriter sw = new StringWriter();
+ char[] buffer = new char[10000];
+ int size = a.read(buffer);
+ while (size > 0) {
+ sw.write(buffer, 0, size);
+ size = a.read(buffer);
+ }
+ return sw.toString();
+ }
+
+ public static File getFile(File base, String file) {
+ File f = new File(file);
+ if (f.isAbsolute())
+ return f;
+ int n;
+
+ f = base.getAbsoluteFile();
+ while ((n = file.indexOf('/')) > 0) {
+ String first = file.substring(0, n);
+ file = file.substring(n + 1);
+ if (first.equals(".."))
+ f = f.getParentFile();
+ else
+ f = new File(f, first);
+ }
+ if (file.equals(".."))
+ return f.getParentFile();
+ return new File(f, file).getAbsoluteFile();
+ }
+
+ public static void delete(File f) {
+ f = f.getAbsoluteFile();
+ if (f.getParentFile() == null)
+ throw new IllegalArgumentException("Cannot recursively delete root for safety reasons");
+
+ if (f.isDirectory()) {
+ File[] subs = f.listFiles();
+ for (File sub : subs)
+ delete(sub);
+ }
+
+ f.delete();
+ }
+
+ public static long drain(InputStream in) throws IOException {
+ long result = 0;
+ byte[] buffer = new byte[10000];
+ try {
+ int size = in.read(buffer);
+ while (size >= 0) {
+ result += size;
+ size = in.read(buffer);
+ }
+ } finally {
+ in.close();
+ }
+ return result;
+ }
+
+ public void copy(Collection<?> c, OutputStream out) throws IOException {
+ Writer w = new OutputStreamWriter(out,"UTF-8");
+ PrintWriter ps = new PrintWriter(w);
+ for (Object o : c) {
+ ps.println(o);
+ }
+ ps.flush();
+ w.flush();
+ }
+
+ public static Throwable close(Closeable in) {
+ if ( in == null)
+ return null;
+
+ try {
+ in.close();
+ return null;
+ } catch (Throwable e) {
+ return e;
+ }
+ }
+
+ public static URL toURL(String s, File base) throws MalformedURLException {
+ int n = s.indexOf(':');
+ if (n > 0 && n < 10) {
+ // is url
+ return new URL(s);
+ }
+ return getFile(base, s).toURI().toURL();
+ }
+
+ public static void store(Object o, File out) throws IOException {
+ store(o, out, "UTF-8");
+ }
+
+ public static void store(Object o, File out, String encoding) throws IOException {
+ FileOutputStream fout = new FileOutputStream(out);
+ try {
+ store(o, fout, encoding);
+ } finally {
+ fout.close();
+ }
+ }
+
+ public static void store(Object o, OutputStream fout) throws UnsupportedEncodingException,
+ IOException {
+ store(o, fout, "UTF-8");
+ }
+
+ public static void store(Object o, OutputStream fout, String encoding)
+ throws UnsupportedEncodingException, IOException {
+ String s;
+
+ if (o == null)
+ s = "";
+ else
+ s = o.toString();
+
+ try {
+ fout.write(s.getBytes(encoding));
+ } finally {
+ fout.close();
+ }
+ }
+
+ public static InputStream stream(String s) {
+ try {
+ return new ByteArrayInputStream(s.getBytes("UTF-8"));
+ } catch (Exception e) {
+ // Ignore
+ return null;
+ }
+ }
+
+ public static InputStream stream(String s, String encoding) throws UnsupportedEncodingException {
+ return new ByteArrayInputStream(s.getBytes(encoding));
+ }
+
+ public static InputStream stream(File s) throws FileNotFoundException {
+ return new FileInputStream(s);
+ }
+
+ public static InputStream stream(URL s) throws IOException {
+ return s.openStream();
+ }
+
+ public static Reader reader(String s) {
+ return new StringReader(s);
+ }
+
+
+ public static BufferedReader reader(File f, String encoding) throws IOException {
+ return reader( new FileInputStream(f), encoding);
+ }
+
+ public static BufferedReader reader(File f) throws IOException {
+ return reader(f,"UTF-8");
+ }
+
+ public static PrintWriter writer(File f, String encoding) throws IOException {
+ return writer( new FileOutputStream(f),encoding);
+ }
+
+ public static PrintWriter writer(File f) throws IOException {
+ return writer(f, "UTF-8");
+ }
+
+ public static PrintWriter writer(OutputStream out, String encoding) throws IOException {
+ return new PrintWriter( new OutputStreamWriter( out,encoding));
+ }
+ public static BufferedReader reader(InputStream in, String encoding) throws IOException {
+ return new BufferedReader( new InputStreamReader(in, encoding));
+ }
+
+ public static BufferedReader reader(InputStream in) throws IOException {
+ return reader(in, "UTF-8");
+ }
+ public static PrintWriter writer(OutputStream out) throws IOException {
+ return writer(out, "UTF-8");
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/io/IO.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/io/IO.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/io/LimitedInputStream.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/io/LimitedInputStream.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/io/LimitedInputStream.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/io/LimitedInputStream.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,78 @@
+package aQute.lib.io;
+
+import java.io.*;
+
+public class LimitedInputStream extends InputStream {
+
+ final InputStream in;
+ final int size;
+ int left;
+
+ public LimitedInputStream(InputStream in, int size) {
+ this.in = in;
+ this.left = size;
+ this.size = size;
+ }
+
+ @Override public int read() throws IOException {
+ if (left <= 0) {
+ eof();
+ return -1;
+ }
+
+ left--;
+ return in.read();
+ }
+
+ @Override public int available() throws IOException {
+ return Math.min(left, in.available());
+ }
+
+ @Override public void close() throws IOException {
+ eof();
+ in.close();
+ }
+
+ protected void eof() {
+ }
+
+ @Override public synchronized void mark(int readlimit) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean markSupported() {
+ return false;
+ }
+
+ @Override public int read(byte[] b, int off, int len) throws IOException {
+ int min = Math.min(len, left);
+ if (min == 0)
+ return 0;
+
+ int read = in.read(b, off, min);
+ if (read > 0)
+ left -= read;
+ return read;
+ }
+
+ @Override public int read(byte[] b) throws IOException {
+ return read(b,0,b.length);
+ }
+
+ @Override public synchronized void reset() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public long skip(long n) throws IOException {
+ long count = 0;
+ byte buffer[] = new byte[1024];
+ while ( n > 0 && read() >= 0) {
+ int size = read(buffer);
+ if ( size <= 0)
+ return count;
+ count+=size;
+ n-=size;
+ }
+ return count;
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/io/LimitedInputStream.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/io/LimitedInputStream.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/io/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/io/packageinfo?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/io/packageinfo (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/io/packageinfo Thu Jun 7 21:57:32 2012
@@ -0,0 +1 @@
+version 1.2.0
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ArrayHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ArrayHandler.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ArrayHandler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ArrayHandler.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,40 @@
+package aQute.lib.json;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+public class ArrayHandler extends Handler {
+ Type componentType;
+
+ ArrayHandler(Class< ? > rawClass, Type componentType) {
+ this.componentType = componentType;
+ }
+
+ @Override
+ void encode(Encoder app, Object object, Map<Object, Type> visited)
+ throws IOException, Exception {
+ app.append("[");
+ String del = "";
+ int l = Array.getLength(object);
+ for (int i = 0; i < l; i++) {
+ app.append(del);
+ app.encode(Array.get(object, i), componentType, visited);
+ del = ",";
+ }
+ app.append("]");
+ }
+
+ @Override
+ Object decodeArray(Decoder r) throws Exception {
+ ArrayList<Object> list = new ArrayList<Object>();
+ r.codec.parseArray(list, componentType, r);
+ Object array = Array.newInstance(r.codec.getRawClass(componentType),
+ list.size());
+ int n = 0;
+ for (Object o : list)
+ Array.set(array, n++, o);
+
+ return array;
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ArrayHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ArrayHandler.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/BooleanHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/BooleanHandler.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/BooleanHandler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/BooleanHandler.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,30 @@
+package aQute.lib.json;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+public class BooleanHandler extends Handler {
+
+ @Override void encode(Encoder app, Object object, Map<Object, Type> visited)
+ throws IOException, Exception {
+ app.append( object.toString());
+ }
+
+ @Override Object decode(boolean s) {
+ return s;
+ }
+
+ @Override Object decode(String s) {
+ return Boolean.parseBoolean(s);
+ }
+
+ @Override Object decode(Number s) {
+ return s.intValue() != 0;
+ }
+
+ @Override Object decode() {
+ return false;
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/BooleanHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/BooleanHandler.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ByteArrayHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ByteArrayHandler.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ByteArrayHandler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ByteArrayHandler.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,30 @@
+package aQute.lib.json;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+import aQute.lib.base64.*;
+
+public class ByteArrayHandler extends Handler {
+
+ @Override void encode(Encoder app, Object object, Map<Object, Type> visited)
+ throws IOException, Exception {
+ StringHandler.string(app, Base64.encodeBase64((byte[]) object));
+ }
+
+ @Override Object decodeArray(Decoder r) throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ ArrayList<Object> list = new ArrayList<Object>();
+ r.codec.parseArray(list, Byte.class, r);
+ for (Object b : list) {
+ out.write(((Byte) b).byteValue());
+ }
+ return out.toByteArray();
+ }
+
+ @Override Object decode(String s) throws Exception {
+ return Base64.decodeBase64(s);
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ByteArrayHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ByteArrayHandler.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/CharacterHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/CharacterHandler.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/CharacterHandler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/CharacterHandler.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,31 @@
+package aQute.lib.json;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+public class CharacterHandler extends Handler {
+
+ @Override void encode(Encoder app, Object object, Map<Object, Type> visited)
+ throws Exception {
+ Character c = (Character) object;
+ int v = (int) c.charValue();
+ app.append( v+"" );
+ }
+
+ @Override Object decode(boolean s) {
+ return s ? 't' : 'f';
+ }
+
+ @Override Object decode(String s) {
+ return (char) Integer.parseInt(s);
+ }
+
+ @Override Object decode(Number s) {
+ return (char) s.shortValue();
+ }
+
+ @Override Object decode() {
+ return 0;
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/CharacterHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/CharacterHandler.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/CollectionHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/CollectionHandler.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/CollectionHandler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/CollectionHandler.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,57 @@
+package aQute.lib.json;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+public class CollectionHandler extends Handler {
+ Class<?> rawClass;
+ Type componentType;
+
+ CollectionHandler(Class<?> rawClass, Type componentType) {
+ this.componentType = componentType;
+ if (rawClass.isInterface()) {
+ if (rawClass.isAssignableFrom(ArrayList.class))
+ rawClass = ArrayList.class;
+ else if (rawClass.isAssignableFrom(LinkedList.class))
+ rawClass = LinkedList.class;
+ else if (rawClass.isAssignableFrom(HashSet.class))
+ rawClass = HashSet.class;
+ else if (rawClass.isAssignableFrom(TreeSet.class))
+ rawClass = TreeSet.class;
+ else if (rawClass.isAssignableFrom(Vector.class))
+ rawClass = Vector.class;
+ else if (rawClass.isAssignableFrom(ConcurrentLinkedQueue.class))
+ rawClass = ConcurrentLinkedQueue.class;
+ else if (rawClass.isAssignableFrom(CopyOnWriteArrayList.class))
+ rawClass = CopyOnWriteArrayList.class;
+ else if (rawClass.isAssignableFrom(CopyOnWriteArraySet.class))
+ rawClass = CopyOnWriteArraySet.class;
+ else
+ throw new IllegalArgumentException("Unknown interface type for collection: "
+ + rawClass);
+ }
+ this.rawClass = rawClass;
+ }
+
+ @Override void encode(Encoder app, Object object, Map<Object, Type> visited)
+ throws IOException, Exception {
+ Collection<?> collection = (Collection<?>) object;
+
+ app.append("[");
+ String del = "";
+ for (Object o : collection) {
+ app.append(del);
+ app.encode(o, componentType, visited);
+ del = ",";
+ }
+ app.append("]");
+ }
+
+ @SuppressWarnings("unchecked") @Override Object decodeArray(Decoder r) throws Exception {
+ Collection<Object> c = (Collection<Object>) rawClass.newInstance();
+ r.codec.parseArray(c, componentType, r);
+ return c;
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/CollectionHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/CollectionHandler.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/DateHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/DateHandler.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/DateHandler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/DateHandler.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,30 @@
+package aQute.lib.json;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.text.*;
+import java.util.*;
+
+public class DateHandler extends Handler {
+ final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+
+ @Override void encode(Encoder app, Object object, Map<Object, Type> visited)
+ throws IOException, Exception {
+ String s;
+ synchronized (sdf) {
+ s = sdf.format((Date) object);
+ }
+ StringHandler.string(app, s);
+ }
+
+ @Override Object decode(String s) throws Exception {
+ synchronized (sdf) {
+ return sdf.parse(s);
+ }
+ }
+
+ @Override Object decode(Number s) throws Exception {
+ return new Date(s.longValue());
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/DateHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/DateHandler.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Decoder.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Decoder.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Decoder.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Decoder.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,137 @@
+package aQute.lib.json;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.security.*;
+import java.util.*;
+
+public class Decoder implements Closeable {
+ final JSONCodec codec;
+ Reader reader;
+ int current;
+ MessageDigest digest;
+ Map<String, Object> extra;
+ String encoding = "UTF-8";
+
+ boolean strict;
+
+ Decoder(JSONCodec codec) {
+ this.codec = codec;
+ }
+
+ public Decoder from(File file) throws Exception {
+ return from(new FileInputStream(file));
+ }
+
+ public Decoder from(InputStream in) throws Exception {
+ return from(new InputStreamReader(in, encoding));
+ }
+
+ public Decoder charset(String encoding) {
+ this.encoding = encoding;
+ return this;
+ }
+
+ public Decoder strict() {
+ this.strict = true;
+ return this;
+ }
+
+ public Decoder from(Reader in) throws Exception {
+ reader = in;
+ read();
+ return this;
+ }
+
+ public Decoder faq(String in) throws Exception {
+ return from(in.replace('\'', '"'));
+ }
+
+ public Decoder from(String in) throws Exception {
+ return from(new StringReader(in));
+ }
+
+ public Decoder mark() throws NoSuchAlgorithmException {
+ if (digest == null)
+ digest = MessageDigest.getInstance("SHA1");
+ digest.reset();
+ return this;
+ }
+
+ public byte[] digest() {
+ if (digest == null)
+ return null;
+
+ return digest.digest();
+ }
+
+ @SuppressWarnings("unchecked") public <T> T get(Class<T> clazz) throws Exception {
+ return (T) codec.decode(clazz, this);
+ }
+
+ public Object get(Type type) throws Exception {
+ return codec.decode(type, this);
+ }
+
+ public Object get() throws Exception {
+ return codec.decode(null, this);
+ }
+
+ int read() throws Exception {
+ current = reader.read();
+ if (digest != null) {
+ digest.update((byte) (current / 256));
+ digest.update((byte) (current % 256));
+ }
+ return current;
+ }
+
+ int current() {
+ return current;
+ }
+
+ /**
+ * Skip any whitespace.
+ *
+ * @return
+ * @throws Exception
+ */
+ int skipWs() throws Exception {
+ while (Character.isWhitespace(current()))
+ read();
+ return current();
+ }
+
+ /**
+ * Skip any whitespace.
+ *
+ * @return
+ * @throws Exception
+ */
+ int next() throws Exception {
+ read();
+ return skipWs();
+ }
+
+ void expect(String s) throws Exception {
+ for (int i = 0; i < s.length(); i++)
+ if (!(s.charAt(i) == read()))
+ throw new IllegalArgumentException("Expected " + s + " but got something different");
+ read();
+ }
+
+ public boolean isEof() throws Exception {
+ int c = skipWs();
+ return c < 0;
+ }
+
+ public void close() throws IOException {
+ reader.close();
+ }
+
+ public Map<String, Object> getExtra() {
+ if (extra == null)
+ extra = new HashMap<String, Object>();
+ return extra;
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Decoder.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Decoder.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Encoder.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Encoder.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Encoder.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Encoder.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,112 @@
+package aQute.lib.json;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.security.*;
+import java.util.*;
+
+public class Encoder implements Appendable, Closeable, Flushable {
+ final JSONCodec codec;
+ Appendable app;
+ MessageDigest digest;
+ boolean writeDefaults;
+ String encoding = "UTF-8";
+
+ Encoder(JSONCodec codec) {
+ this.codec = codec;
+ }
+
+ public Encoder put(Object object) throws Exception {
+ if (app == null)
+ to();
+
+ codec.encode(this, object, null, new IdentityHashMap<Object, Type>());
+ return this;
+ }
+
+ public Encoder mark() throws NoSuchAlgorithmException {
+ if (digest == null)
+ digest = MessageDigest.getInstance("SHA1");
+ digest.reset();
+ return this;
+ }
+
+ public byte[] digest() throws NoSuchAlgorithmException, IOException {
+ if (digest == null)
+ return null;
+ append('\n');
+ return digest.digest();
+ }
+
+ public Encoder to() throws IOException {
+ to(new StringWriter());
+ return this;
+ }
+
+ public Encoder to(File file) throws IOException {
+ return to(new FileOutputStream(file));
+ }
+
+ public Encoder charset(String encoding) {
+ this.encoding = encoding;
+ return this;
+ }
+
+ public Encoder to(OutputStream out) throws IOException {
+ return to(new OutputStreamWriter(out, encoding));
+ }
+
+ public Encoder to(Appendable out) throws IOException {
+ app = out;
+ return this;
+ }
+
+ public Appendable append(char c) throws IOException {
+ if (digest != null) {
+ digest.update((byte) (c / 256));
+ digest.update((byte) (c % 256));
+ }
+ app.append(c);
+ return this;
+ }
+
+ public Appendable append(CharSequence sq) throws IOException {
+ return append(sq, 0, sq.length());
+ }
+
+ public Appendable append(CharSequence sq, int start, int length) throws IOException {
+ if (digest != null) {
+ for (int i = start; i < length; i++) {
+ char c = sq.charAt(i);
+ digest.update((byte) (c / 256));
+ digest.update((byte) (c % 256));
+ }
+ }
+ app.append(sq, start, length);
+ return this;
+ }
+
+ public String toString() {
+ return app.toString();
+ }
+
+ public void close() throws IOException {
+ if (app != null && app instanceof Closeable)
+ ((Closeable) app).close();
+ }
+
+ void encode(Object object, Type type, Map<Object, Type> visited) throws Exception {
+ codec.encode(this, object, type, visited);
+ }
+
+ public Encoder writeDefaults() {
+ writeDefaults = true;
+ return this;
+ }
+
+ public void flush() throws IOException {
+ if (app instanceof Flushable) {
+ ((Flushable) app).flush();
+ }
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Encoder.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Encoder.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/EnumHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/EnumHandler.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/EnumHandler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/EnumHandler.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,24 @@
+package aQute.lib.json;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+public class EnumHandler extends Handler {
+ @SuppressWarnings("rawtypes")
+ final Class type;
+
+ public EnumHandler(Class<?> type) {
+ this.type = type;
+ }
+
+ @Override void encode(Encoder app, Object object, Map<Object, Type> visited)
+ throws IOException, Exception {
+ StringHandler.string(app, object.toString());
+ }
+
+ @SuppressWarnings("unchecked") Object decode(String s) throws Exception {
+ return Enum.valueOf(type, s);
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/EnumHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/EnumHandler.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/FileHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/FileHandler.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/FileHandler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/FileHandler.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,38 @@
+package aQute.lib.json;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+import aQute.lib.base64.*;
+
+public class FileHandler extends Handler {
+
+ @Override void encode(Encoder app, Object object, Map<Object, Type> visited)
+ throws IOException, Exception {
+ File f = (File) object;
+ if ( !f.isFile())
+ throw new RuntimeException("Encoding a file requires the file to exist and to be a normal file " + f );
+
+ FileInputStream in = new FileInputStream(f);
+ try {
+ app.append('"');
+ Base64.encode(in, app);
+ app.append('"');
+ } finally {
+ in.close();
+ }
+ }
+
+ Object decode(String s) throws Exception {
+ File tmp = File.createTempFile("json", ".bin");
+ FileOutputStream fout = new FileOutputStream(tmp);
+ try {
+ Base64.decode(new StringReader(s), fout);
+ } finally {
+ fout.close();
+ }
+ return tmp;
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/FileHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/FileHandler.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Handler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Handler.java?rev=1347815&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Handler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Handler.java Thu Jun 7 21:57:32 2012
@@ -0,0 +1,35 @@
+package aQute.lib.json;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+abstract class Handler {
+ abstract void encode(Encoder app, Object object, Map<Object, Type> visited)
+ throws IOException, Exception;
+
+ Object decodeObject(Decoder isr) throws Exception {
+ throw new UnsupportedOperationException("Cannot be mapped to object " + this);
+ }
+
+ Object decodeArray(Decoder isr) throws Exception {
+ throw new UnsupportedOperationException("Cannot be mapped to array " + this);
+ }
+
+ Object decode(String s) throws Exception {
+ throw new UnsupportedOperationException("Cannot be mapped to string " + this);
+ }
+
+ Object decode(Number s) throws Exception {
+ throw new UnsupportedOperationException("Cannot be mapped to number " + this);
+ }
+
+ Object decode(boolean s) {
+ throw new UnsupportedOperationException("Cannot be mapped to boolean " + this);
+ }
+
+ Object decode() {
+ return null;
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Handler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/Handler.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision