/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.bundlerepository.impl; import java.io.*; import java.lang.reflect.Array; import java.net.URL; import java.util.*; import org.apache.felix.bundlerepository.Capability; import org.apache.felix.bundlerepository.Reason; import org.apache.felix.bundlerepository.Requirement; import org.apache.felix.bundlerepository.Resolver; import org.apache.felix.bundlerepository.Resource; import org.apache.felix.bundlerepository.impl.FileUtil; import org.apache.felix.shell.Command; import org.osgi.framework.*; public class ObrCommandImpl implements Command { private static final String HELP_CMD = "help"; private static final String ADDURL_CMD = "add-url"; private static final String REMOVEURL_CMD = "remove-url"; private static final String LISTURL_CMD = "list-url"; private static final String REFRESHURL_CMD = "refresh-url"; private static final String LIST_CMD = "list"; private static final String INFO_CMD = "info"; private static final String DEPLOY_CMD = "deploy"; private static final String START_CMD = "start"; private static final String SOURCE_CMD = "source"; private static final String JAVADOC_CMD = "javadoc"; private static final String EXTRACT_SWITCH = "-x"; private static final String VERBOSE_SWITCH = "-v"; private BundleContext m_context = null; private org.apache.felix.bundlerepository.RepositoryAdmin m_repoAdmin = null; public ObrCommandImpl(BundleContext context, org.apache.felix.bundlerepository.RepositoryAdmin repoAdmin) { m_context = context; m_repoAdmin = repoAdmin; } public String getName() { return "obr"; } public String getUsage() { return "obr help"; } public String getShortDescription() { return "OSGi bundle repository."; } public synchronized void execute(String commandLine, PrintStream out, PrintStream err) { try { // Parse the commandLine to get the OBR command. StringTokenizer st = new StringTokenizer(commandLine); // Ignore the invoking command. st.nextToken(); // Try to get the OBR command, default is HELP command. String command = HELP_CMD; try { command = st.nextToken(); } catch (Exception ex) { // Ignore. } // Perform the specified command. if ((command == null) || (command.equals(HELP_CMD))) { help(out, st); } else { if (command.equals(ADDURL_CMD) || command.equals(REFRESHURL_CMD) || command.equals(REMOVEURL_CMD) || command.equals(LISTURL_CMD)) { urls(commandLine, command, out, err); } else if (command.equals(LIST_CMD)) { list(commandLine, command, out, err); } else if (command.equals(INFO_CMD)) { info(commandLine, command, out, err); } else if (command.equals(DEPLOY_CMD) || command.equals(START_CMD)) { deploy(commandLine, command, out, err); } else if (command.equals(SOURCE_CMD)) { source(commandLine, command, out, err); } else if (command.equals(JAVADOC_CMD)) { javadoc(commandLine, command, out, err); } else { err.println("Unknown command: " + command); } } } catch (InvalidSyntaxException ex) { err.println("Syntax error: " + ex.getMessage()); } catch (IOException ex) { err.println("Error: " + ex); } } private void urls( String commandLine, String command, PrintStream out, PrintStream err) throws IOException { // Parse the commandLine. StringTokenizer st = new StringTokenizer(commandLine); // Ignore the "obr" command. st.nextToken(); // Ignore the "url" command. st.nextToken(); int count = st.countTokens(); if (count > 0) { while (st.hasMoreTokens()) { try { String uri = st.nextToken(); if (command.equals(ADDURL_CMD)) { m_repoAdmin.addRepository(uri); } else if (command.equals(REFRESHURL_CMD)) { m_repoAdmin.removeRepository(uri); m_repoAdmin.addRepository(uri); } else { m_repoAdmin.removeRepository(uri); } } catch (Exception ex) { ex.printStackTrace(err); } } } else { org.apache.felix.bundlerepository.Repository[] repos = m_repoAdmin.listRepositories(); if ((repos != null) && (repos.length > 0)) { for (int i = 0; i < repos.length; i++) { out.println(repos[i].getURI()); } } else { out.println("No repository URLs are set."); } } } private void list( String commandLine, String command, PrintStream out, PrintStream err) throws IOException, InvalidSyntaxException { // Parse the command for an option switch and tokens. ParsedCommand pc = parseList(commandLine); // Create a filter that will match presentation name or symbolic name. StringBuffer sb = new StringBuffer(); if ((pc.getTokens() == null) || (pc.getTokens().length() == 0)) { sb.append("(|(presentationname=*)(symbolicname=*))"); } else { sb.append("(|(presentationname=*"); sb.append(pc.getTokens()); sb.append("*)(symbolicname=*"); sb.append(pc.getTokens()); sb.append("*))"); } // Use filter to get matching resources. Resource[] resources = m_repoAdmin.discoverResources(sb.toString()); // Group the resources by symbolic name in descending version order, // but keep them in overall sorted order by presentation name. Map revisionMap = new TreeMap(new Comparator() { public int compare(Object o1, Object o2) { Resource r1 = (Resource) o1; Resource r2 = (Resource) o2; // Assume if the symbolic name is equal, then the two are equal, // since we are trying to aggregate by symbolic name. int symCompare = r1.getSymbolicName().compareTo(r2.getSymbolicName()); if (symCompare == 0) { return 0; } // Otherwise, compare the presentation name to keep them sorted // by presentation name. If the presentation names are equal, then // use the symbolic name to differentiate. int compare = (r1.getPresentationName() == null) ? -1 : (r2.getPresentationName() == null) ? 1 : r1.getPresentationName().compareToIgnoreCase( r2.getPresentationName()); if (compare == 0) { return symCompare; } return compare; } }); for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++) { Resource[] revisions = (Resource[]) revisionMap.get(resources[resIdx]); revisionMap.put(resources[resIdx], addResourceByVersion(revisions, resources[resIdx])); } // Print any matching resources. for (Iterator i = revisionMap.entrySet().iterator(); i.hasNext(); ) { Map.Entry entry = (Map.Entry) i.next(); Resource[] revisions = (Resource[]) entry.getValue(); String name = revisions[0].getPresentationName(); name = (name == null) ? revisions[0].getSymbolicName() : name; out.print(name); if (pc.isVerbose() && revisions[0].getPresentationName() != null) { out.print(" [" + revisions[0].getSymbolicName() + "]"); } out.print(" ("); int revIdx = 0; do { if (revIdx > 0) { out.print(", "); } out.print(revisions[revIdx].getVersion()); revIdx++; } while (pc.isVerbose() && (revIdx < revisions.length)); if (!pc.isVerbose() && (revisions.length > 1)) { out.print(", ..."); } out.println(")"); } if ((resources == null) || (resources.length == 0)) { out.println("No matching bundles."); } } private void info( String commandLine, String command, PrintStream out, PrintStream err) throws IOException, InvalidSyntaxException { ParsedCommand pc = parseInfo(commandLine); for (int cmdIdx = 0; (pc != null) && (cmdIdx < pc.getTargetCount()); cmdIdx++) { // Find the target's bundle resource. Resource[] resources = searchRepository(pc.getTargetId(cmdIdx), pc.getTargetVersion(cmdIdx)); if (resources == null) { err.println("Unknown bundle and/or version: " + pc.getTargetId(cmdIdx)); } else { for (int resIdx = 0; resIdx < resources.length; resIdx++) { if (resIdx > 0) { out.println(""); } printResource(out, resources[resIdx]); } } } } private void deploy( String commandLine, String command, PrintStream out, PrintStream err) throws IOException, InvalidSyntaxException { ParsedCommand pc = parseInstallStart(commandLine); _deploy(pc, command, out, err); } private void _deploy( ParsedCommand pc, String command, PrintStream out, PrintStream err) throws IOException, InvalidSyntaxException { org.apache.felix.bundlerepository.Resolver resolver = m_repoAdmin.resolver(); for (int i = 0; (pc != null) && (i < pc.getTargetCount()); i++) { // Find the target's bundle resource. Resource resource = selectNewestVersion( searchRepository(pc.getTargetId(i), pc.getTargetVersion(i))); if (resource != null) { resolver.add(resource); } else { err.println("Unknown bundle - " + pc.getTargetId(i)); } } if ((resolver.getAddedResources() != null) && (resolver.getAddedResources().length > 0)) { if (resolver.resolve()) { out.println("Target resource(s):"); printUnderline(out, 19); Resource[] resources = resolver.getAddedResources(); for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++) { out.println(" " + resources[resIdx].getPresentationName() + " (" + resources[resIdx].getVersion() + ")"); } resources = resolver.getRequiredResources(); if ((resources != null) && (resources.length > 0)) { out.println("\nRequired resource(s):"); printUnderline(out, 21); for (int resIdx = 0; resIdx < resources.length; resIdx++) { out.println(" " + resources[resIdx].getPresentationName() + " (" + resources[resIdx].getVersion() + ")"); } } resources = resolver.getOptionalResources(); if ((resources != null) && (resources.length > 0)) { out.println("\nOptional resource(s):"); printUnderline(out, 21); for (int resIdx = 0; resIdx < resources.length; resIdx++) { out.println(" " + resources[resIdx].getPresentationName() + " (" + resources[resIdx].getVersion() + ")"); } } try { out.print("\nDeploying..."); resolver.deploy(command.equals(START_CMD) ? Resolver.START : 0); out.println("done."); } catch (IllegalStateException ex) { err.println(ex); } } else { Reason[] reqs = resolver.getUnsatisfiedRequirements(); if ((reqs != null) && (reqs.length > 0)) { out.println("Unsatisfied requirement(s):"); printUnderline(out, 27); for (int reqIdx = 0; reqIdx < reqs.length; reqIdx++) { out.println(" " + reqs[reqIdx].getRequirement().getFilter()); out.println(" " + reqs[reqIdx].getResource().getPresentationName()); } } else { out.println("Could not resolve targets."); } } } } private void source( String commandLine, String command, PrintStream out, PrintStream err) throws IOException, InvalidSyntaxException { // Parse the command line to get all local targets to update. ParsedCommand pc = parseSource(commandLine); for (int i = 0; i < pc.getTargetCount(); i++) { Resource resource = selectNewestVersion( searchRepository(pc.getTargetId(i), pc.getTargetVersion(i))); if (resource == null) { err.println("Unknown bundle and/or version: " + pc.getTargetId(i)); } else { String srcURI = (String) resource.getProperties().get(Resource.SOURCE_URI); if (srcURI != null) { FileUtil.downloadSource( out, err, new URL(srcURI), pc.getDirectory(), pc.isExtract()); } else { err.println("Missing source URL: " + pc.getTargetId(i)); } } } } private void javadoc( String commandLine, String command, PrintStream out, PrintStream err) throws IOException, InvalidSyntaxException { // Parse the command line to get all local targets to update. ParsedCommand pc = parseSource(commandLine); for (int i = 0; i < pc.getTargetCount(); i++) { Resource resource = selectNewestVersion( searchRepository(pc.getTargetId(i), pc.getTargetVersion(i))); if (resource == null) { err.println("Unknown bundle and/or version: " + pc.getTargetId(i)); } else { URL docURL = (URL) resource.getProperties().get("javadoc"); if (docURL != null) { FileUtil.downloadSource( out, err, docURL, pc.getDirectory(), pc.isExtract()); } else { err.println("Missing javadoc URL: " + pc.getTargetId(i)); } } } } private Resource[] searchRepository(String targetId, String targetVersion) throws InvalidSyntaxException { // Try to see if the targetId is a bundle ID. try { Bundle bundle = m_context.getBundle(Long.parseLong(targetId)); targetId = bundle.getSymbolicName(); } catch (NumberFormatException ex) { // It was not a number, so ignore. } // The targetId may be a bundle name or a bundle symbolic name, // so create the appropriate LDAP query. StringBuffer sb = new StringBuffer("(|(presentationname="); sb.append(targetId); sb.append(")(symbolicname="); sb.append(targetId); sb.append("))"); if (targetVersion != null) { sb.insert(0, "(&"); sb.append("(version="); sb.append(targetVersion); sb.append("))"); } return m_repoAdmin.discoverResources(sb.toString()); } public Resource selectNewestVersion(Resource[] resources) { int idx = -1; Version v = null; for (int i = 0; (resources != null) && (i < resources.length); i++) { if (i == 0) { idx = 0; v = resources[i].getVersion(); } else { Version vtmp = resources[i].getVersion(); if (vtmp.compareTo(v) > 0) { idx = i; v = vtmp; } } } return (idx < 0) ? null : resources[idx]; } private void printResource(PrintStream out, Resource resource) { printUnderline(out, resource.getPresentationName().length()); out.println(resource.getPresentationName()); printUnderline(out, resource.getPresentationName().length()); Map map = resource.getProperties(); for (Iterator iter = map.entrySet().iterator(); iter.hasNext(); ) { Map.Entry entry = (Map.Entry) iter.next(); if (entry.getValue().getClass().isArray()) { out.println(entry.getKey() + ":"); for (int j = 0; j < Array.getLength(entry.getValue()); j++) { out.println(" " + Array.get(entry.getValue(), j)); } } else { out.println(entry.getKey() + ": " + entry.getValue()); } } Requirement[] reqs = resource.getRequirements(); if ((reqs != null) && (reqs.length > 0)) { out.println("Requires:"); for (int i = 0; i < reqs.length; i++) { out.println(" " + reqs[i].getFilter()); } } Capability[] caps = resource.getCapabilities(); if ((caps != null) && (caps.length > 0)) { out.println("Capabilities:"); for (int i = 0; i < caps.length; i++) { out.println(" " + caps[i].getPropertiesAsMap()); } } } private static void printUnderline(PrintStream out, int length) { for (int i = 0; i < length; i++) { out.print('-'); } out.println(""); } private ParsedCommand parseList(String commandLine) throws IOException, InvalidSyntaxException { // The command line for list will be something like: // obr list -v token token // Create a stream tokenizer for the command line string, StringReader sr = new StringReader(commandLine); StreamTokenizer tokenizer = new StreamTokenizer(sr); tokenizer.resetSyntax(); tokenizer.quoteChar('\''); tokenizer.quoteChar('\"'); tokenizer.whitespaceChars('\u0000', '\u0020'); tokenizer.wordChars('A', 'Z'); tokenizer.wordChars('a', 'z'); tokenizer.wordChars('0', '9'); tokenizer.wordChars('\u00A0', '\u00FF'); tokenizer.wordChars('.', '.'); tokenizer.wordChars('-', '-'); tokenizer.wordChars('_', '_'); // Ignore the invoking command name and the OBR command. int type = tokenizer.nextToken(); type = tokenizer.nextToken(); int EOF = 1; int SWITCH = 2; int TOKEN = 4; // Construct an install record. ParsedCommand pc = new ParsedCommand(); String tokens = null; // The state machine starts by expecting either a // SWITCH or a DIRECTORY. int expecting = (SWITCH | TOKEN | EOF); while (true) { // Get the next token type. type = tokenizer.nextToken(); switch (type) { // EOF received. case StreamTokenizer.TT_EOF: // Error if we weren't expecting EOF. if ((expecting & EOF) == 0) { throw new InvalidSyntaxException( "Expecting more arguments.", null); } // Add current target if there is one. if (tokens != null) { pc.setTokens(tokens); } // Return cleanly. return pc; // WORD or quoted WORD received. case StreamTokenizer.TT_WORD: case '\'': case '\"': // If we are expecting a command SWITCH and the token // equals a command SWITCH, then record it. if (((expecting & SWITCH) > 0) && tokenizer.sval.equals(VERBOSE_SWITCH)) { pc.setVerbose(true); expecting = (TOKEN | EOF); } // If we are expecting a target, the record it. else if ((expecting & TOKEN) > 0) { // Add a space in between tokens. if (tokens == null) { tokens = ""; } else { tokens += " "; } // Append to the current token. tokens += tokenizer.sval; expecting = (EOF | TOKEN); } else { throw new InvalidSyntaxException( "Not expecting '" + tokenizer.sval + "'.", null); } break; } } } private ParsedCommand parseInfo(String commandLine) throws IOException, InvalidSyntaxException { // Create a stream tokenizer for the command line string, // since the syntax for install/start is more sophisticated. StringReader sr = new StringReader(commandLine); StreamTokenizer tokenizer = new StreamTokenizer(sr); tokenizer.resetSyntax(); tokenizer.quoteChar('\''); tokenizer.quoteChar('\"'); tokenizer.whitespaceChars('\u0000', '\u0020'); tokenizer.wordChars('A', 'Z'); tokenizer.wordChars('a', 'z'); tokenizer.wordChars('0', '9'); tokenizer.wordChars('\u00A0', '\u00FF'); tokenizer.wordChars('.', '.'); tokenizer.wordChars('-', '-'); tokenizer.wordChars('_', '_'); // Ignore the invoking command name and the OBR command. int type = tokenizer.nextToken(); type = tokenizer.nextToken(); int EOF = 1; int SWITCH = 2; int TARGET = 4; int VERSION = 8; int VERSION_VALUE = 16; // Construct an install record. ParsedCommand pc = new ParsedCommand(); String currentTargetName = null; // The state machine starts by expecting either a // SWITCH or a TARGET. int expecting = (TARGET); while (true) { // Get the next token type. type = tokenizer.nextToken(); switch (type) { // EOF received. case StreamTokenizer.TT_EOF: // Error if we weren't expecting EOF. if ((expecting & EOF) == 0) { throw new InvalidSyntaxException( "Expecting more arguments.", null); } // Add current target if there is one. if (currentTargetName != null) { pc.addTarget(currentTargetName, null); } // Return cleanly. return pc; // WORD or quoted WORD received. case StreamTokenizer.TT_WORD: case '\'': case '\"': // If we are expecting a target, the record it. if ((expecting & TARGET) > 0) { // Add current target if there is one. if (currentTargetName != null) { pc.addTarget(currentTargetName, null); } // Set the new target as the current target. currentTargetName = tokenizer.sval; expecting = (EOF | TARGET | VERSION); } else if ((expecting & VERSION_VALUE) > 0) { pc.addTarget(currentTargetName, tokenizer.sval); currentTargetName = null; expecting = (EOF | TARGET); } else { throw new InvalidSyntaxException( "Not expecting '" + tokenizer.sval + "'.", null); } break; // Version separator character received. case ';': // Error if we weren't expecting the version separator. if ((expecting & VERSION) == 0) { throw new InvalidSyntaxException( "Not expecting version.", null); } // Otherwise, we will only expect a version value next. expecting = (VERSION_VALUE); break; } } } private ParsedCommand parseInstallStart(String commandLine) throws IOException, InvalidSyntaxException { // Create a stream tokenizer for the command line string, // since the syntax for install/start is more sophisticated. StringReader sr = new StringReader(commandLine); StreamTokenizer tokenizer = new StreamTokenizer(sr); tokenizer.resetSyntax(); tokenizer.quoteChar('\''); tokenizer.quoteChar('\"'); tokenizer.whitespaceChars('\u0000', '\u0020'); tokenizer.wordChars('A', 'Z'); tokenizer.wordChars('a', 'z'); tokenizer.wordChars('0', '9'); tokenizer.wordChars('\u00A0', '\u00FF'); tokenizer.wordChars('.', '.'); tokenizer.wordChars('-', '-'); tokenizer.wordChars('_', '_'); // Ignore the invoking command name and the OBR command. int type = tokenizer.nextToken(); type = tokenizer.nextToken(); int EOF = 1; int SWITCH = 2; int TARGET = 4; int VERSION = 8; int VERSION_VALUE = 16; // Construct an install record. ParsedCommand pc = new ParsedCommand(); String currentTargetName = null; // The state machine starts by expecting either a // SWITCH or a TARGET. int expecting = (SWITCH | TARGET); while (true) { // Get the next token type. type = tokenizer.nextToken(); switch (type) { // EOF received. case StreamTokenizer.TT_EOF: // Error if we weren't expecting EOF. if ((expecting & EOF) == 0) { throw new InvalidSyntaxException( "Expecting more arguments.", null); } // Add current target if there is one. if (currentTargetName != null) { pc.addTarget(currentTargetName, null); } // Return cleanly. return pc; // WORD or quoted WORD received. case StreamTokenizer.TT_WORD: case '\'': case '\"': // If we are expecting a target, the record it. if ((expecting & TARGET) > 0) { // Add current target if there is one. if (currentTargetName != null) { pc.addTarget(currentTargetName, null); } // Set the new target as the current target. currentTargetName = tokenizer.sval; expecting = (EOF | TARGET | VERSION); } else if ((expecting & VERSION_VALUE) > 0) { pc.addTarget(currentTargetName, tokenizer.sval); currentTargetName = null; expecting = (EOF | TARGET); } else { throw new InvalidSyntaxException( "Not expecting '" + tokenizer.sval + "'.", null); } break; // Version separator character received. case ';': // Error if we weren't expecting the version separator. if ((expecting & VERSION) == 0) { throw new InvalidSyntaxException( "Not expecting version.", null); } // Otherwise, we will only expect a version value next. expecting = (VERSION_VALUE); break; } } } private ParsedCommand parseSource(String commandLine) throws IOException, InvalidSyntaxException { // Create a stream tokenizer for the command line string, // since the syntax for install/start is more sophisticated. StringReader sr = new StringReader(commandLine); StreamTokenizer tokenizer = new StreamTokenizer(sr); tokenizer.resetSyntax(); tokenizer.quoteChar('\''); tokenizer.quoteChar('\"'); tokenizer.whitespaceChars('\u0000', '\u0020'); tokenizer.wordChars('A', 'Z'); tokenizer.wordChars('a', 'z'); tokenizer.wordChars('0', '9'); tokenizer.wordChars('\u00A0', '\u00FF'); tokenizer.wordChars('.', '.'); tokenizer.wordChars('-', '-'); tokenizer.wordChars('_', '_'); tokenizer.wordChars('/', '/'); tokenizer.wordChars('\\', '\\'); tokenizer.wordChars(':', ':'); // Ignore the invoking command name and the OBR command. int type = tokenizer.nextToken(); type = tokenizer.nextToken(); int EOF = 1; int SWITCH = 2; int DIRECTORY = 4; int TARGET = 8; int VERSION = 16; int VERSION_VALUE = 32; // Construct an install record. ParsedCommand pc = new ParsedCommand(); String currentTargetName = null; // The state machine starts by expecting either a // SWITCH or a DIRECTORY. int expecting = (SWITCH | DIRECTORY); while (true) { // Get the next token type. type = tokenizer.nextToken(); switch (type) { // EOF received. case StreamTokenizer.TT_EOF: // Error if we weren't expecting EOF. if ((expecting & EOF) == 0) { throw new InvalidSyntaxException( "Expecting more arguments.", null); } // Add current target if there is one. if (currentTargetName != null) { pc.addTarget(currentTargetName, null); } // Return cleanly. return pc; // WORD or quoted WORD received. case StreamTokenizer.TT_WORD: case '\'': case '\"': // If we are expecting a command SWITCH and the token // equals a command SWITCH, then record it. if (((expecting & SWITCH) > 0) && tokenizer.sval.equals(EXTRACT_SWITCH)) { pc.setExtract(true); expecting = (DIRECTORY); } // If we are expecting a directory, the record it. else if ((expecting & DIRECTORY) > 0) { // Set the directory for the command. pc.setDirectory(tokenizer.sval); expecting = (TARGET); } // If we are expecting a target, the record it. else if ((expecting & TARGET) > 0) { // Add current target if there is one. if (currentTargetName != null) { pc.addTarget(currentTargetName, null); } // Set the new target as the current target. currentTargetName = tokenizer.sval; expecting = (EOF | TARGET | VERSION); } else if ((expecting & VERSION_VALUE) > 0) { pc.addTarget(currentTargetName, tokenizer.sval); currentTargetName = null; expecting = (EOF | TARGET); } else { throw new InvalidSyntaxException( "Not expecting '" + tokenizer.sval + "'.", null); } break; // Version separator character received. case ';': // Error if we weren't expecting the version separator. if ((expecting & VERSION) == 0) { throw new InvalidSyntaxException( "Not expecting version.", null); } // Otherwise, we will only expect a version value next. expecting = (VERSION_VALUE); break; } } } private void help(PrintStream out, StringTokenizer st) { String command = HELP_CMD; if (st.hasMoreTokens()) { command = st.nextToken(); } if (command.equals(ADDURL_CMD)) { out.println(""); out.println("obr " + ADDURL_CMD + " <repository-url> ..."); out.println(""); out.println( "This command adds the space-delimited list of repository URLs to\n" + "the repository service."); out.println(""); } else if (command.equals(REFRESHURL_CMD)) { out.println(""); out.println("obr " + REFRESHURL_CMD + " <repository-url> ..."); out.println(""); out.println( "This command refreshes the space-delimited list of repository URLs\n" + "within the repository service.\n" + "(The command internally removes and adds the specified URLs from the\n" + "repository service.)"); out.println(""); } else if (command.equals(REMOVEURL_CMD)) { out.println(""); out.println("obr " + REMOVEURL_CMD + " <repository-url> ..."); out.println(""); out.println( "This command removes the space-delimited list of repository URLs\n" + "from the repository service."); out.println(""); } else if (command.equals(LISTURL_CMD)) { out.println(""); out.println("obr " + LISTURL_CMD); out.println(""); out.println( "This command displays the repository URLs currently associated\n" + "with the repository service."); out.println(""); } else if (command.equals(LIST_CMD)) { out.println(""); out.println("obr " + LIST_CMD + " [" + VERBOSE_SWITCH + "] [<string> ...]"); out.println(""); out.println( "This command lists bundles available in the bundle repository.\n" + "If no arguments are specified, then all available bundles are\n" + "listed, otherwise any arguments are concatenated with spaces\n" + "and used as a substring filter on the bundle names. By default,\n" + "only the most recent version of each artifact is shown. To list\n" + "all available versions use the \"" + VERBOSE_SWITCH + "\" switch."); out.println(""); } else if (command.equals(INFO_CMD)) { out.println(""); out.println("obr " + INFO_CMD + " <bundle-name>|<bundle-symbolic-name>|<bundle-id>[;<version>] ..."); out.println(""); out.println( "This command displays the meta-data for the specified bundles.\n" + "If a bundle's name contains spaces, then it must be surrounded\n" + "by quotes. It is also possible to specify a precise version\n" + "if more than one version exists, such as:\n" + "\n" + " obr info \"Bundle Repository\";1.0.0\n" + "\n" + "The above example retrieves the meta-data for version \"1.0.0\"\n" + "of the bundle named \"Bundle Repository\"."); out.println(""); } else if (command.equals(DEPLOY_CMD)) { out.println(""); out.println("obr " + DEPLOY_CMD + " <bundle-name>|<bundle-symbolic-name>|<bundle-id>[;<version>] ... "); out.println(""); out.println( "This command tries to install or update the specified bundles\n" + "and all of their dependencies. You can specify either the bundle\n" + "name or the bundle identifier. If a bundle's name contains spaces,\n" + "then it must be surrounded by quotes. It is also possible to\n" + "specify a precise version if more than one version exists, such as:\n" + "\n" + " obr deploy \"Bundle Repository\";1.0.0\n" + "\n" + "For the above example, if version \"1.0.0\" of \"Bundle Repository\" is\n" + "already installed locally, then the command will attempt to update it\n" + "and all of its dependencies; otherwise, the command will install it\n" + "and all of its dependencies."); out.println(""); } else if (command.equals(START_CMD)) { out.println(""); out.println("obr " + START_CMD + " <bundle-name>|<bundle-symbolic-name>|<bundle-id>[;<version>] ..."); out.println(""); out.println( "This command installs and starts the specified bundles and all\n" + "of their dependencies. If a bundle's name contains spaces, then\n" + "it must be surrounded by quotes. If a specified bundle is already\n" + "installed, then this command has no effect. It is also possible\n" + "to specify a precise version if more than one version exists,\n" + "such as:\n" + "\n" + " obr start \"Bundle Repository\";1.0.0\n" + "\n" + "The above example installs and starts version \"1.0.0\" of the\n" + "bundle named \"Bundle Repository\" and its dependencies."); out.println(""); } else if (command.equals(SOURCE_CMD)) { out.println(""); out.println("obr " + SOURCE_CMD + " [" + EXTRACT_SWITCH + "] <local-dir> <bundle-name>[;<version>] ..."); out.println(""); out.println( "This command retrieves the source archives of the specified\n" + "bundles and saves them to the specified local directory; use\n" + "the \"" + EXTRACT_SWITCH + "\" switch to automatically extract the source archives.\n" + "If a bundle name contains spaces, then it must be surrounded\n" + "by quotes. It is also possible to specify a precise version if\n" + "more than one version exists, such as:\n" + "\n" + " obr source /home/rickhall/tmp \"Bundle Repository\";1.0.0\n" + "\n" + "The above example retrieves the source archive of version \"1.0.0\"\n" + "of the bundle named \"Bundle Repository\" and saves it to the\n" + "specified local directory."); out.println(""); } else if (command.equals(JAVADOC_CMD)) { out.println(""); out.println("obr " + JAVADOC_CMD + " [" + EXTRACT_SWITCH + "] <local-dir> <bundle-name>[;<version>] ..."); out.println(""); out.println( "This command retrieves the javadoc archives of the specified\n" + "bundles and saves them to the specified local directory; use\n" + "the \"" + EXTRACT_SWITCH + "\" switch to automatically extract the javadoc archives.\n" + "If a bundle name contains spaces, then it must be surrounded\n" + "by quotes. It is also possible to specify a precise version if\n" + "more than one version exists, such as:\n" + "\n" + " obr javadoc /home/rickhall/tmp \"Bundle Repository\";1.0.0\n" + "\n" + "The above example retrieves the javadoc archive of version \"1.0.0\"\n" + "of the bundle named \"Bundle Repository\" and saves it to the\n" + "specified local directory."); out.println(""); } else { out.println("obr " + HELP_CMD + " [" + ADDURL_CMD + " | " + REMOVEURL_CMD + " | " + LISTURL_CMD + " | " + LIST_CMD + " | " + INFO_CMD + " | " + DEPLOY_CMD + " | " + START_CMD + " | " + SOURCE_CMD + " | " + JAVADOC_CMD + "]"); out.println("obr " + ADDURL_CMD + " [<repository-file-url> ...]"); out.println("obr " + REFRESHURL_CMD + " [<repository-file-url> ...]"); out.println("obr " + REMOVEURL_CMD + " [<repository-file-url> ...]"); out.println("obr " + LISTURL_CMD); out.println("obr " + LIST_CMD + " [" + VERBOSE_SWITCH + "] [<string> ...]"); out.println("obr " + INFO_CMD + " <bundle-name>|<bundle-symbolic-name>|<bundle-id>[;<version>] ..."); out.println("obr " + DEPLOY_CMD + " <bundle-name>|<bundle-symbolic-name>|<bundle-id>[;<version>] ..."); out.println("obr " + START_CMD + " <bundle-name>|<bundle-symbolic-name>|<bundle-id>[;<version>] ..."); out.println("obr " + SOURCE_CMD + " [" + EXTRACT_SWITCH + "] <local-dir> <bundle-name>[;<version>] ..."); out.println("obr " + JAVADOC_CMD + " [" + EXTRACT_SWITCH + "] <local-dir> <bundle-name>[;<version>] ..."); } } private static Resource[] addResourceByVersion(Resource[] revisions, Resource resource) { // We want to add the resource into the array of revisions // in descending version sorted order (i.e., newest first) Resource[] sorted = null; if (revisions == null) { sorted = new Resource[] { resource }; } else { Version version = resource.getVersion(); Version middleVersion = null; int top = 0, bottom = revisions.length - 1, middle = 0; while (top <= bottom) { middle = (bottom - top) / 2 + top; middleVersion = revisions[middle].getVersion(); // Sort in reverse version order. int cmp = middleVersion.compareTo(version); if (cmp < 0) { bottom = middle - 1; } else { top = middle + 1; } } // Ignore duplicates. if ((top >= revisions.length) || (revisions[top] != resource)) { sorted = new Resource[revisions.length + 1]; System.arraycopy(revisions, 0, sorted, 0, top); System.arraycopy(revisions, top, sorted, top + 1, revisions.length - top); sorted[top] = resource; } } return sorted; } private static class ParsedCommand { private static final int NAME_IDX = 0; private static final int VERSION_IDX = 1; private boolean m_isResolve = true; private boolean m_isCheck = false; private boolean m_isExtract = false; private boolean m_isVerbose = false; private String m_tokens = null; private String m_dir = null; private String[][] m_targets = new String[0][]; public boolean isResolve() { return m_isResolve; } public void setResolve(boolean b) { m_isResolve = b; } public boolean isCheck() { return m_isCheck; } public void setCheck(boolean b) { m_isCheck = b; } public boolean isExtract() { return m_isExtract; } public void setExtract(boolean b) { m_isExtract = b; } public boolean isVerbose() { return m_isVerbose; } public void setVerbose(boolean b) { m_isVerbose = b; } public String getTokens() { return m_tokens; } public void setTokens(String s) { m_tokens = s; } public String getDirectory() { return m_dir; } public void setDirectory(String s) { m_dir = s; } public int getTargetCount() { return m_targets.length; } public String getTargetId(int i) { if ((i < 0) || (i >= getTargetCount())) { return null; } return m_targets[i][NAME_IDX]; } public String getTargetVersion(int i) { if ((i < 0) || (i >= getTargetCount())) { return null; } return m_targets[i][VERSION_IDX]; } public void addTarget(String name, String version) { String[][] newTargets = new String[m_targets.length + 1][]; System.arraycopy(m_targets, 0, newTargets, 0, m_targets.length); newTargets[m_targets.length] = new String[] { name, version }; m_targets = newTargets; } } }