@Override public Iterator<T> iterator() { final ArrayDeque<T> ts = new ArrayDeque<>(); SnocList<T> current = this; while (true) { ts.push(current.last); if (current.init.isPresent()) { current = current.init.get(); } else { break; } } return ts.iterator(); }
/** * Parse command line options. * * @param params command line parameters * @return -1 to proceed, otherwise process exit value */ public int parseOptions(ArrayDeque<String> params) { // Special logic to automate the demo when no flags are given if (params.isEmpty() && DEMO_XML_FILE.exists() && DEMO_SUBDIR.exists()) { params.add("--xml"); params.add(DEMO_XML_FILE.toString()); params.add("--classpath"); params.add(DEMO_SUBDIR.toString()); params.add("--model-pkg"); params.add("org.jsimpledb.demo"); final StringBuilder buf = new StringBuilder(); for (String param : params) buf.append(' ').append(param); System.err.println( this.getName() + ": automatically configuring demo database using the following flags:\n " + buf); } // Parse --classpath options prior to searching classpath for key/value implementations for (Iterator<String> i = params.iterator(); i.hasNext(); ) { final String param = i.next(); if (param.equals("-cp") || param.equals("--classpath")) { i.remove(); if (!i.hasNext()) this.usageError(); if (!this.appendClasspath(i.next())) return 1; i.remove(); } } // Parse (and remove) options supported by key/value implementations for (KVImplementation availableKVImplementation : KVImplementation.getImplementations()) { final Object config; try { config = availableKVImplementation.parseCommandLineOptions(params); } catch (IllegalArgumentException e) { System.err.println(this.getName() + ": " + (e.getMessage() != null ? e.getMessage() : e)); return 1; } if (config != null) this.kvConfigMap.put(availableKVImplementation, config); } // Parse options supported by this class final LinkedHashSet<String> modelPackages = new LinkedHashSet<>(); final LinkedHashSet<String> typePackages = new LinkedHashSet<>(); while (!params.isEmpty() && params.peekFirst().startsWith("-")) { final String option = params.removeFirst(); if (option.equals("-h") || option.equals("--help")) { this.usageMessage(); return 0; } else if (option.equals("-ro") || option.equals("--read-only")) this.readOnly = true; else if (option.equals("--verbose")) this.verbose = true; else if (option.equals("-v") || option.equals("--schema-version")) { if (params.isEmpty()) this.usageError(); final String vstring = params.removeFirst(); try { this.schemaVersion = Integer.parseInt(vstring); if (this.schemaVersion < 0) throw new IllegalArgumentException("schema version is negative"); } catch (Exception e) { System.err.println( this.getName() + ": invalid schema version `" + vstring + "': " + e.getMessage()); return 1; } } else if (option.equals("--model-pkg")) { if (params.isEmpty()) this.usageError(); modelPackages.add(params.removeFirst()); } else if (option.equals("--type-pkg")) { if (params.isEmpty()) this.usageError(); typePackages.add(params.removeFirst()); } else if (option.equals("-p") || option.equals("--pkg")) { if (params.isEmpty()) this.usageError(); final String packageName = params.removeFirst(); modelPackages.add(packageName); typePackages.add(packageName); } else if (option.equals("--new-schema")) this.allowNewSchema = true; else if (option.equals("--")) break; else if (!this.parseOption(option, params)) { System.err.println(this.getName() + ": unknown option `" + option + "'"); this.usageError(); return 1; } } // Decode what key/value implementations where specified and how they nest, if at all final Iterator<KVImplementation> i = this.kvConfigMap.keySet().iterator(); switch (this.kvConfigMap.size()) { case 0: System.err.println( this.getName() + ": no key/value database specified; use one of `--arraydb', etc."); this.usageError(); return 1; case 1: this.kvImplementation = i.next(); final Object config = this.kvConfigMap.get(this.kvImplementation); if (this.kvImplementation.requiresAtomicKVStore(config) || this.kvImplementation.requiresKVDatabase(config)) { System.err.println( this.getName() + ": " + this.kvImplementation.getDescription(config) + " requires the configuration of an underlying key/value technology; use one of `--arraydb', etc."); return 1; } break; case 2: // Put them in proper order: inner first, outer second final KVImplementation[] kvis = new KVImplementation[] {i.next(), i.next()}; final Object[] configs = new Object[] {this.kvConfigMap.get(kvis[0]), this.kvConfigMap.get(kvis[1])}; if (kvis[0].requiresAtomicKVStore(configs[0]) || kvis[0].requiresKVDatabase(configs[0])) { Collections.reverse(Arrays.asList(kvis)); Collections.reverse(Arrays.asList(configs)); } // Sanity check nesting requirements if ((kvis[0].requiresAtomicKVStore(configs[0]) || kvis[0].requiresKVDatabase(configs[0])) || !(kvis[1].requiresAtomicKVStore(configs[1]) || kvis[1].requiresKVDatabase(configs[1]))) { System.err.println( this.getName() + ": incompatible combination of " + kvis[0].getDescription(configs[0]) + " and " + kvis[1].getDescription(configs[1])); return 1; } // Nest them as required if (kvis[1].requiresAtomicKVStore(configs[1])) this.requiredAtomicKVStore = kvis[0]; else this.requiredKVDatabase = kvis[0]; this.kvImplementation = kvis[1]; break; default: System.err.println(this.getName() + ": too many key/value store(s) specified"); return 1; } // Scan for model and type classes final LinkedHashSet<String> emptyPackages = new LinkedHashSet<>(); emptyPackages.addAll(modelPackages); emptyPackages.addAll(typePackages); for (String packageName : modelPackages) { if (this.scanModelClasses(packageName) > 0) emptyPackages.remove(packageName); } for (String packageName : typePackages) { if (this.scanTypeClasses(packageName) > 0) emptyPackages.remove(packageName); } // Warn if we didn't find anything for (String packageName : emptyPackages) { final boolean isModel = modelPackages.contains(packageName); final boolean isType = typePackages.contains(packageName); if (isModel && isType) this.log.warn( "no Java model or custom FieldType classes found under package `" + packageName + "'"); else if (isModel) this.log.warn("no Java model classes found under package `" + packageName + "'"); else this.log.warn("no custom FieldType classes found under package `" + packageName + "'"); } // Done return -1; }