/* * eXist Open Source Native XML Database * Copyright (C) 2001-2011 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $Id$ */ package org.exist.client; import java.awt.Dimension; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.EOFException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.io.OutputStreamWriter; import java.io.PrintStream; import java.io.PushbackInputStream; import java.io.StreamTokenizer; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.lang.reflect.Field; import java.net.URISyntaxException; import java.net.URLDecoder; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Observable; import java.util.Observer; import java.util.Properties; import java.util.Random; import java.util.Set; import java.util.StringTokenizer; import java.util.TreeSet; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import jline.Completor; import jline.ConsoleReader; import jline.History; import jline.Terminal; import org.apache.avalon.excalibur.cli.CLArgsParser; import org.apache.avalon.excalibur.cli.CLOption; import org.apache.avalon.excalibur.cli.CLUtil; import org.apache.log4j.Logger; import org.exist.dom.XMLUtil; import org.exist.security.Permission; import org.exist.security.SecurityManager; import org.exist.security.User; import org.exist.storage.ElementIndex; import org.exist.storage.TextSearchEngine; import org.exist.util.CollectionScanner; import org.exist.util.ConfigurationHelper; import org.exist.util.DirectoryScanner; import org.exist.util.MimeTable; import org.exist.util.MimeType; import org.exist.util.Occurrences; import org.exist.util.ProgressBar; import org.exist.util.ProgressIndicator; import org.exist.util.GZIPInputSource; import org.exist.util.ZipEntryInputSource; import org.exist.util.serializer.SAXSerializer; import org.exist.util.serializer.SerializerPool; import org.exist.validation.service.ValidationService; import org.exist.xmldb.CollectionManagementServiceImpl; import org.exist.xmldb.DatabaseInstanceManager; import org.exist.xmldb.EXistResource; import org.exist.xmldb.ExtendedResource; import org.exist.xmldb.IndexQueryService; import org.exist.xmldb.UserManagementService; import org.exist.xmldb.XPathQueryServiceImpl; import org.exist.xmldb.XmldbURI; import org.exist.xquery.Constants; import org.exist.xquery.util.URIUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; import org.xmldb.api.DatabaseManager; import org.xmldb.api.base.Collection; import org.xmldb.api.base.Database; import org.xmldb.api.base.Resource; import org.xmldb.api.base.ResourceSet; import org.xmldb.api.base.XMLDBException; import org.xmldb.api.modules.BinaryResource; import org.xmldb.api.modules.XPathQueryService; import org.xmldb.api.modules.XUpdateQueryService; /** * Command-line client based on the XML:DB API. * * @author wolf */ public class InteractiveClient { // ANSI colors for ls display // private final static String ANSI_BLUE = "\033[0;34m"; private final static String ANSI_CYAN = "\033[0;36m"; private final static String ANSI_WHITE = "\033[0;37m"; // properties // keys public static final String USER="user"; public static final String PASSWORD="password"; public static final String URI="uri"; public static final String CONFIGURATION="configuration"; public static final String DRIVER="driver"; // values protected static String EDIT_CMD = "emacsclient -t $file"; protected static String ENCODING = "ISO-8859-1"; protected static String PASS = null; protected static String URI_DEFAULT = "xmldb:exist://localhost:8080/exist/xmlrpc"; protected static String USER_DEFAULT = SecurityManager.DBA_USER; protected static int PARALLEL_THREADS = 5; // Set protected static Properties defaultProps = new Properties(); { defaultProps.setProperty(DRIVER, driver); defaultProps.setProperty(URI, URI_DEFAULT); defaultProps.setProperty(USER, USER_DEFAULT); defaultProps.setProperty("editor", EDIT_CMD); defaultProps.setProperty("indent", "true"); defaultProps.setProperty("encoding", ENCODING); defaultProps.setProperty("colors", "false"); defaultProps.setProperty("permissions", "false"); defaultProps.setProperty("expand-xincludes", "true"); } protected static final int colSizes[] = new int[]{10, 10, 10, -1}; protected static String driver = "org.exist.xmldb.DatabaseImpl"; protected static String configuration = null; protected TreeSet completitions = new TreeSet(); protected LinkedList queryHistory = new LinkedList(); protected File queryHistoryFile; protected File historyFile; protected ConsoleReader console = null; protected Collection current = null; protected int nextInSet = 1; protected int maxResults = 10; protected XmldbURI path = XmldbURI.ROOT_COLLECTION_URI; protected Properties properties; protected String[] resources = null; protected ResourceSet result = null; protected HashMap namespaceMappings = new HashMap(); /** number of files of a recursive store */ protected int filesCount = 0; /** total length of a recursive store */ protected long totalLength =0; protected boolean quiet = false; protected boolean verbose = false; /** default recursive, maybe override by client.properties */ protected boolean recurseDirs = true; protected boolean startGUI = true; protected Writer traceWriter = null; protected ClientFrame frame; private static Logger LOG = Logger.getLogger(InteractiveClient.class.getName()); public InteractiveClient() { } /** Display help on commands */ protected void displayHelp() { messageln("--- general commands ---"); messageln("ls list collection contents"); messageln("cd [collection|..] change current collection"); messageln("put [file pattern] upload file or directory" + " to the database"); messageln("putgz [file pattern] upload possibly gzip compressed file or directory" + " to the database"); messageln("putzip [file pattern] upload the contents of a ZIP archive" + " to the database"); messageln("edit [resource] open the resource for editing"); messageln("mkcol collection create new sub-collection in " + "current collection"); messageln("rm document remove document from current " + "collection"); messageln("rmcol collection remove collection"); messageln("set [key=value] set property. Calling set without "); messageln(" argument shows current settings."); messageln("validate [document] validate xml document with system xml catalog."); messageln("validate [document] [grammar] validate xml document with "); messageln(" specified grammar document."); messageln("\n--- search commands ---"); messageln("find xpath-expr execute the given XPath expression."); messageln("show [position] display query result value at position."); messageln("\n--- user management (may require dba rights) ---"); messageln("users list existing users."); messageln("adduser username create a new user."); messageln("passwd username change password for user. "); messageln("chown user group [resource]"); messageln(" change resource ownership. chown without"); messageln(" resource changes ownership of the current"); messageln(" collection."); messageln("chmod [resource] permissions"); messageln(" change resource permissions. Format:"); messageln(" [user|group|other]=[+|-][read|write|update]."); messageln(" chmod without resource changes permissions for"); messageln(" the current collection."); messageln("lock resource put a write lock on the specified resource."); messageln("unlock resource remove a write lock from the specified resource."); messageln("quit quit the program"); } /** * The main program for the InteractiveClient class. * * @param args * The command line arguments */ public static void main(String[] args) { try { InteractiveClient client = new InteractiveClient(); if (!client.run(args)) System.exit(1); // return non-zero exit status on failure } catch (Exception e) { e.printStackTrace(); System.exit(1); // return non-zero exit status on exception } } /** * Register XML:DB driver and retrieve root collection. * * @exception Exception Description of the Exception */ protected void connect() throws Exception { if (startGUI && frame != null) frame.setStatus("connecting to " + properties.getProperty("uri")); Class cl = Class.forName(properties.getProperty(DRIVER)); Database database = (Database) cl.newInstance(); database.setProperty("create-database", "true"); // secure empty configuration String configuration=properties.getProperty("configuration"); if (configuration != null && !"".equals(configuration)) database.setProperty("configuration", configuration); DatabaseManager.registerDatabase(database); current = DatabaseManager.getCollection(properties.getProperty("uri") + path, properties.getProperty("user"), properties .getProperty("password")); if (startGUI && frame != null) frame.setStatus("connected to " + properties.getProperty("uri") + " as user " + properties.getProperty("user")); } /** * Returns the current collection. * * @return the current collection */ protected Collection getCollection() { return current; } protected void reloadCollection() throws XMLDBException { current = DatabaseManager.getCollection(properties.getProperty("uri") + path, properties.getProperty("user"), properties.getProperty("password")); getResources(); } protected void setProperties() throws XMLDBException { String key; for(Iterator i = properties.keySet().iterator(); i.hasNext(); ) { key = (String)i.next(); current.setProperty(key, properties.getProperty(key)); } } /** * Get list of resources contained in collection. * * @exception XMLDBException * Description of the Exception */ protected void getResources() throws XMLDBException { if (current == null) return; setProperties(); UserManagementService mgtService = (UserManagementService) current .getService("UserManagementService", "1.0"); String childCollections[] = current.listChildCollections(); String childResources[] = current.listResources(); resources = new String[childCollections.length + childResources.length]; int i = 0; Collection child; Permission perm; List tableData = new ArrayList(resources.length); // A list of ResourceDescriptor for the GUI String cols[] = new String[4]; for (; i < childCollections.length; i++) { child = current.getChildCollection(childCollections[i]); perm = mgtService.getPermissions(child); if (properties.getProperty("permissions").equals("true")) { cols[0] = perm.toString(); cols[1] = perm.getOwner(); cols[2] = perm.getOwnerGroup(); cols[3] = URIUtils.urlDecodeUtf8(childCollections[i]); resources[i] = 'd' + formatString(cols, colSizes); } else resources[i] = URIUtils.urlDecodeUtf8(childCollections[i]); if (startGUI) { tableData.add( new ResourceDescriptor.Collection( XmldbURI.create(childCollections[i]), perm.getOwner(), perm.getOwnerGroup(), perm.toString(), null /*lastModificationTime*/ ) ); } completitions.add(childCollections[i]); } Resource res; for (int j = 0; j < childResources.length; i++, j++) { res = current.getResource(childResources[j]); perm = mgtService.getPermissions(res); if (perm == null) System.out.println("null"); if (properties.getProperty("permissions").equals("true")) { resources[i] = '-' + perm.toString() + '\t' + perm.getOwner() + '\t' + perm.getOwnerGroup() + '\t' + URIUtils.urlDecodeUtf8(childResources[j]); } else resources[i] = URIUtils.urlDecodeUtf8(childResources[j]); Date lastModificationTime = ((EXistResource)res).getLastModificationTime(); resources[i] += "\t" + lastModificationTime; if (startGUI) { tableData.add(new ResourceDescriptor.Document( XmldbURI.create(childResources[j]), perm.getOwner(), perm.getOwnerGroup(), perm.toString(), lastModificationTime ) ); } completitions.add(childResources[j]); } if (startGUI) frame.setResources(tableData); } /** * Display document on screen, by 24 lines. * * @param str string containing the document. */ protected void more(String str) { LineNumberReader reader = new LineNumberReader(new StringReader(str)); String line; // int count = 0; int ch; try { while (System.in.available() > 0) System.in.read(); while ((line = reader.readLine()) != null) { if (reader.getLineNumber() % 24 == 0) { System.out.print("line: " + reader.getLineNumber() + "; press [return] for more or [q] for quit."); ch = System.in.read(); if (ch == 'q' || ch == 'Q') return; } System.out.println(line); } } catch (IOException ioe) { System.err.println("IOException: " + ioe); } } /** * In interactive mode, process a line entered by the user. * * @param line the line entered * @return true if command != quit */ protected boolean process(String line) { if (startGUI) frame.setPath(path); String args[]; if (line.startsWith("find")) { args = new String[2]; args[0] = "find"; args[1] = line.substring(5); } else { StreamTokenizer tok = new StreamTokenizer(new StringReader(line)); tok.resetSyntax(); tok.wordChars(0x21, 0x7FFF); tok.quoteChar('"'); tok.whitespaceChars(0x20, 0x20); List argList = new ArrayList(3); // int i = 0; int token; try { while ((token = tok.nextToken()) != StreamTokenizer.TT_EOF) { if (token == StreamTokenizer.TT_WORD || token == '"') { argList.add(tok.sval); } } } catch (IOException e) { System.err.println("Could not parse command line."); return true; } args = new String[argList.size()]; argList.toArray(args); } if (args.length == 0) return true; try { XmldbURI newPath = path; XmldbURI currUri = XmldbURI.xmldbUriFor(properties.getProperty("uri")).resolveCollectionPath(path); if (args[0].equalsIgnoreCase("ls")) { // list collection contents getResources(); if (properties.getProperty("permissions").equals("true")) { for (int i = 0; i < resources.length; i++) messageln(resources[i]); } else { StringBuilder buf; for (int i = 0; i < resources.length; i++) { buf = new StringBuilder(); int k = 0; for (int j = 0; i < resources.length && j < 5; i++, j++) { buf.append(resources[i] + '\t'); k = j; } if (k == 4 && i < resources.length) i--; messageln(buf.toString()); } } } else if (args[0].equalsIgnoreCase("cd")) { // change current collection completitions.clear(); Collection temp; XmldbURI collectionPath; if (args.length < 2 || args[1] == null) { collectionPath = XmldbURI.ROOT_COLLECTION_URI; } else { collectionPath = XmldbURI.xmldbUriFor(URIUtils.urlEncodeUtf8(args[1])); } collectionPath = currUri.resolveCollectionPath(collectionPath); if(collectionPath.numSegments()==0) { collectionPath = currUri.resolveCollectionPath(XmldbURI.ROOT_COLLECTION_URI); messageln("cannot go above "+XmldbURI.ROOT_COLLECTION_URI.toString()); } temp = DatabaseManager.getCollection( collectionPath.toString(), properties.getProperty("user"), properties.getProperty("password")); if (temp != null) { current = temp; newPath = collectionPath.toCollectionPathURI(); if (startGUI) frame.setPath(collectionPath.toCollectionPathURI()); } else { messageln("no such collection."); } getResources(); } else if (args[0].equalsIgnoreCase("cp")) { if (args.length != 3) { messageln("cp requires two arguments."); return true; } XmldbURI src,dest; try { src = URIUtils.encodeXmldbUriFor(args[1]); dest = URIUtils.encodeXmldbUriFor(args[2]); } catch(URISyntaxException e) { errorln("could not parse collection name into a valid URI: "+e.getMessage()); return false; } copy(src,dest); getResources(); } else if (args[0].equalsIgnoreCase("edit")) { if (args.length == 2) { XmldbURI resource; try { resource = URIUtils.encodeXmldbUriFor(args[1]); } catch(URISyntaxException e) { errorln("could not parse resource name into a valid URI: "+e.getMessage()); return false; } editResource(resource); } else { messageln("Please specify a resource."); } } else if (args[0].equalsIgnoreCase("get")) { if (args.length < 2) { System.err.println("wrong number of arguments."); return true; } XmldbURI resource; try { resource = URIUtils.encodeXmldbUriFor(args[1]); } catch(URISyntaxException e) { errorln("could not parse resource name into a valid URI: "+e.getMessage()); return false; } Resource res = retrieve(resource); // display document if (res != null) { String data; if (res.getResourceType().equals("XMLResource")) data = (String) res.getContent(); else data = new String((byte[]) res.getContent()); if (startGUI) { frame.setEditable(false); frame.display(data); frame.setEditable(true); } else { String content = data; more(content); } } return true; } else if (args[0].equalsIgnoreCase("find")) { // search if (args.length < 2) { messageln("no query argument found."); return true; } messageln(args[1]); long start = System.currentTimeMillis(); result = find(args[1]); if (result == null) messageln("nothing found"); else messageln("found " + result.getSize() + " hits in " + (System.currentTimeMillis() - start) + "ms."); nextInSet = 1; } else if (args[0].equalsIgnoreCase("run")) { if (args.length < 2) { messageln("please specify a query file."); return true; } try { BufferedReader reader = new BufferedReader(new FileReader( args[1])); StringBuilder buf = new StringBuilder(); String nextLine; while ((nextLine = reader.readLine()) != null) { buf.append(nextLine); buf.append('\n'); } args[1] = buf.toString(); long start = System.currentTimeMillis(); result = find(args[1]); if (result == null) messageln("nothing found"); else messageln("found " + result.getSize() + " hits in " + (System.currentTimeMillis() - start) + "ms."); nextInSet = 1; } catch (Exception e) { errorln("An error occurred: " + e.getMessage()); } } else if (args[0].equalsIgnoreCase("show")) { // show search results if (result == null) { messageln("no result set."); return true; } try { int start = nextInSet; int count = 1; if (args.length > 1) start = Integer.parseInt(args[1]); if (args.length > 2) count = Integer.parseInt(args[2]); final int s = (int) result.getSize(); if (start < 1 || start > s) { messageln("start offset out of range"); return true; } --start; if (start + count > s) count = s - start; nextInSet = start + count + 1; for (int i = start; i < start + count; i++) { Resource r = result.getResource(i); if (startGUI) frame.display((String) r.getContent()); else more((String) r.getContent()); } messageln("displayed items " + (start + 1) + " to " + (start + count) + " of " + result.getSize()); } catch (NumberFormatException nfe) { errorln("wrong argument"); return true; } } else if (args[0].equalsIgnoreCase("mkcol")) { // create collection if (args.length < 2) { messageln("missing argument."); return true; } XmldbURI collUri; try { collUri = URIUtils.encodeXmldbUriFor(args[1]); } catch(URISyntaxException e) { errorln("could not parse collection name into a valid URI: "+e.getMessage()); return false; } CollectionManagementServiceImpl mgtService = (CollectionManagementServiceImpl) current .getService("CollectionManagementService", "1.0"); Collection newCollection = mgtService.createCollection(collUri); if (newCollection == null) messageln("could not create collection."); else messageln("created collection."); // re-read current collection current = DatabaseManager.getCollection(properties .getProperty("uri") + path, properties.getProperty("user"), properties .getProperty("password")); getResources(); } else if (args[0].equalsIgnoreCase("put")) { // put a document or directory into the database if (args.length < 2) { messageln("missing argument."); return true; } boolean r = parse(args[1]); getResources(); return r; } else if (args[0].equalsIgnoreCase("putzip")) { // put the contents of a zip archive into the database if (args.length < 2) { messageln("missing argument."); return true; } boolean r = parseZip(args[1]); getResources(); return r; } else if (args[0].equalsIgnoreCase("putgz")) { // put the contents of a zip archive into the database if (args.length < 2) { messageln("missing argument."); return true; } boolean r = parseGZip(args[1]); getResources(); return r; } else if (args[0].equalsIgnoreCase("blob")) { // put a document or directory into the database if (args.length < 2) { messageln("missing argument."); return true; } storeBinary(args[1]); getResources(); } else if (args[0].equalsIgnoreCase("rm")) { // remove document if (args.length < 2) { messageln("missing argument."); return true; } remove(args[1]); // re-read current collection current = DatabaseManager.getCollection(properties .getProperty("uri") + path, properties.getProperty("user"), properties .getProperty("password")); getResources(); } else if (args[0].equalsIgnoreCase("rmcol")) { // remove collection if (args.length < 2) { messageln("wrong argument count."); return true; } XmldbURI collUri; try { collUri = URIUtils.encodeXmldbUriFor(args[1]); } catch(URISyntaxException e) { errorln("could not parse collection name into a valid URI: "+e.getMessage()); return false; } rmcol(collUri); // re-read current collection current = DatabaseManager.getCollection(properties .getProperty("uri") + path, properties.getProperty("user"), properties .getProperty("password")); getResources(); } else if (args[0].equalsIgnoreCase("adduser")) { if (args.length < 2) { System.err.println("Usage: adduser name"); return true; } if (startGUI) { messageln("command not supported in GUI mode. Please use the \"Edit users\" menu option."); return true; } try { UserManagementService mgtService = (UserManagementService) current .getService("UserManagementService", "1.0"); String p1; String p2; while (true) { p1 = console.readLine("password: ", new Character('*')); p2 = console.readLine("re-enter password: ", new Character('*')); if (p1.equals(p2)) break; System.out.println("\nentered passwords differ. Try again..."); } String home = console.readLine("home collection [none]: "); User user = new User(args[1], p1); if (home != null && home.length() > 0) { user.setHome(URIUtils.encodeXmldbUriFor(home)); } String groups = console.readLine("enter groups: "); StringTokenizer tok = new StringTokenizer(groups, " ,"); String group; while (tok.hasMoreTokens()) { group = tok.nextToken(); if (group.length() > 0) user.addGroup(group); } mgtService.addUser(user); System.out.println("user " + user + " created."); } catch (Exception e) { System.out.println("ERROR: " + e.getMessage()); e.printStackTrace(); } } else if (args[0].equalsIgnoreCase("users")) { UserManagementService mgtService = (UserManagementService) current .getService("UserManagementService", "1.0"); User users[] = mgtService.getUsers(); System.out.println("User\t\tGroups"); System.out.println("-----------------------------------------"); for (int i = 0; i < users.length; i++) { System.out.print(users[i].getName() + "\t\t"); String[] groups = users[i].getGroups(); for (int j = 0; j < groups.length; j++) { System.out.print(groups[j]); if (j + 1< groups.length) System.out.print(", "); } System.out.println(); } } else if (args[0].equalsIgnoreCase("passwd")) { if (startGUI) { messageln("command not supported in GUI mode. Please use the \"Edit users\" menu option."); return true; } if (args.length < 2) { System.out.println("Usage: passwd username"); return true; } try { UserManagementService mgtService = (UserManagementService) current .getService("UserManagementService", "1.0"); User user = mgtService.getUser(args[1]); if (user == null) { System.out.println("no such user."); return true; } String p1; String p2; while (true) { p1 = console.readLine("password: ", new Character('*')); p2 = console.readLine("re-enter password: ", new Character('*')); if (p1.equals(p2)) break; System.out.println("\nentered passwords differ. Try again..."); } user.setPassword(p1); mgtService.updateUser(user); properties.setProperty("password", p1); } catch (Exception e) { System.err.println("ERROR: " + e.getMessage()); } } else if (args[0].equalsIgnoreCase("chmod")) { if (args.length < 2) { System.out.println("Usage: chmod [resource] mode"); return true; } Collection temp = null; if (args.length == 3) { System.out.println("trying collection: " + args[1]); temp = current.getChildCollection(args[1]); if (temp == null) { System.out.println("\ntrying resource: " + args[1]); Resource r = current.getResource(args[1]); if (r != null) { UserManagementService mgtService = (UserManagementService) current .getService("UserManagementService", "1.0"); mgtService.chmod(r, args[2]); } else System.err.println("Resource " + args[1] + " not found."); } else { UserManagementService mgtService = (UserManagementService) temp .getService("UserManagementService", "1.0"); mgtService.chmod(args[2]); } } else { UserManagementService mgtService = (UserManagementService) current .getService("UserManagementService", "1.0"); mgtService.chmod(args[1]); } // re-read current collection current = DatabaseManager.getCollection(properties .getProperty("uri") + path, properties.getProperty("user"), properties .getProperty("password")); getResources(); } else if (args[0].equalsIgnoreCase("chown")) { if (args.length < 3) { System.out .println("Usage: chown username group [resource]"); return true; } Collection temp; if (args.length == 4) temp = current.getChildCollection(args[3]); else temp = current; if (temp != null) { UserManagementService mgtService = (UserManagementService) temp .getService("UserManagementService", "1.0"); User u = mgtService.getUser(args[1]); if (u == null) { System.out.println("unknown user"); return true; } mgtService.chown(u, args[2]); System.out.println("owner changed."); getResources(); return true; } Resource res = current.getResource(args[3]); if (res != null) { UserManagementService mgtService = (UserManagementService) current .getService("UserManagementService", "1.0"); User u = mgtService.getUser(args[1]); if (u == null) { System.out.println("unknown user"); return true; } mgtService.chown(res, u, args[2]); getResources(); return true; } System.err.println("Resource " + args[3] + " not found."); } else if (args[0].equalsIgnoreCase("lock") || args[0].equalsIgnoreCase("unlock")) { if(args.length < 2) { messageln("Usage: lock resource"); return true; } Resource res = current.getResource(args[1]); if (res != null) { UserManagementService mgtService = (UserManagementService) current.getService("UserManagementService", "1.0"); User user = mgtService.getUser(properties.getProperty("user", "guest")); if(args[0].equalsIgnoreCase("lock")) mgtService.lockResource(res, user); else mgtService.unlockResource(res); } } else if (args[0].equalsIgnoreCase("elements")) { System.out.println("Element occurrences in collection " + current.getName()); System.out .println("--------------------------------------------" + "-----------"); IndexQueryService service = (IndexQueryService) current .getService("IndexQueryService", "1.0"); Occurrences[] elements = service.getIndexedElements(true); for (int i = 0; i < elements.length; i++) { System.out .println(formatString(elements[i].getTerm().toString(), Integer.toString(elements[i] .getOccurrences()), 50)); } return true; } else if (args[0].equalsIgnoreCase("terms")) { if (args.length < 3) { System.out .println("Usage: terms [xpath] sequence-start sequence-end"); return true; } IndexQueryService service = (IndexQueryService) current .getService("IndexQueryService", "1.0"); Occurrences[] terms; if (args.length == 3) terms = service.scanIndexTerms(args[1], args[2], true); else terms = service.scanIndexTerms(args[1], args[2], args[3]); System.out.println("Element occurrences in collection " + current.getName()); System.out .println("--------------------------------------------" + "-----------"); for (int i = 0; i < terms.length; i++) { System.out.println(formatString(terms[i].getTerm().toString(), Integer .toString(terms[i].getOccurrences()), 50)); } } else if (args[0].equalsIgnoreCase("xupdate")) { if (startGUI) { messageln("command not supported in GUI mode."); return true; } String lastLine, command = ""; try { while (true) { lastLine = console.readLine("| "); if (lastLine == null || lastLine.length() == 0) break; command += lastLine; } } catch (EOFException e) { } catch (IOException e) { } String xupdate = "<xu:modifications version=\"1.0\" " + "xmlns:xu=\"http://www.xmldb.org/xupdate\">" + command + "</xu:modifications>"; XUpdateQueryService service = (XUpdateQueryService) current .getService("XUpdateQueryService", "1.0"); long mods = service.update(xupdate); System.out.println(mods + " modifications processed."); } else if (args[0].equalsIgnoreCase("map")) { StringTokenizer tok = new StringTokenizer(args[1], "= "); String prefix; if (args[1].startsWith("=")) prefix = ""; else { if (tok.countTokens() < 2) { messageln("please specify a namespace/prefix mapping as: prefix=namespaceURI"); return true; } prefix = tok.nextToken(); } String uri = tok.nextToken(); namespaceMappings.put(prefix, uri); } else if (args[0].equalsIgnoreCase("set")) { if (args.length == 1) properties.list(System.out); else try { StringTokenizer tok = new StringTokenizer(args[1], "= "); if (tok.countTokens() < 2) { System.err .println("please specify a key=value pair"); return true; } String key = tok.nextToken(); String val = tok.nextToken(); properties.setProperty(key, val); current.setProperty(key, val); getResources(); } catch (Exception e) { System.err.println("Exception: " + e.getMessage()); } } else if (args[0].equalsIgnoreCase("shutdown")) { DatabaseInstanceManager mgr = (DatabaseInstanceManager) current .getService("DatabaseInstanceManager", "1.0"); if (mgr == null) { messageln("Service is not available"); return true; } mgr.shutdown(); return true; } else if (args[0].equalsIgnoreCase("help") || args[0].equals("?")) displayHelp(); else if (args[0].equalsIgnoreCase("quit")) { return false; } else if (args[0].equalsIgnoreCase("validate")) { if (args.length < 2) messageln("missing document name."); else { ValidationService validationService = (ValidationService) current.getService("ValidationService", "1.0"); boolean valid=false; if(args.length==2){ valid=validationService.validateResource(args[1]); } else { valid=validationService.validateResource(args[1], args[2]); } if (valid){ messageln("document is valid."); } else { messageln("document is not valid."); } } } else { messageln("unknown command"); return true; } path = newPath; return true; } catch (Throwable e) { if (startGUI) ClientFrame.showErrorMessage(getExceptionMessage(e), e); else { errorln(getExceptionMessage(e)); e.printStackTrace(); } return true; } } /** * @param args */ private void editResource(XmldbURI name) { try { DocumentView view = new DocumentView(this, name, properties); view.setSize(new Dimension(640, 400)); view.viewDocument(); } catch (XMLDBException ex) { errorln("XMLDB error: " + ex.getMessage()); } } private final ResourceSet find(String xpath) throws XMLDBException { if (xpath.charAt(xpath.length() - 1) == '\n') xpath = xpath.substring(0, xpath.length() - 1); if (traceWriter != null) try { traceWriter.write("<query>"); traceWriter.write(xpath); traceWriter.write("</query>\r\n"); } catch (IOException e) { } String sortBy = null; int p = xpath.indexOf(" sort by "); if (p != Constants.STRING_NOT_FOUND) { String xp = xpath.substring(0, p); sortBy = xpath.substring(p + " sort by ".length()); xpath = xp; System.out.println("XPath = " + xpath); System.out.println("Sort-by = " + sortBy); } XPathQueryServiceImpl service = (XPathQueryServiceImpl) current .getService("XPathQueryService", "1.0"); service .setProperty(OutputKeys.INDENT, properties .getProperty("indent")); service.setProperty(OutputKeys.ENCODING, properties .getProperty("encoding")); Map.Entry mapping; for (Iterator i = namespaceMappings.entrySet().iterator(); i.hasNext(); ) { mapping = (Map.Entry) i.next(); service.setNamespace((String) mapping.getKey(), (String) mapping .getValue()); } return (sortBy == null) ? service.query(xpath) : service.query(xpath, sortBy); } /** unused, for testing purposes ?? */ private final void testQuery(String queryFile) { try { File f = new File(queryFile); if (!f.canRead()) { System.err.println("can't read query file: " + queryFile); return; } BufferedReader reader = new BufferedReader(new FileReader(f)); String line; ArrayList queries = new ArrayList(10); QueryThread thread = null; while ((line = reader.readLine()) != null) queries.add(line); for (int i = 0; i < PARALLEL_THREADS; i++) { thread = new QueryThread(queries); thread.setName("QueryThread" + i); thread.start(); } try { thread.join(); } catch (InterruptedException e) { } } catch (FileNotFoundException e) { System.err.println("ERROR: " + e); } catch (IOException e) { System.err.println("ERROR: " + e); } } private class QueryThread extends Thread { ArrayList queries; public QueryThread(ArrayList queries) { this.queries = queries; } public void run() { try { // Collection collection = DatabaseManager.getCollection( properties.getProperty("uri") + path, properties.getProperty("user"), properties.getProperty("password")); XPathQueryService service = (XPathQueryService) current .getService("XPathQueryService", "1.0"); service.setProperty(OutputKeys.INDENT, "yes"); service.setProperty(OutputKeys.ENCODING, properties.getProperty("encoding")); Random r = new Random(System.currentTimeMillis()); String query; for (int i = 0; i < 10; i++) { query = (String) queries.get(r.nextInt(queries.size())); System.out.println(getName() + " query: " + query); ResourceSet result = service.query(query); System.out.println(getName() + " found: " + result.getSize()); } } catch (XMLDBException e) { System.err.println("ERROR: " + e.getMessage()); } System.out.println(getName() + " finished."); } } protected final Resource retrieve(XmldbURI resource) throws XMLDBException { return retrieve(resource, properties.getProperty("indent")); } protected final Resource retrieve(XmldbURI resource, String indent) throws XMLDBException { Resource res = current.getResource(resource.toString()); if (res == null) { messageln("document not found."); return null; } return res; } private final void remove(String pattern) throws XMLDBException { Collection collection = current; if (pattern.startsWith("/")) { System.err .println("path pattern should be relative to current collection"); return; } Resource resources[]; Resource res = collection.getResource(pattern); if (res == null) resources = CollectionScanner.scan(collection, "", pattern); else { resources = new Resource[1]; resources[0] = res; } Collection parent; for (int i = 0; i < resources.length; i++) { message("removing document " + resources[i].getId() + " ..."); parent = resources[i].getParentCollection(); parent.removeResource(resources[i]); messageln("done."); } } private final void xupdate(String resource, String filename) throws XMLDBException, IOException { File file = new File(filename); if (!(file.exists() && file.canRead())) { messageln("cannot read file " + filename); return; } String commands = XMLUtil.readFile(file, "UTF-8"); XUpdateQueryService service = (XUpdateQueryService) current.getService( "XUpdateQueryService", "1.0"); long modifications = 0; if (resource == null) modifications = service.update(commands); else modifications = service.updateResource(resource, commands); messageln(modifications + " modifications processed " + "successfully."); } private final void rmcol(XmldbURI collection) throws XMLDBException { CollectionManagementServiceImpl mgtService = (CollectionManagementServiceImpl) current .getService("CollectionManagementService", "1.0"); message("removing collection " + collection + " ..."); mgtService.removeCollection(collection); messageln("done."); } private final void copy(XmldbURI source, XmldbURI destination) throws XMLDBException { CollectionManagementServiceImpl mgtService = (CollectionManagementServiceImpl) current.getService("CollectionManagementService", "1.0"); XmldbURI destName = destination.lastSegment(); Collection destCol = resolveCollection(destination); if(destCol == null) { if(destination.numSegments()==1) { destination = XmldbURI.create(current.getName()); } else { destination = destination.removeLastSegment(); } } Resource srcDoc = resolveResource(source); if(srcDoc != null) { XmldbURI resourcePath = XmldbURI.create(srcDoc.getParentCollection().getName()).append(srcDoc.getId()); messageln("Copying resource '" + resourcePath + "' to '" + destination + "'"); mgtService.copyResource(resourcePath, destination, destName); } else { messageln("Copying collection '" + source + "' to '" + destination + "'"); mgtService.copy(source, destination, destName); } } private final void reindex() throws XMLDBException { IndexQueryService service = (IndexQueryService) current.getService("IndexQueryService", "1.0"); message("reindexing collection " + current.getName()); service.reindexCollection(); messageln("done."); } private final void storeBinary(String fileName) throws XMLDBException { File file = new File(fileName); if (file.canRead()) { MimeType mime = MimeTable.getInstance().getContentTypeFor(file.getName()); BinaryResource resource = (BinaryResource) current.createResource( file.getName(), "BinaryResource"); resource.setContent(file); ((EXistResource)resource).setMimeType(mime == null ? "application/octet-stream" : mime.getName()); current.storeResource(resource); } } private synchronized boolean findRecursive(Collection collection, File dir, XmldbURI base) throws XMLDBException { File files[] = dir.listFiles(); Collection c; Resource document; CollectionManagementServiceImpl mgtService; //The XmldbURIs here aren't really used... XmldbURI next; MimeType mimeType; for (int i = 0; i < files.length; i++) { next = base.append(files[i].getName()); try { if (files[i].isDirectory()) { messageln("entering directory " + files[i].getAbsolutePath()); c = collection.getChildCollection(files[i].getName()); if (c == null) { mgtService = (CollectionManagementServiceImpl) collection .getService("CollectionManagementService", "1.0"); c = mgtService.createCollection(URIUtils.encodeXmldbUriFor(files[i].getName())); } if (c instanceof Observable && verbose) { ProgressObserver observer = new ProgressObserver(); ((Observable) c).addObserver(observer); } findRecursive(c, files[i], next); } else { long start1 = System.currentTimeMillis(); mimeType = MimeTable.getInstance().getContentTypeFor(files[i].getName()); if(mimeType == null) { messageln("File " + files[i].getName() + " has an unknown " + "suffix. Cannot determine file type."); mimeType = MimeType.BINARY_TYPE; } message("storing document " + files[i].getName() + " (" + i + " of " + files.length + ") " + "..."); document = collection.createResource(URIUtils.urlEncodeUtf8(files[i] .getName()), mimeType.getXMLDBType()); document.setContent(files[i]); ((EXistResource)document).setMimeType(mimeType.getName()); collection.storeResource(document); ++filesCount; messageln(" " + files[i].length() + " bytes in " + (System.currentTimeMillis() - start1) + "ms."); } } catch (URISyntaxException e) { errorln("uri syntax exception parsing " + files[i].getAbsolutePath() + ": " + e.getMessage()); } } return true; } /** stores given Resource * @param fileName simple file or directory * @throws XMLDBException */ protected synchronized boolean parse(String fileName) throws XMLDBException { //TODO : why is this test for ? Fileshould make it, shouldn't it ? -pb fileName = fileName.replace('/', File.separatorChar).replace('\\', File.separatorChar); File file = new File(fileName); Resource document; // String xml; File files[]; if (current instanceof Observable && verbose) { ProgressObserver observer = new ProgressObserver(); ((Observable) current).addObserver(observer); } if (file.canRead()) { // TODO, same logic as for the graphic client if (file.isDirectory()) { if (recurseDirs) { filesCount = 0; long start = System.currentTimeMillis(); boolean result = findRecursive(current, file, path); messageln("storing " + filesCount + " files took " + ((System.currentTimeMillis() - start) / 1000) + "sec."); return result; } files = file.listFiles(); } else { files = new File[1]; files[0] = file; } } else files = DirectoryScanner.scanDir(fileName); long start; long start0 = System.currentTimeMillis(); long bytes = 0; MimeType mimeType; for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) continue; start = System.currentTimeMillis(); mimeType = MimeTable.getInstance().getContentTypeFor(files[i].getName()); if(mimeType == null) mimeType = MimeType.BINARY_TYPE; document = current.createResource(files[i].getName(), mimeType.getXMLDBType()); message("storing document " + files[i].getName() + " (" + (i + 1) + " of " + files.length + ") ..."); document.setContent(files[i]); ((EXistResource)document).setMimeType(mimeType.getName()); current.storeResource(document); messageln("done."); messageln("parsing " + files[i].length() + " bytes took " + (System.currentTimeMillis() - start) + "ms.\n"); bytes += files[i].length(); } messageln("parsed " + bytes + " bytes in " + (System.currentTimeMillis() - start0) + "ms."); return true; } private synchronized boolean findGZipRecursive(Collection collection, File dir, XmldbURI base) throws XMLDBException { File files[] = dir.listFiles(); Collection c; Resource document; CollectionManagementServiceImpl mgtService; //The XmldbURIs here aren't really used... XmldbURI next; MimeType mimeType; for (int i = 0; i < files.length; i++) { next = base.append(files[i].getName()); try { if (files[i].isDirectory()) { messageln("entering directory " + files[i].getAbsolutePath()); c = collection.getChildCollection(files[i].getName()); if (c == null) { mgtService = (CollectionManagementServiceImpl) collection .getService("CollectionManagementService", "1.0"); c = mgtService.createCollection(URIUtils.encodeXmldbUriFor(files[i].getName())); } if (c instanceof Observable && verbose) { ProgressObserver observer = new ProgressObserver(); ((Observable) c).addObserver(observer); } findGZipRecursive(c, files[i], next); } else { long start1 = System.currentTimeMillis(); String compressedName=files[i].getName(); String localName=compressedName; String[] cSuffix={".gz",".Z"}; boolean isCompressed=false; for(int isuf=0;isuf<cSuffix.length;isuf++) { String suf=cSuffix[isuf]; if(localName.endsWith(suf)) { // Removing compressed prefix to validate localName=compressedName.substring(0, localName.length()-suf.length()); isCompressed=true; break; } } mimeType = MimeTable.getInstance().getContentTypeFor(localName); if(mimeType == null) { messageln("File " + compressedName + " has an unknown " + "suffix. Cannot determine file type."); mimeType = MimeType.BINARY_TYPE; } message("storing document " + compressedName + " (" + i + " of " + files.length + ") " + "..."); document = collection.createResource(URIUtils.urlEncodeUtf8(compressedName), mimeType.getXMLDBType()); document.setContent(isCompressed?new GZIPInputSource(files[i]):files[i]); ((EXistResource)document).setMimeType(mimeType.getName()); collection.storeResource(document); ++filesCount; messageln(" " + files[i].length() + (isCompressed?" compressed":"") + " bytes in " + (System.currentTimeMillis() - start1) + "ms."); } } catch (URISyntaxException e) { errorln("uri syntax exception parsing " + files[i].getAbsolutePath() + ": " + e.getMessage()); } } return true; } /** stores given Resource * @param fileName simple file or directory * @throws XMLDBException */ protected synchronized boolean parseGZip(String fileName) throws XMLDBException { //TODO : why is this test for ? Fileshould make it, shouldn't it ? -pb fileName = fileName.replace('/', File.separatorChar).replace('\\', File.separatorChar); File file = new File(fileName); Resource document; // String xml; File files[]; if (current instanceof Observable && verbose) { ProgressObserver observer = new ProgressObserver(); ((Observable) current).addObserver(observer); } if (file.canRead()) { // TODO, same logic as for the graphic client if (file.isDirectory()) { if (recurseDirs) { filesCount = 0; long start = System.currentTimeMillis(); boolean result = findGZipRecursive(current, file, path); messageln("storing " + filesCount + " compressed files took " + ((System.currentTimeMillis() - start) / 1000) + "sec."); return result; } files = file.listFiles(); } else { files = new File[1]; files[0] = file; } } else files = DirectoryScanner.scanDir(fileName); long start; long start0 = System.currentTimeMillis(); long bytes = 0; MimeType mimeType; for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) continue; start = System.currentTimeMillis(); String compressedName=files[i].getName(); String localName=compressedName; String[] cSuffix={".gz",".Z"}; boolean isCompressed=false; for(int isuf=0;isuf<cSuffix.length;isuf++) { String suf=cSuffix[isuf]; if(localName.endsWith(suf)) { // Removing compressed prefix to validate localName=compressedName.substring(0, localName.length()-suf.length()); isCompressed=true; break; } } mimeType = MimeTable.getInstance().getContentTypeFor(localName); if(mimeType == null) mimeType = MimeType.BINARY_TYPE; document = current.createResource(compressedName,mimeType.getXMLDBType()); message("storing document " + compressedName + " (" + (i + 1) + " of " + files.length + ") ..."); document.setContent(isCompressed?new GZIPInputSource(files[i]):files[i]); ((EXistResource)document).setMimeType(mimeType.getName()); current.storeResource(document); messageln("done."); messageln("parsing " + files[i].length() + (isCompressed?" compressed":"") + " bytes took " + (System.currentTimeMillis() - start) + "ms.\n"); bytes += files[i].length(); } messageln("parsed " + bytes + " compressed bytes in " + (System.currentTimeMillis() - start0) + "ms."); return true; } /** stores given Resource * @param fileName simple file or directory * @throws XMLDBException */ protected synchronized boolean parseZip(String fileName) throws XMLDBException { fileName = fileName.replace('/', File.separatorChar).replace('\\', File.separatorChar); try { ZipFile zfile = new ZipFile(fileName); Resource document; // String xml; if (current instanceof Observable && verbose) { ProgressObserver observer = new ProgressObserver(); ((Observable) current).addObserver(observer); } long start; long start0 = System.currentTimeMillis(); long bytes = 0; MimeType mimeType; Enumeration e = zfile.entries(); int number=0; Collection base=current; String baseStr=""; while(e.hasMoreElements()) { number++; ZipEntry ze=(ZipEntry)e.nextElement(); String zeName=ze.getName().replace('\\','/'); String[] pathSteps=zeName.split("/"); String currStr=pathSteps[0]; for(int i=1;i<pathSteps.length-1;i++) { currStr += "/"+pathSteps[i]; } if(!baseStr.equals(currStr)) { base=current; for(int i=0;i<pathSteps.length-1;i++) { Collection c = base.getChildCollection(pathSteps[i]); if (c == null) { CollectionManagementServiceImpl mgtService = (CollectionManagementServiceImpl) base.getService("CollectionManagementService","1.0"); c = mgtService.createCollection(URIUtils.encodeXmldbUriFor(pathSteps[i])); } base=c; } if (base instanceof Observable && verbose) { ProgressObserver observer = new ProgressObserver(); ((Observable) base).addObserver(observer); } baseStr=currStr; messageln("entering directory " + baseStr); } if (!ze.isDirectory()) { String localName=pathSteps[pathSteps.length-1]; start = System.currentTimeMillis(); mimeType = MimeTable.getInstance().getContentTypeFor(localName); if(mimeType == null) mimeType = MimeType.BINARY_TYPE; document = base.createResource(localName,mimeType.getXMLDBType()); message("storing Zip-entry document " + localName + " (" + (number) + " of " + zfile.size() + ") ..."); document.setContent(new ZipEntryInputSource(zfile,ze)); ((EXistResource)document).setMimeType(mimeType.getName()); base.storeResource(document); messageln("done."); messageln("parsing " + ze.getSize() + " bytes took " + (System.currentTimeMillis() - start) + "ms.\n"); bytes += ze.getSize(); } } messageln("parsed " + bytes + " bytes in " + (System.currentTimeMillis() - start0) + "ms."); } catch (URISyntaxException e) { errorln("uri syntax exception parsing a ZIP entry from " + fileName + ": " + e.getMessage()); } catch (IOException e) { errorln("could not parse ZIP file " + fileName+": "+e.getMessage()); } return true; } /** * * Method called by the store Dialog * * @param files : selected * @param upload : GUI object * @throws XMLDBException */ protected synchronized boolean parse(File[] files, UploadDialog upload) throws XMLDBException { if (!upload.isVisible()) upload.setVisible(true); if (current instanceof Observable) { ((Observable) current).addObserver(upload.getObserver()); } upload.setTotalSize(calculateFileSizes(files)); for (int i = 0; i < files.length; i++) { if (upload.isCancelled()) break; // should replace the lines above store(current, files[i], upload); } if (current instanceof Observable) ((Observable) current).deleteObservers(); upload.uploadCompleted(); return true; } private long calculateFileSizes(File[] files) throws XMLDBException { long size = 0; for (int i = 0; i < files.length; i++) { if (!files[i].canRead()) continue; if (files[i].isDirectory()) size += calculateFileSizes(files[i].listFiles()); else size += files[i].length(); } return size; } /* * This is for a future GUI implementation of ZIP archive loads */ private long calculateFileSizes(ZipFile file) throws XMLDBException { Enumeration e = file.entries(); long size = 0; while(e.hasMoreElements()) { ZipEntry ze=(ZipEntry)e.nextElement(); if(!ze.isDirectory()) size += ze.getSize(); } return size; } /** * Pass to this method a java file object * (may be a file or a directory), GUI object * will create relative collections or resources * recursively */ private void store( Collection collection, File file, UploadDialog upload ) { // cancel, stop crawl if (upload.isCancelled()) return; // can't read there, inform client if (!file.canRead()) { upload.showMessage(file.getAbsolutePath()+ " impossible to read "); return; } XmldbURI filenameUri; try { filenameUri = URIUtils.encodeXmldbUriFor(file.getName()); } catch (URISyntaxException e1) { upload.showMessage(file.getAbsolutePath()+ " could not be encoded as a URI"); return; } // Directory, create collection, and crawl it if (file.isDirectory()) { Collection c=null; try { c = collection.getChildCollection(filenameUri.toString()); if (c == null) { CollectionManagementServiceImpl mgtService = (CollectionManagementServiceImpl) collection .getService("CollectionManagementService", "1.0"); c = mgtService.createCollection(filenameUri); } } catch (XMLDBException e) { upload.showMessage("Impossible to create a collection " + file.getAbsolutePath() + ": " + e.getMessage()); } // change displayed collection if it's OK upload.setCurrentDir(file.getAbsolutePath()); if (c instanceof Observable) { ((Observable) c).addObserver(upload.getObserver()); } // maybe a depth or recurs flag could be added here File temp[] = file.listFiles(); for (int i = 0; i < temp.length; i++) { store(c, temp[i], upload); } return; } // File, create and store resource if (file.isFile()) { upload.reset(); upload.setCurrent(file.getName()); upload.setCurrentSize(file.length()); MimeType mimeType = MimeTable.getInstance().getContentTypeFor(file.getName()); // unknown mime type, here prefered is to do nothing if(mimeType == null) { upload.showMessage(file.getAbsolutePath() + " - unknown suffix. No matching mime-type found in : " + MimeTable.getInstance().getSrc()); // if some one prefers to store it as binary by default, but dangerous mimeType = MimeType.BINARY_TYPE; } try { Resource res = collection.createResource( filenameUri.toString(), mimeType.getXMLDBType() ); ((EXistResource) res).setMimeType(mimeType.getName()); res.setContent(file); collection.storeResource(res); ++filesCount; this.totalLength += file.length(); upload.setStoredSize(this.totalLength); } catch (XMLDBException e) { upload.showMessage("Impossible to store a resource " + file.getAbsolutePath() + ": " + e.getMessage()); } } // should never arrive } private void mkcol(XmldbURI collPath) throws XMLDBException { messageln("creating '" + collPath + "'"); XmldbURI[] segments = collPath.getPathSegments(); CollectionManagementServiceImpl mgtService; Collection c; XmldbURI p = XmldbURI.ROOT_COLLECTION_URI; for(int i=1;i<segments.length;i++) { p = p.append(segments[i]); c = DatabaseManager.getCollection( properties.getProperty("uri") + p, properties.getProperty("user"), properties.getProperty("password")); if (c == null) { mgtService = (CollectionManagementServiceImpl) current.getService( "CollectionManagementService", "1.0"); current = mgtService.createCollection(segments[i]); } else current = c; } path = p; } protected Collection getCollection(String path) throws XMLDBException { return DatabaseManager.getCollection(properties.getProperty("uri") + path, properties.getProperty("user"), properties .getProperty("password")); } /** NEVER USED !!! Reads user password from given input stream. */ private char[] readPassword(InputStream in) throws IOException { char[] lineBuffer; char[] buf; // int i; buf = lineBuffer = new char[128]; int room = buf.length; int offset = 0; int c; loop : while (true) switch (c = in.read()) { case -1 : case '\n' : break loop; case '\r' : int c2 = in.read(); if ((c2 != '\n') && (c2 != -1)) { if (!(in instanceof PushbackInputStream)) in = new PushbackInputStream(in); ((PushbackInputStream) in).unread(c2); } else break loop; default : if (--room < 0) { buf = new char[offset + 128]; room = buf.length - offset - 1; System.arraycopy(lineBuffer, 0, buf, 0, offset); Arrays.fill(lineBuffer, ' '); lineBuffer = buf; } buf[offset++] = (char) c; break; } if (offset == 0) return null; char[] ret = new char[offset]; System.arraycopy(buf, 0, ret, 0, offset); Arrays.fill(buf, ' '); return ret; } private Properties loadClientProperties(){ Properties clientProps = new Properties(); File propFile = ConfigurationHelper.lookup("client.properties"); InputStream pin = null; // Try to load from file try{ pin = new FileInputStream(propFile); } catch (FileNotFoundException ex) { // File not found, no exception handling } if(pin == null){ // Try to load via classloader pin = InteractiveClient.class .getResourceAsStream("client.properties"); } if (pin != null){ // Try to load properties from stream try{ clientProps.load(pin); } catch (IOException ex) { // } } return clientProps; } /** * Parse command line options, store into dedicated object * @param args Arguments * @param props Client configuration * @return Object representing commandline parametres. */ protected CommandlineOptions getCommandlineOptions(String args[], Properties props){ // parse command-line options CLArgsParser optParser = new CLArgsParser(args, CommandlineOptions.OPTIONS); if (optParser.getErrorString() != null) { System.err.println("ERROR: " + optParser.getErrorString()); return null; } List opt = optParser.getArguments(); int size = opt.size(); CLOption option; CommandlineOptions cOpt = new CommandlineOptions(); for (int i = 0; i < size; i++) { option = (CLOption) opt.get(i); switch (option.getId()) { case CommandlineOptions.HELP_OPT : printUsage(); return null; case CommandlineOptions.NO_GUI_OPT : startGUI = false; break; // case CommandlineOptions.NO_EMBED_OPT : props.setProperty("NO_EMBED_MODE", "TRUE"); break; case CommandlineOptions.QUIET_OPT : quiet = true; break; case CommandlineOptions.VERBOSE_OPT : verbose = true; break; case CommandlineOptions.LOCAL_OPT : props.setProperty("uri", XmldbURI.EMBEDDED_SERVER_URI.toString()); break; case CommandlineOptions.USER_OPT : props.setProperty("user", option.getArgument()); if (!cOpt.passwdSpecified) cOpt.needPasswd = true; break; case CommandlineOptions.PASS_OPT : props.setProperty("password", option.getArgument()); cOpt.needPasswd = false; cOpt.passwdSpecified = true; break; case CommandlineOptions.CONFIG_OPT : properties.setProperty("configuration", option .getArgument()); break; case CommandlineOptions.COLLECTION_OPT : try { path = URIUtils.encodeXmldbUriFor(option.getArgument()); cOpt.foundCollection = true; } catch(URISyntaxException e) { System.err.println("Invalid collection path specified: "+e.getMessage()); return null; } break; case CommandlineOptions.RESOURCE_OPT : cOpt.optionResource = option.getArgument(); break; case CommandlineOptions.OUTPUT_FILE_OPT : cOpt.optionOutputFile = option.getArgument(); break; case CommandlineOptions.PARSE_OPT : cOpt.doStore = true; if (option.getArgumentCount() == 1) cOpt.optionalArgs.add(option.getArgument()); cOpt.interactive = false; break; case CommandlineOptions.RECURSE_DIRS_OPT : recurseDirs = true; break; case CommandlineOptions.REMOVE_OPT : cOpt.optionRemove = option.getArgument(); cOpt.interactive = false; break; case CommandlineOptions.GET_OPT : try { cOpt.optionGet = URIUtils.encodeXmldbUriFor(option.getArgument()); cOpt.interactive = false; } catch(URISyntaxException e) { System.err.println("Invalid collection path specified: "+e.getMessage()); return null; } break; case CommandlineOptions.MKCOL_OPT : try { cOpt.optionMkcol = URIUtils.encodeXmldbUriFor(option.getArgument()); cOpt.foundCollection = true; } catch(URISyntaxException e) { System.err.println("Invalid collection path specified: "+e.getMessage()); return null; } break; case CommandlineOptions.RMCOL_OPT : try { cOpt.optionRmcol = URIUtils.encodeXmldbUriFor(option.getArgument()); cOpt.foundCollection = true; cOpt.interactive = false; } catch(URISyntaxException e) { System.err.println("Invalid collection path specified: "+e.getMessage()); return null; } break; case CommandlineOptions.FIND_OPT : cOpt.optionXpath = (option.getArgumentCount() == 1 ? option .getArgument() : "stdin"); cOpt.interactive = false; break; case CommandlineOptions.RESULTS_OPT : try { maxResults = Integer.parseInt(option.getArgument()); } catch (NumberFormatException e) { System.err.println("parameter -n needs a valid number"); return null; } break; case CommandlineOptions.OPTION_OPT : properties.setProperty(option.getArgument(0), option .getArgument(1)); break; case CommandlineOptions.QUERY_FILE_OPT : cOpt.optionQueryFile = option.getArgument(); cOpt.interactive = false; break; case CommandlineOptions.THREADS_OPT : try { PARALLEL_THREADS = Integer.parseInt(option .getArgument()); } catch (NumberFormatException e) { System.err.println("parameter -t needs a valid number"); return null; } break; case CommandlineOptions.XUPDATE_OPT : cOpt.optionXUpdate = option.getArgument(); cOpt.interactive = false; break; case CommandlineOptions.TRACE_QUERIES_OPT : String traceFile = option.getArgument(); File f = new File(traceFile); try { traceWriter = new OutputStreamWriter( new FileOutputStream(f, false), "UTF-8"); traceWriter.write("<?xml version=\"1.0\"?>\r\n"); traceWriter.write("<query-log>\r\n"); } catch (UnsupportedEncodingException e1) { LOG.warn(e1); } catch (FileNotFoundException e1) { errorln("Cannot open file " + traceFile); return null; } catch (IOException e) { } break; case CommandlineOptions.REINDEX_OPT : cOpt.doReindex = true; cOpt.interactive = false; break; case CommandlineOptions.QUERY_GUI_OPT : cOpt.openQueryGui = true; break; case CLOption.TEXT_ARGUMENT : cOpt.optionalArgs.add(option.getArgument()); break; } } return cOpt; } /** * Process the command line options * @param cOpt Object representing commandline options * @throws java.lang.Exception * @return TRUE is all successfull, FALSE of not. */ private boolean processCommandLineActions(CommandlineOptions cOpt) throws Exception { // process command-line actions if (cOpt.doReindex) { if(!cOpt.foundCollection) { System.err.println("Please specify target collection with --collection"); shutdown(false); return false; } try { reindex(); } catch (XMLDBException e) { System.err.println("XMLDBException while reindexing collection: " + getExceptionMessage(e)); e.printStackTrace(); return false; } } if (cOpt.optionRmcol != null) { if (!cOpt.foundCollection) { System.err .println("Please specify target collection with --collection"); shutdown(false); return false; } try { rmcol(cOpt.optionRmcol); } catch (XMLDBException e) { System.err.println("XMLDBException while removing collection: " + getExceptionMessage(e)); e.printStackTrace(); return false; } } if (cOpt.optionMkcol != null) { try { mkcol(cOpt.optionMkcol); } catch (XMLDBException e) { System.err.println("XMLDBException during mkcol: " + getExceptionMessage(e)); e.printStackTrace(); return false; } } if (cOpt.optionGet != null) { try { Resource res = retrieve(cOpt.optionGet); if (res != null) { // String data; if (res.getResourceType().equals("XMLResource")) { if (cOpt.optionOutputFile != null) writeOutputFile(cOpt.optionOutputFile, res.getContent()); else System.out.println(res.getContent().toString()); } else { if (cOpt.optionOutputFile != null) { ((ExtendedResource)res).getContentIntoAFile(new File(cOpt.optionOutputFile)); ((EXistResource)res).freeResources(); } else { ((ExtendedResource)res).getContentIntoAStream(System.out); System.out.println(); } } } } catch (XMLDBException e) { System.err .println("XMLDBException while trying to retrieve document: " + getExceptionMessage(e)); e.printStackTrace(); return false; } } else if (cOpt.optionRemove != null) { if (!cOpt.foundCollection) { System.err .println("Please specify target collection with --collection"); } else { try { remove(cOpt.optionRemove); } catch (XMLDBException e) { System.err.println("XMLDBException during parse: " + getExceptionMessage(e)); e.printStackTrace(); return false; } } } else if (cOpt.doStore) { if (!cOpt.foundCollection) { System.err .println("Please specify target collection with --collection"); } else { for (Iterator i = cOpt.optionalArgs.iterator(); i.hasNext(); ) try { parse((String) i.next()); } catch (XMLDBException e) { System.err.println("XMLDBException during parse: " + getExceptionMessage(e)); e.printStackTrace(); return false; } } } else if (cOpt.optionXpath != null || cOpt.optionQueryFile != null) { if (cOpt.optionQueryFile != null) { BufferedReader reader = new BufferedReader(new FileReader( cOpt.optionQueryFile)); StringBuilder buf = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { buf.append(line); buf.append('\n'); } cOpt.optionXpath = buf.toString(); } // if no argument has been found, read query from stdin if (cOpt.optionXpath.equals("stdin")) { try { BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); StringBuilder buf = new StringBuilder(); String line; while ((line = stdin.readLine()) != null) buf.append(line + '\n'); cOpt.optionXpath = buf.toString(); } catch (IOException e) { System.err.println("failed to read query from stdin"); cOpt.optionXpath = null; return false; } } if (cOpt.optionXpath != null) { try { ResourceSet result = find(cOpt.optionXpath); if (maxResults <= 0) maxResults = (int) result.getSize(); if (cOpt.optionOutputFile == null) { for (int i = 0; i < maxResults && i < result.getSize(); i++) { Resource res=result.getResource(i); if(res instanceof ExtendedResource) { ((ExtendedResource)res).getContentIntoAStream(System.out); } else { System.out.println(res.getContent()); } } } else { FileOutputStream fos=new FileOutputStream(cOpt.optionOutputFile); BufferedOutputStream bos=new BufferedOutputStream(fos); PrintStream ps=new PrintStream(bos); for (int i = 0; i < maxResults && i < result.getSize(); i++) { Resource res=result.getResource(i); if(res instanceof ExtendedResource) { ((ExtendedResource)res).getContentIntoAStream(ps); } else { ps.print(res.getContent().toString()); } } ps.close(); bos.close(); fos.close(); } } catch (XMLDBException e) { System.err.println("XMLDBException during query: " + getExceptionMessage(e)); e.printStackTrace(); return false; } } // } else if (optionQueryFile != null) { // testQuery(optionQueryFile); } else if (cOpt.optionXUpdate != null) { try { xupdate(cOpt.optionResource, cOpt.optionXUpdate); } catch (XMLDBException e) { System.err.println("XMLDBException during xupdate: " + getExceptionMessage(e)); return false; } catch (IOException e) { System.err.println("IOException during xupdate: " + getExceptionMessage(e)); return false; } } return true; } /** * Ask user for login data using gui. * @param props Client properties * @return FALSE when pressed cancel, TRUE is sucessfull. */ private boolean getGuiLoginData(Properties props){ Properties loginData = ClientFrame.getLoginData(properties); if (loginData == null) { // User pressed <cancel> return false; } props.putAll(loginData); return true; } /** * Reusable method for connecting to database. Exits process on failure. */ private void connectToDatabase() { try { connect(); } catch (Exception cnf) { if (startGUI && frame != null) frame.setStatus("Connection to database failed; message: " + cnf.getMessage()); else System.err.println("Connection to database failed; message: " + cnf.getMessage()); cnf.printStackTrace(); System.exit(1); } } /** * Main processing method for the InteractiveClient object * * @param args arguments from main() * @return true on success, false on failure */ public boolean run(String args[]) throws Exception { // Get exist home directory File home = ConfigurationHelper.getExistHome(); // initialize with default properties, before add client properties properties = new Properties(defaultProps); // get default configuration filename from the driver class and set it in properties Class cl = Class.forName(properties.getProperty(DRIVER)); Field CONF_XML = cl.getDeclaredField("CONF_XML"); if (CONF_XML != null && home != null) { File configuration = ConfigurationHelper.lookup((String)CONF_XML.get(new String())); properties.setProperty(CONFIGURATION, configuration.getAbsolutePath()); } properties.putAll(loadClientProperties()); // parse command-line options CommandlineOptions cOpt = getCommandlineOptions(args, properties); if(cOpt==null){ // An error occured during parsing. exit program. return false; } // print copyright notice - after parsing command line options, or it can't be silenced! if (!quiet) printNotice(); // Fix "uri" property: Excalibur CLI can't parse dashes, so we need to URL encode them: properties.setProperty("uri", URLDecoder.decode(properties.getProperty("uri"), "UTF-8")); // prompt for password if needed if (cOpt.interactive && startGUI) { boolean haveLoginData = getGuiLoginData(properties); if(!haveLoginData){ return false; } } else if (cOpt.needPasswd) { try { properties.setProperty("password", console.readLine("password: ", new Character('*'))); } catch (Exception e) { } } historyFile = new File(home, ".exist_history"); queryHistoryFile = new File(home, ".exist_query_history"); if (queryHistoryFile.canRead()) readQueryHistory(); if (cOpt.interactive) { // in gui mode we use Readline for history management // initialize Readline library Terminal.setupTerminal(); console = new ConsoleReader(); console.addCompletor(new CollectionCompleter()); try { History history = new History(historyFile); console.setHistory(history); } catch (Exception e) { // No error handling } } // connect to the db connectToDatabase(); if (current == null) { if (startGUI && frame != null) frame.setStatus("Could not retrieve collection " + path); else System.err.println("Could not retrieve collection " + path); shutdown(false); return false; } boolean processingOK = processCommandLineActions(cOpt); if(!processingOK){ return false; } if (cOpt.interactive) { if (startGUI) { frame = new ClientFrame(this, path, properties); frame.setLocation(100, 100); frame.setSize(500, 500); frame.setVisible(true); } // enter interactive mode if( (!startGUI) || (frame == null) ){ // No gui try { getResources(); } catch (XMLDBException e) { System.err.println("XMLDBException while " + "retrieving collection contents: " + getExceptionMessage(e)); e.getCause().printStackTrace(); return false; } } else { // with gui ; re-login posibility boolean retry=true; while(retry){ String errorMessage=""; try { getResources(); } catch (XMLDBException e) { errorMessage=getExceptionMessage(e); ClientFrame.showErrorMessage( "XMLDBException occurred while retrieving collection: " + errorMessage, e); } // Determine error text. For special reasons we can retry // to connect. if( errorMessage.matches("^.*Invalid password for user.*$") || errorMessage.matches("^.*User .* unknown.*") || errorMessage.matches("^.*Connection refused: connect.*") ){ boolean haveLoginData = getGuiLoginData(properties); if(!haveLoginData){ // pressed cancel return false; } // Need to shutdown ?? ask wolfgang shutdown(false); // connect to the db connectToDatabase(); } else { if(errorMessage!=""){ // No pattern match, but we have an error. stop here frame.dispose(); return false; } else { // No error message, continue startup. retry=false; } } } } messageln("\ntype help or ? for help."); if (cOpt.openQueryGui) { QueryDialog qd = new QueryDialog(this, current, properties); qd.setLocation(100, 100); qd.setVisible(true); } else if (!startGUI) readlineInputLoop(home.getAbsolutePath()); else frame.displayPrompt(); } else shutdown(false); return true; } public final static String getExceptionMessage(Throwable e) { Throwable cause; while((cause = e.getCause()) != null) e = cause; return e.getMessage(); } /** * Read Query History file. */ protected void readQueryHistory() { try { DocumentBuilderFactory factory = DocumentBuilderFactory .newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(queryHistoryFile); NodeList nodes = doc.getElementsByTagName("query"); for (int i = 0; i < nodes.getLength(); i++) { Element query = (Element) nodes.item(i); StringBuilder value = new StringBuilder(); Node next = query.getFirstChild(); while (next != null) { value.append(next.getNodeValue()); next = next.getNextSibling(); } queryHistory.addLast(value.toString()); } } catch (Exception e) { if (startGUI) ClientFrame.showErrorMessage( "Error while reading query history: " + e.getMessage(), e); else errorln("Error while reading query history: " + e.getMessage()); } } protected void addToHistory(String query) { queryHistory.add(query); } protected void writeQueryHistory() { try { console.getHistory().flushBuffer(); } catch (Exception e) { } try { BufferedWriter writer = new BufferedWriter(new FileWriter( queryHistoryFile)); SAXSerializer serializer = (SAXSerializer) SerializerPool.getInstance().borrowObject(SAXSerializer.class); serializer.setOutput(writer, null); int p = 0; if (queryHistory.size() > 20) p = queryHistory.size() - 20; AttributesImpl attrs = new AttributesImpl(); serializer.startDocument(); serializer.startElement("", "history", "history", attrs); for (ListIterator i = queryHistory.listIterator(p); i.hasNext(); ) { serializer.startElement("", "query", "query", attrs); String next = (String) i.next(); serializer.characters(next.toCharArray(), 0, next.length()); serializer.endElement("", "query", "query"); } serializer.endElement("", "history", "history"); serializer.endDocument(); writer.close(); SerializerPool.getInstance().returnObject(serializer); } catch (IOException e) { System.err.println("IO error while writing query history."); } catch (SAXException e) { System.err.println("SAX exception while writing query history."); } } public void readlineInputLoop(String home) { String line; boolean cont = true; while (cont) try { if (properties.getProperty("colors").equals("true")) line = console.readLine(ANSI_CYAN + "exist:" + path + ">" + ANSI_WHITE); else line = console.readLine("exist:" + path + ">"); if (line != null) cont = process(line); } catch (EOFException e) { break; } catch (IOException ioe) { System.err.println(ioe); } catch (Exception e) { System.err.println(e); } try { console.getHistory().flushBuffer(); } catch (Exception e) { System.err.println("Could not write history File to " + historyFile.getAbsolutePath() ); } shutdown(false); messageln("quit."); } protected final void shutdown(boolean force) { if (traceWriter != null) try { traceWriter.write("</query-log>"); traceWriter.close(); } catch (IOException e1) { } try { DatabaseInstanceManager mgr = (DatabaseInstanceManager) current .getService("DatabaseInstanceManager", "1.0"); if (mgr == null) { System.err.println("service is not available"); } else if (mgr.isLocalInstance() || force) { System.out.println("shutting down database..."); mgr.shutdown(); } } catch (XMLDBException e) { System.err.println("database shutdown failed: "); e.printStackTrace(); } } private final void printUsage() { System.out.println("Usage: java " + InteractiveClient.class.getName() + " [options]"); System.out.println(CLUtil.describeOptions(CommandlineOptions.OPTIONS).toString()); } public void printNotice() { Properties sysProperties = getSystemProperties(); messageln(sysProperties.getProperty("product-name") + " version " + sysProperties.getProperty("product-version") +", Copyright (C) 2001-2011 The eXist Project"); messageln("eXist-db comes with ABSOLUTELY NO WARRANTY."); messageln("This is free software, and you are welcome to " + "redistribute it\nunder certain conditions; " + "for details read the license file.\n"); } private final void message(String msg) { if (!quiet) { if (startGUI && frame != null) frame.display(msg); else System.out.print(msg); } } private final void messageln(String msg) { if (!quiet) { if (startGUI && frame != null) frame.display(msg + '\n'); else System.out.println(msg); } } private final void errorln(String msg) { if (startGUI && frame != null) frame.display(msg + '\n'); else System.err.println(msg); } private Collection resolveCollection(XmldbURI path) throws XMLDBException { return DatabaseManager.getCollection( properties.getProperty("uri") + path, properties.getProperty("user"), properties.getProperty("password")); } private Resource resolveResource(XmldbURI path) throws XMLDBException { XmldbURI collectionPath = path.numSegments()==1?XmldbURI.create(current.getName()):path.removeLastSegment(); XmldbURI resourceName = path.lastSegment(); Collection collection = resolveCollection(collectionPath); if(collection == null) { messageln("Collection " + collectionPath + " not found."); return null; } messageln("Locating resource " + resourceName + " in collection " + collection.getName()); return collection.getResource(resourceName.toString()); } private class CollectionCompleter implements Completor { public int complete(String buffer, int cursor, List candidates) { int p = buffer.lastIndexOf(' '); String toComplete; if (p > -1 && ++p < buffer.length()) { toComplete = buffer.substring(p); } else { toComplete = buffer; p = 0; } // System.out.println("\nbuffer: '" + toComplete + "'; cursor: " + cursor); Set set = completitions.tailSet(toComplete); if (set != null && set.size() > 0) { for (Iterator i = completitions.tailSet(toComplete).iterator(); i.hasNext(); ) { String next = i.next().toString(); if (next.startsWith(toComplete)) candidates.add(next); } } return p + 1; } } public static class ProgressObserver implements Observer { ProgressBar elementsProgress = new ProgressBar("storing elements"); Observable lastObservable = null; ProgressBar parseProgress = new ProgressBar("storing nodes "); ProgressBar wordsProgress = new ProgressBar("storing words "); public void update(Observable o, Object obj) { ProgressIndicator ind = (ProgressIndicator) obj; if (lastObservable == null || o != lastObservable) System.out.println(); if (o instanceof ElementIndex) elementsProgress.set(ind.getValue(), ind.getMax()); else if (o instanceof TextSearchEngine) wordsProgress.set(ind.getValue(), ind.getMax()); else parseProgress.set(ind.getValue(), ind.getMax()); lastObservable = o; } } private void writeOutputFile(String fileName, Object data) throws Exception { File file = new File(fileName); FileOutputStream os = new FileOutputStream(file); if (data instanceof byte[]) { os.write((byte[]) data); os.close(); } else { OutputStreamWriter writer = new OutputStreamWriter(os, Charset .forName(properties.getProperty("encoding"))); writer.write(data.toString()); writer.close(); } } private static String formatString(String s1, String s2, int width) { StringBuilder buf = new StringBuilder(width); if (s1.length() > width) s1 = s1.substring(0, width - 1); buf.append(s1); int fill = width - (s1.length() + s2.length()); for (int i = 0; i < fill; i++) buf.append(' '); buf.append(s2); return buf.toString(); } private static String formatString(String[] args, int[] sizes) { StringBuilder buf = new StringBuilder(); for (int i = 0; i < args.length; i++) { if (sizes[i] < 0) { buf.append(args[i]); } else { for (int j = 0; j < sizes[i] && j < args[i].length(); j++) buf.append(args[i].charAt(j)); } for (int j = 0; j < sizes[i] - args[i].length(); j++) buf.append(' '); } return buf.toString(); } public static Properties getSystemProperties(){ Properties sysProperties = new Properties(); try { sysProperties.load(InteractiveClient.class.getClassLoader().getResourceAsStream("org/exist/system.properties")); } catch (IOException e) { System.err.println("Unable to load system.properties from class loader"); } return sysProperties; } }