Return-Path: Delivered-To: apmail-incubator-oscar-commits-archive@www.apache.org Received: (qmail 83895 invoked from network); 16 Aug 2005 18:42:01 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 16 Aug 2005 18:42:01 -0000 Received: (qmail 76965 invoked by uid 500); 16 Aug 2005 18:42:01 -0000 Delivered-To: apmail-incubator-oscar-commits-archive@incubator.apache.org Received: (qmail 76940 invoked by uid 500); 16 Aug 2005 18:42:01 -0000 Mailing-List: contact oscar-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: oscar-dev@incubator.apache.org Delivered-To: mailing list oscar-commits@incubator.apache.org Delivered-To: moderator for oscar-commits@incubator.apache.org Received: (qmail 66628 invoked by uid 500); 16 Aug 2005 18:35:29 -0000 Delivered-To: apmail-incubator-oscar-cvs@incubator.apache.org X-ASF-Spam-Status: No, hits=-9.8 required=10.0 tests=ALL_TRUSTED,DRUGS_PAIN,NO_REAL_NAME X-Spam-Check-By: apache.org Message-ID: <20050816183522.80467.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r233031 [2/21] - in /incubator/oscar/trunk: ./ etc/ lib/ src/ src/org/ src/org/apache/ src/org/apache/osgi/ src/org/apache/osgi/bundle/ src/org/apache/osgi/bundle/bundlerepository/ src/org/apache/osgi/bundle/bundlerepository/kxmlsax/ src/or... Date: Tue, 16 Aug 2005 18:34:41 -0000 To: oscar-cvs@incubator.apache.org From: rickhall@apache.org X-Mailer: svnmailer-1.0.3 X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Added: incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/ObrCommandImpl.java URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/ObrCommandImpl.java?rev=233031&view=auto ============================================================================== --- incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/ObrCommandImpl.java (added) +++ incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/ObrCommandImpl.java Tue Aug 16 11:33:34 2005 @@ -0,0 +1,1374 @@ +/* + * Copyright 2005 The Apache Software Foundation + * + * Licensed 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.osgi.bundle.bundlerepository; + +import java.io.*; +import java.util.*; + +import org.apache.osgi.service.bundlerepository.BundleRecord; +import org.apache.osgi.service.bundlerepository.BundleRepository; +import org.apache.osgi.service.shell.Command; +import org.osgi.framework.*; + +public class ObrCommandImpl implements Command +{ + private static final String HELP_CMD = "help"; + private static final String URLS_CMD = "urls"; + 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 INSTALL_CMD = "install"; + private static final String START_CMD = "start"; +// private static final String UPDATE_CMD = "update"; + private static final String SOURCE_CMD = "source"; + + private static final String NODEPS_SWITCH = "-nodeps"; + private static final String CHECK_SWITCH = "-check"; + private static final String EXTRACT_SWITCH = "-x"; + + private BundleContext m_context = null; + private BundleRepository m_repo = null; + + public ObrCommandImpl(BundleContext context, BundleRepository repo) + { + m_context = context; + m_repo = repo; + } + + 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(URLS_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(INSTALL_CMD) || command.equals(START_CMD)) + { + install(commandLine, command, out, err); + } + else if (command.equals(UPDATE_CMD)) + { + update(commandLine, command, out, err); + } +*/ + else if (command.equals(SOURCE_CMD)) + { + source(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 "urls" command. + st.nextToken(); + + int count = st.countTokens(); + String[] urls = new String[count]; + for (int i = 0; i < count; i++) + { + urls[i] = st.nextToken(); + } + + if (count > 0) + { + m_repo.setRepositoryURLs(urls); + } + else + { + urls = m_repo.getRepositoryURLs(); + if (urls != null) + { + for (int i = 0; i < urls.length; i++) + { + out.println(urls[i]); + } + } + else + { + out.println("No repository URLs are set."); + } + } + } + + private void list( + String commandLine, String command, PrintStream out, PrintStream err) + throws IOException + { + // 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(); + + String substr = null; + + for (type = tokenizer.nextToken(); + type != StreamTokenizer.TT_EOF; + type = tokenizer.nextToken()) + { + // Add a space in between tokens. + if (substr == null) + { + substr = ""; + } + else + { + substr += " "; + } + + if ((type == StreamTokenizer.TT_WORD) || + (type == '\'') || (type == '"')) + { + substr += tokenizer.sval.toLowerCase(); + } + } + + boolean found = false; + BundleRecord[] records = m_repo.getBundleRecords(); + for (int recIdx = 0; recIdx < records.length; recIdx++) + { + String name = (String) + records[recIdx].getAttribute(BundleRecord.BUNDLE_NAME); + String symName = (String) + records[recIdx].getAttribute(BundleRecord.BUNDLE_SYMBOLICNAME); + if ((substr == null) || + ((name != null) && (name.toLowerCase().indexOf(substr) >= 0)) || + ((symName != null) && (symName.toLowerCase().indexOf(substr) >= 0))) + { + found = true; + String version = + (String) records[recIdx].getAttribute(BundleRecord.BUNDLE_VERSION); + if (version != null) + { + out.println(name + " (" + version + ")"); + } + else + { + out.println(name); + } + } + } + + if (!found) + { + 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 i = 0; (pc != null) && (i < pc.getTargetCount()); i++) + { + BundleRecord[] records = searchRepository( + pc.getTargetId(i), pc.getTargetVersion(i)); + if (records == null) + { + err.println("Unknown bundle and/or version: " + + pc.getTargetId(i)); + } + else if (records.length > 1) + { + err.println("More than one version exists: " + + pc.getTargetId(i)); + } + else + { + records[0].printAttributes(out); + } + } + } + + 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 + { + for (int i = 0; (pc != null) && (i < pc.getTargetCount()); i++) + { + // Find the target's bundle record. + BundleRecord record = selectNewestVersion( + searchRepository(pc.getTargetId(i), pc.getTargetVersion(i))); + if (record != null) + { + m_repo.deployBundle( + out, // Output stream. + err, // Error stream. + (String) record.getAttribute(BundleRecord.BUNDLE_SYMBOLICNAME), + Util.parseVersionString((String)record.getAttribute(BundleRecord.BUNDLE_VERSION)), + pc.isResolve(), // Resolve dependencies. + command.equals(START_CMD)); // Start. + } + else + { + err.println("Unknown bundle or amiguous version: " + + pc.getTargetId(i)); + } + } + } +/* + private void install( + String commandLine, String command, PrintStream out, PrintStream err) + throws IOException, InvalidSyntaxException + { + // Parse the command line to get all local targets to install. + ParsedCommand pc = parseInstallStart(commandLine); + + // Loop through each local target and try to find + // the corresponding bundle record from the repository. + for (int targetIdx = 0; + (pc != null) && (targetIdx < pc.getTargetCount()); + targetIdx++) + { + // Get the current target's name and version. + String targetName = pc.getTargetId(targetIdx); + String targetVersionString = pc.getTargetVersion(targetIdx); + + // Make sure the bundle is not already installed. + Bundle bundle = findLocalBundle(targetName, targetVersionString); + if (bundle == null) + { + _deploy(pc, command, out, err); + } + else + { + err.println("Already installed: " + targetName); + } + } + } + + private void update( + String commandLine, String command, PrintStream out, PrintStream err) + throws IOException, InvalidSyntaxException + { + // Parse the command line to get all local targets to update. + ParsedCommand pc = parseUpdate(commandLine); + + if (pc.isCheck()) + { + updateCheck(out, err); + } + else + { + // Loop through each local target and try to find + // the corresponding bundle record from the repository. + for (int targetIdx = 0; + (pc != null) && (targetIdx < pc.getTargetCount()); + targetIdx++) + { + // Get the current target's name and version. + String targetName = pc.getTargetId(targetIdx); + String targetVersionString = pc.getTargetVersion(targetIdx); + + // Make sure the bundle is not already installed. + Bundle bundle = findLocalBundle(targetName, targetVersionString); + if (bundle != null) + { + _deploy(pc, command, out, err); + } + else + { + err.println("Not installed: " + targetName); + } + } + } + } + + private void updateCheck(PrintStream out, PrintStream err) + throws IOException + { + Bundle[] bundles = m_context.getBundles(); + + // Loop through each local target and try to find + // the corresponding locally installed bundle. + for (int bundleIdx = 0; + (bundles != null) && (bundleIdx < bundles.length); + bundleIdx++) + { + // Ignore the system bundle. + if (bundles[bundleIdx].getBundleId() == 0) + { + continue; + } + + // Get the local bundle's update location. + String localLoc = (String) + bundles[bundleIdx].getHeaders().get(Constants.BUNDLE_UPDATELOCATION); + if (localLoc == null) + { + // Without an update location, there is no way to + // check for an update, so ignore the bundle. + continue; + } + + // Get the local bundle's version. + String localVersion = (String) + bundles[bundleIdx].getHeaders().get(Constants.BUNDLE_VERSION); + localVersion = (localVersion == null) ? "0.0.0" : localVersion; + + // Get the matching repository bundle records. + BundleRecord[] records = m_repo.getBundleRecords( + (String) bundles[bundleIdx].getHeaders().get(Constants.BUNDLE_NAME)); + + // Loop through all records to see if there is an update. + for (int recordIdx = 0; + (records != null) && (recordIdx < records.length); + recordIdx++) + { + String remoteLoc = (String) + records[recordIdx].getAttribute(BundleRecord.BUNDLE_UPDATELOCATION); + if (remoteLoc == null) + { + continue; + } + + // If the update locations are equal, then compare versions. + if (remoteLoc.equals(localLoc)) + { + String remoteVersion = (String) + records[recordIdx].getAttribute(BundleRecord.BUNDLE_VERSION); + if (remoteVersion != null) + { + int result = Util.compareVersion( + Util.parseVersionString(remoteVersion), + Util.parseVersionString(localVersion)); + if (result > 0) + { + out.println( + records[recordIdx].getAttribute(BundleRecord.BUNDLE_NAME) + + " update available."); + break; + } + } + } + } + } + } +*/ + 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++) + { + BundleRecord[] records = + searchRepository(pc.getTargetId(i), pc.getTargetVersion(i)); + if (records == null) + { + err.println("Unknown bundle and/or version: " + + pc.getTargetId(i)); + } + else if (records.length > 1) + { + err.println("More than one version exists: " + + pc.getTargetId(i)); + } + else + { + String srcURL = (String) + records[0].getAttribute(BundleRecord.BUNDLE_SOURCEURL); + if (srcURL != null) + { + FileUtil.downloadSource( + out, err, srcURL, pc.getDirectory(), pc.isExtract()); + } + else + { + err.println("Missing source URL: " + pc.getTargetId(i)); + } + } + } + } + + private BundleRecord[] searchRepository(String targetId, String targetVersion) + { + // The targetId may be a bundle name or a bundle symbolic name. + // Query for symbolic name first, since it is more specific. If + // that can't be found, then compare bundle names. + BundleRecord[] records = null; + if (targetVersion != null) + { + BundleRecord record = m_repo.getBundleRecord( + targetId, Util.parseVersionString(targetVersion)); + if (record != null) + { + records = new BundleRecord[] { record }; + } + } + else + { + records = m_repo.getBundleRecords(targetId); + } + + if (records == null) + { + List recordList = new ArrayList(); + records = m_repo.getBundleRecords(); + for (int i = 0; (records != null) && (i < records.length); i++) + { + if (targetId.compareToIgnoreCase((String) + records[i].getAttribute(BundleRecord.BUNDLE_NAME)) == 0) + { + int[] v1 = Util.parseVersionString(targetVersion); + int[] v2 = Util.parseVersionString((String) + records[i].getAttribute(BundleRecord.BUNDLE_VERSION)); + if ((targetVersion == null) || + ((targetVersion != null) && (Util.compareVersion(v1, v2) == 0))) + { + recordList.add(records[i]); + } + } + } + records = (recordList.size() == 0) + ? null + : (BundleRecord[]) recordList.toArray(new BundleRecord[recordList.size()]); + } + + return records; + } + + public BundleRecord selectNewestVersion(BundleRecord[] records) + { + int idx = -1; + int[] v = null; + for (int i = 0; (records != null) && (i < records.length); i++) + { + if (i == 0) + { + idx = 0; + v = Util.parseVersionString((String) + records[i].getAttribute(BundleRecord.BUNDLE_VERSION)); + } + else + { + int[] vtmp = Util.parseVersionString((String) + records[i].getAttribute(BundleRecord.BUNDLE_VERSION)); + if (Util.compareVersion(vtmp, v) > 0) + { + idx = i; + v = vtmp; + } + } + } + + return (idx < 0) ? null : records[idx]; + } + + private Bundle findLocalBundle(String name, String versionString) + { + Bundle bundle = null; + + // Get the name only if there is no version, but error + // if there are multiple matches for the same name. + if (versionString == null) + { + // Perhaps the target name is a bundle ID and + // not a name, so try to interpret as a long. + try + { + bundle = m_context.getBundle(Long.parseLong(name)); + } + catch (NumberFormatException ex) + { + // The bundle is not a number, so look for a local + // bundle with the same name. + Bundle[] matchingBundles = findLocalBundlesBySymbolicName(name); + + // If only one matches, then select is. + if (matchingBundles.length == 1) + { + bundle = matchingBundles[0]; + } + } + } + else + { + // Find the local bundle by name and version. + bundle = findLocalBundleByVersion( + name, Util.parseVersionString(versionString)); + } + + return bundle; + } + + private Bundle findLocalBundleByVersion(String symName, int[] version) + { + // Get bundles with matching name. + Bundle[] targets = findLocalBundlesBySymbolicName(symName); + + // Find bundle with matching version. + if (targets.length > 0) + { + for (int i = 0; i < targets.length; i++) + { + String targetName = (String) + targets[i].getHeaders().get(BundleRecord.BUNDLE_SYMBOLICNAME); + int[] targetVersion = Util.parseVersionString((String) + targets[i].getHeaders().get(BundleRecord.BUNDLE_VERSION)); + + if ((targetName != null) && + targetName.equalsIgnoreCase(symName) && + (Util.compareVersion(targetVersion, version) == 0)) + { + return targets[i]; + } + } + } + + return null; + } + + private Bundle[] findLocalBundlesBySymbolicName(String symName) + { + // Get local bundles. + Bundle[] bundles = m_context.getBundles(); + + // Find bundles with matching name. + Bundle[] targets = new Bundle[0]; + for (int i = 0; i < bundles.length; i++) + { + String targetName = (String) + bundles[i].getHeaders().get(BundleRecord.BUNDLE_SYMBOLICNAME); + if (targetName == null) + { + targetName = bundles[i].getLocation(); + } + if ((targetName != null) && targetName.equalsIgnoreCase(symName)) + { + Bundle[] newTargets = new Bundle[targets.length + 1]; + System.arraycopy(targets, 0, newTargets, 0, targets.length); + newTargets[targets.length] = bundles[i]; + targets = newTargets; + } + } + + return targets; + } + + 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 command SWITCH and the token + // equals a command SWITCH, then record it. + if (((expecting & SWITCH) > 0) && tokenizer.sval.equals(NODEPS_SWITCH)) + { + pc.setResolve(false); + expecting = (EOF | 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 ParsedCommand parseUpdate(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 command SWITCH and the token + // equals a NODEPS switch, then record it. + if (((expecting & SWITCH) > 0) && tokenizer.sval.equals(NODEPS_SWITCH)) + { + pc.setResolve(false); + expecting = (EOF | TARGET); + } + // If we are expecting a command SWITCH and the token + // equals a CHECK swithc, then record it. + else if (((expecting & SWITCH) > 0) && tokenizer.sval.equals(CHECK_SWITCH)) + { + pc.setCheck(true); + expecting = (EOF); + } + // 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 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('/', '/'); + + // 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(URLS_CMD)) + { + out.println(""); + out.println("obr " + URLS_CMD + " [ ...]"); + out.println(""); + out.println( + "This command gets or sets the URLs to the repository files\n" + "used by OBR. Specify no arguments to get the current repository\n" + + "URLs or specify a space-delimited list of URLs to change the\n" + + "URLs. Each URL should point to a file containing meta-data about\n" + "available bundles in XML format."); + out.println(""); + } + else if (command.equals(LIST_CMD)) + { + out.println(""); + out.println("obr " + LIST_CMD + " [ ...]"); + 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."); + out.println(""); + } + else if (command.equals(INFO_CMD)) + { + out.println(""); + out.println("obr " + INFO_CMD + + " [;] ..."); + 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 + + " [" + NODEPS_SWITCH + + "] [;] ... | ..."); + out.println(""); + out.println( + "This command tries to install or update the specified bundles\n" + + "and all of their dependencies by default; use the \"" + NODEPS_SWITCH + "\" switch\n" + + "to ignore dependencies. You can specify either the bundle name or\n" + + "the bundle identifier. If a bundle's name contains spaces, then\n" + + "it must be surrounded by quotes. It is also possible to specify a\n" + "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(INSTALL_CMD)) + { + out.println(""); + out.println("obr " + INSTALL_CMD + + " [" + NODEPS_SWITCH + + "] [;] ..."); + out.println(""); + out.println( + "This command installs the specified bundles and all of their\n" + + "dependencies by default; use the \"" + NODEPS_SWITCH + "\" switch to ignore\n" + + "dependencies. If a bundle's name contains spaces, then it\n" + + "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 install \"Bundle Repository\";1.0.0\n" + + "\n" + + "The above example installs version \"1.0.0\" of the bundle\n" + + "named \"Bundle Repository\" and its dependencies. "); + out.println(""); + } +*/ + else if (command.equals(START_CMD)) + { + out.println(""); + out.println("obr " + START_CMD + + " [" + NODEPS_SWITCH + + "] [;] ..."); + out.println(""); + out.println( + "This command installs and starts the specified bundles and all\n" + + "of their dependencies by default; use the \"" + NODEPS_SWITCH + "\" switch to\n" + + "ignore 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(UPDATE_CMD)) + { + out.println(""); + out.println("obr " + UPDATE_CMD + " " + CHECK_SWITCH); + out.println(""); + out.println("obr " + UPDATE_CMD + + " [" + NODEPS_SWITCH + + "] [;] ... | ..."); + out.println(""); + out.println( + "The first form of the command above checks for available updates\n" + "and the second updates the specified locally installed bundles\n" + + "and all of their dependencies by default; use the \"" + NODEPS_SWITCH + "\" switch\n" + + "to ignore dependencies. You can specify either the bundle name or\n" + + "the bundle identifier. If a bundle's name contains spaces, then\n" + + "it must be surrounded by quotes. If a specified bundle is not\n" + "already installed, then this command has no effect. It is also\n" + "possible to specify a precise version if more than one version\n" + "exists, such as:\n" + + "\n" + + " obr update \"Bundle Repository\";1.0.0\n" + + "\n" + + "The above example updates version \"1.0.0\" of the bundle named\n" + + "\"Bundle Repository\" and its dependencies. The update command may\n" + + "install new bundles if the updated bundles have new dependencies."); + out.println(""); + } +*/ + else if (command.equals(SOURCE_CMD)) + { + out.println(""); + out.println("obr " + SOURCE_CMD + + " [" + EXTRACT_SWITCH + + "] [;] ..."); + 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 + { + out.println("obr " + HELP_CMD + + " [" + URLS_CMD + " | " + LIST_CMD +// + " | " + INFO_CMD + " | " + INSTALL_CMD + + " | " + INFO_CMD + + " | " + DEPLOY_CMD + " | " + START_CMD +// + " | " + UPDATE_CMD + " | " + SOURCE_CMD + "]"); + + " | " + SOURCE_CMD + "]"); + out.println("obr " + URLS_CMD + " [ ...]"); + out.println("obr " + LIST_CMD + " [ ...]"); + out.println("obr " + INFO_CMD + + " [;] ..."); + out.println("obr " + DEPLOY_CMD + + " [" + NODEPS_SWITCH + + "] [;] ... | ..."); +// out.println("obr " + INSTALL_CMD +// + " [" + NODEPS_SWITCH +// + "] [;] ..."); + out.println("obr " + START_CMD + + " [" + NODEPS_SWITCH + + "] [;] ..."); +// out.println("obr " + UPDATE_CMD + " " + CHECK_SWITCH); +// out.println("obr " + UPDATE_CMD +// + " [" + NODEPS_SWITCH +// + "] [;] ... | ..."); + out.println("obr " + SOURCE_CMD + + " [" + EXTRACT_SWITCH + + "] [;] ..."); + } + } + + 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 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 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; + } + } +} Added: incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Attribute.java URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Attribute.java?rev=233031&view=auto ============================================================================== --- incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Attribute.java (added) +++ incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Attribute.java Tue Aug 16 11:33:34 2005 @@ -0,0 +1,57 @@ +/* + * Copyright 2005 The Apache Software Foundation + * + * Licensed 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.osgi.bundle.bundlerepository; + +import org.apache.osgi.service.bundlerepository.IAttribute; + +public class R4Attribute implements IAttribute +{ + private String m_name = ""; + private String m_value = ""; + private boolean m_isMandatory = false; + + public R4Attribute(String name, String value, boolean isMandatory) + { + m_name = name; + m_value = value; + m_isMandatory = isMandatory; + } + + /* (non-Javadoc) + * @see org.ungoverned.osgi.service.bundlerepository.Attribute#getName() + **/ + public String getName() + { + return m_name; + } + + /* (non-Javadoc) + * @see org.ungoverned.osgi.service.bundlerepository.Attribute#getValue() + **/ + public String getValue() + { + return m_value; + } + + /* (non-Javadoc) + * @see org.ungoverned.osgi.service.bundlerepository.Attribute#isMandatory() + **/ + public boolean isMandatory() + { + return m_isMandatory; + } +} \ No newline at end of file Added: incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Directive.java URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Directive.java?rev=233031&view=auto ============================================================================== --- incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Directive.java (added) +++ incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Directive.java Tue Aug 16 11:33:34 2005 @@ -0,0 +1,47 @@ +/* + * Copyright 2005 The Apache Software Foundation + * + * Licensed 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.osgi.bundle.bundlerepository; + +import org.apache.osgi.service.bundlerepository.IDirective; + +public class R4Directive implements IDirective +{ + private String m_name = ""; + private String m_value = ""; + + public R4Directive(String name, String value) + { + m_name = name; + m_value = value; + } + + /* (non-Javadoc) + * @see org.ungoverned.osgi.service.bundlerepository.Directive#getName() + **/ + public String getName() + { + return m_name; + } + + /* (non-Javadoc) + * @see org.ungoverned.osgi.service.bundlerepository.Directive#getValue() + **/ + public String getValue() + { + return m_value; + } +} \ No newline at end of file Added: incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Package.java URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Package.java?rev=233031&view=auto ============================================================================== --- incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Package.java (added) +++ incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Package.java Tue Aug 16 11:33:34 2005 @@ -0,0 +1,501 @@ +/* + * Copyright 2005 The Apache Software Foundation + * + * Licensed 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.osgi.bundle.bundlerepository; + +import java.util.*; + +import org.apache.osgi.service.bundlerepository.*; +import org.osgi.framework.Constants; + +// +// This class is essentially the same as the R4Package class in Felix, +// except that I had to add the parseDelimitedString() method. These +// two classes should be unified. +// + +/** + * This is a simple class to encapsulate a package declaration for + * bundle imports and exports for the bundle repository. +**/ +public class R4Package implements IPackage +{ + private String m_id = ""; + private IDirective[] m_directives = null; + private IAttribute[] m_attrs = null; + private IVersion m_versionLow = null; + private IVersion m_versionHigh = null; + private boolean m_isOptional = false; + + protected R4Package(R4Package pkg) + { + m_id = pkg.m_id; + m_directives = pkg.m_directives; + m_attrs = pkg.m_attrs; + m_versionLow = pkg.m_versionLow; + m_versionHigh = pkg.m_versionHigh; + m_isOptional = pkg.m_isOptional; + } + + public R4Package(String id, IDirective[] directives, IAttribute[] attrs) + { + m_id = id; + m_directives = (directives == null) ? new IDirective[0] : directives; + m_attrs = (attrs == null) ? new IAttribute[0] : attrs; + + // Find mandatory and resolution directives, if present. + String mandatory = ""; + for (int i = 0; i < m_directives.length; i++) + { + if (m_directives[i].getName().equals(Constants.MANDATORY_DIRECTIVE)) + { + mandatory = m_directives[i].getValue(); + } + else if (m_directives[i].getName().equals(Constants.RESOLUTION_DIRECTIVE)) + { + m_isOptional = m_directives[i].getValue().equals(Constants.RESOLUTION_OPTIONAL); + } + } + + // Parse mandatory directive and mark specified + // attributes as mandatory. + StringTokenizer tok = new StringTokenizer(mandatory, ""); + while (tok.hasMoreTokens()) + { + // Get attribute name. + String attrName = tok.nextToken().trim(); + // Find attribute and mark it as mandatory. + boolean found = false; + for (int i = 0; (!found) && (i < m_attrs.length); i++) + { + if (m_attrs[i].getName().equals(attrName)) + { + m_attrs[i] = new R4Attribute( + m_attrs[i].getName(), m_attrs[i].getValue(), true); + found = true; + } + } + // If a specified mandatory attribute was not found, + // then error. + if (!found) + { + throw new IllegalArgumentException( + "Mandatory attribute '" + attrName + "' does not exist."); + } + } + + // Find and parse version attribute, if present. + String versionInterval = "0.0.0"; + for (int i = 0; i < m_attrs.length; i++) + { + if (m_attrs[i].getName().equals(Constants.VERSION_ATTRIBUTE) || + m_attrs[i].getName().equals(Constants.PACKAGE_SPECIFICATION_VERSION)) + { + // Normalize version attribute name. + m_attrs[i] = new R4Attribute( + Constants.VERSION_ATTRIBUTE, m_attrs[i].getValue(), + m_attrs[i].isMandatory()); + versionInterval = m_attrs[i].getValue(); + break; + } + } + + IVersion[] versions = parseVersionInterval(versionInterval); + m_versionLow = versions[0]; + if (versions.length == 2) + { + m_versionHigh = versions[1]; + } + } + + public String getId() + { + return m_id; + } + + public IDirective[] getDirectives() + { + return m_directives; + } + + public IAttribute[] getAttributes() + { + return m_attrs; + } + + public IVersion getVersionLow() + { + return m_versionLow; + } + + public IVersion getVersionHigh() + { + return m_versionHigh; + } + + public boolean isOptional() + { + return m_isOptional; + } + + // PREVIOUSLY PART OF COMPATIBILITY POLICY. + public boolean doesSatisfy(IPackage pkg) + { + // For packages to be compatible, they must have the + // same name. + if (!m_id.equals(pkg.getId())) + { + return false; + } + + return isVersionInRange(m_versionLow, pkg.getVersionLow(), pkg.getVersionHigh()) + && doAttributesMatch(pkg); + } + + // PREVIOUSLY PART OF COMPATIBILITY POLICY. + public static boolean isVersionInRange(IVersion version, IVersion low, IVersion high) + { + // We might not have an upper end to the range. + if (high == null) + { + return (version.compareTo(low) >= 0); + } + else if (low.isInclusive() && high.isInclusive()) + { + return (version.compareTo(low) >= 0) && (version.compareTo(high) <= 0); + } + else if (high.isInclusive()) + { + return (version.compareTo(low) > 0) && (version.compareTo(high) <= 0); + } + else if (low.isInclusive()) + { + return (version.compareTo(low) >= 0) && (version.compareTo(high) < 0); + } + + return (version.compareTo(low) > 0) && (version.compareTo(high) < 0); + } + + private boolean doAttributesMatch(IPackage pkg) + { + // Cycle through all attributes of the specified package + // and make sure their values match the attribute values + // of this package. + for (int attrIdx = 0; attrIdx < pkg.getAttributes().length; attrIdx++) + { + // Get current attribute from specified package. + IAttribute attr = pkg.getAttributes()[attrIdx]; + + // Ignore version attribute, since it is a special case that + // has already been compared using isVersionInRange() before + // the call to this method was made. + if (attr.getName().equals(Constants.VERSION_ATTRIBUTE)) + { + continue; + } + + // Check if this package has the same attribute. + boolean found = false; + for (int thisAttrIdx = 0; + (!found) && (thisAttrIdx < m_attrs.length); + thisAttrIdx++) + { + // Get current attribute for this package. + IAttribute thisAttr = m_attrs[thisAttrIdx]; + // Check if the attribute names are equal. + if (attr.getName().equals(thisAttr.getName())) + { + // If the values are not equal, then return false immediately. + // We should not compare version values here, since they are + // a special case and have already been compared by a call to + // isVersionInRange() before getting here; however, it is + // possible for version to be mandatory, so make sure it is + // present below. + if (!attr.getValue().equals(thisAttr.getValue())) + { + return false; + } + found = true; + } + } + // If the attribute was not found, then return false. + if (!found) + { + return false; + } + } + + // Now, cycle through all attributes of this package and verify that + // all mandatory attributes are present in the speceified package. + for (int thisAttrIdx = 0; thisAttrIdx < m_attrs.length; thisAttrIdx++) + { + // Get current attribute for this package. + IAttribute thisAttr = m_attrs[thisAttrIdx]; + + // If the attribute is mandatory, then make sure + // the specified package has the attribute. + if (thisAttr.isMandatory()) + { + boolean found = false; + for (int attrIdx = 0; + (!found) && (attrIdx < pkg.getAttributes().length); + attrIdx++) + { + // Get current attribute from specified package. + IAttribute attr = pkg.getAttributes()[attrIdx]; + + // Check if the attribute names are equal + // and set found flag. + if (thisAttr.getName().equals(attr.getName())) + { + found = true; + } + } + // If not found, then return false. + if (!found) + { + return false; + } + } + } + + return true; + } + + public String toString() + { + String msg = getId(); + for (int i = 0; (m_directives != null) && (i < m_directives.length); i++) + { + msg = msg + " [" + m_directives[i].getName() + ":="+ m_directives[i].getName() + "]"; + } + for (int i = 0; (m_attrs != null) && (i < m_attrs.length); i++) + { + msg = msg + " [" + m_attrs[i].getValue() + "="+ m_attrs[i].getValue() + "]"; + } + return msg; + } + + // Like this: pkg1; pkg2; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2, + // pkg1; pkg2; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2 + public static IPackage[] parseImportOrExportHeader(String s) + { + IPackage[] pkgs = null; + if (s != null) + { + if (s.length() == 0) + { + throw new IllegalArgumentException( + "The import and export headers cannot be an empty string."); + } + String[] ss = parseDelimitedString(s, ","); // FelixConstants.CLASS_PATH_SEPARATOR + pkgs = parsePackageStrings(ss); + } + return (pkgs == null) ? new IPackage[0] : pkgs; + } + + // Like this: pkg1; pkg2; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2 + public static IPackage[] parsePackageStrings(String[] ss) + throws IllegalArgumentException + { + if (ss == null) + { + return null; + } + + List completeList = new ArrayList(); + for (int ssIdx = 0; ssIdx < ss.length; ssIdx++) + { + // Break string into semi-colon delimited pieces. + String[] pieces = parseDelimitedString( + ss[ssIdx], ";"); // FelixConstants.PACKAGE_SEPARATOR + + // Count the number of different packages; packages + // will not have an '=' in their string. This assumes + // that packages come first, before directives and + // attributes. + int pkgCount = 0; + for (int pieceIdx = 0; pieceIdx < pieces.length; pieceIdx++) + { + if (pieces[pieceIdx].indexOf('=') >= 0) + { + break; + } + pkgCount++; + } + + // Error if no packages were specified. + if (pkgCount == 0) + { + throw new IllegalArgumentException( + "No packages specified on import: " + ss[ssIdx]); + } + + // Parse the directives/attributes. + IDirective[] dirs = new IDirective[pieces.length - pkgCount]; + IAttribute[] attrs = new IAttribute[pieces.length - pkgCount]; + int dirCount = 0, attrCount = 0; + int idx = -1; + String sep = null; + for (int pieceIdx = pkgCount; pieceIdx < pieces.length; pieceIdx++) + { + // Check if it is a directive. + if ((idx = pieces[pieceIdx].indexOf(":=")) >= 0) // FelixConstants.DIRECTIVE_SEPARATOR + { + sep = ":="; // FelixConstants.DIRECTIVE_SEPARATOR + } + // Check if it is an attribute. + else if ((idx = pieces[pieceIdx].indexOf("=")) >= 0) // FelixConstants.ATTRIBUTE_SEPARATOR + { + sep = "="; // FelixConstants.ATTRIBUTE_SEPARATOR + } + // It is an error. + else + { + throw new IllegalArgumentException( + "Not a directive/attribute: " + ss[ssIdx]); + } + + String key = pieces[pieceIdx].substring(0, idx).trim(); + String value = pieces[pieceIdx].substring(idx + sep.length()).trim(); + + // Remove quotes, if value is quoted. + if (value.startsWith("\"") && value.endsWith("\"")) + { + value = value.substring(1, value.length() - 1); + } + + // Save the directive/attribute in the appropriate array. + if (sep.equals(":=")) // FelixConstants.DIRECTIVE_SEPARATOR + { + dirs[dirCount++] = new R4Directive(key, value); + } + else + { + attrs[attrCount++] = new R4Attribute(key, value, false); + } + } + + // Shrink directive array. + IDirective[] dirsFinal = new IDirective[dirCount]; + System.arraycopy(dirs, 0, dirsFinal, 0, dirCount); + // Shrink attribute array. + IAttribute[] attrsFinal = new IAttribute[attrCount]; + System.arraycopy(attrs, 0, attrsFinal, 0, attrCount); + + // Create package attributes for each package and + // set directives/attributes. Add each package to + // completel list of packages. + IPackage[] pkgs = new IPackage[pkgCount]; + for (int pkgIdx = 0; pkgIdx < pkgCount; pkgIdx++) + { + pkgs[pkgIdx] = new R4Package(pieces[pkgIdx], dirsFinal, attrsFinal); + completeList.add(pkgs[pkgIdx]); + } + } + + IPackage[] ips = (IPackage[]) + completeList.toArray(new IPackage[completeList.size()]); + return ips; + } + + public static IVersion[] parseVersionInterval(String interval) + { + // Check if the version is an interval. + if (interval.indexOf(',') >= 0) + { + String s = interval.substring(1, interval.length() - 1); + String vlo = s.substring(0, s.indexOf(',')); + String vhi = s.substring(s.indexOf(',') + 1, s.length()); + return new IVersion[] { + new R4Version(vlo, (interval.charAt(0) == '[')), + new R4Version(vhi, (interval.charAt(interval.length() - 1) == ']')) + }; + } + else + { + return new IVersion[] { new R4Version(interval, true) }; + } + } + + /** + * Parses delimited string and returns an array containing the tokens. This + * parser obeys quotes, so the delimiter character will be ignored if it is + * inside of a quote. This method assumes that the quote character is not + * included in the set of delimiter characters. + * @param value the delimited string to parse. + * @param delim the characters delimiting the tokens. + * @return an array of string tokens or null if there were no tokens. + **/ + public static String[] parseDelimitedString(String value, String delim) + { + if (value == null) + { + value = ""; + } + + List list = new ArrayList(); + + int CHAR = 1; + int DELIMITER = 2; + int STARTQUOTE = 4; + int ENDQUOTE = 8; + + StringBuffer sb = new StringBuffer(); + + int expecting = (CHAR | DELIMITER | STARTQUOTE); + + for (int i = 0; i < value.length(); i++) + { + char c = value.charAt(i); + + boolean isDelimiter = (delim.indexOf(c) >= 0); + boolean isQuote = (c == '"'); + + if (isDelimiter && ((expecting & DELIMITER) > 0)) + { + list.add(sb.toString().trim()); + sb.delete(0, sb.length()); + expecting = (CHAR | DELIMITER | STARTQUOTE); + } + else if (isQuote && ((expecting & STARTQUOTE) > 0)) + { + sb.append(c); + expecting = CHAR | ENDQUOTE; + } + else if (isQuote && ((expecting & ENDQUOTE) > 0)) + { + sb.append(c); + expecting = (CHAR | STARTQUOTE | DELIMITER); + } + else if ((expecting & CHAR) > 0) + { + sb.append(c); + } + else + { + throw new IllegalArgumentException("Invalid delimited string: " + value); + } + } + + if (sb.length() > 0) + { + list.add(sb.toString().trim()); + } + + return (String[]) list.toArray(new String[list.size()]); + } +} \ No newline at end of file Added: incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Version.java URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Version.java?rev=233031&view=auto ============================================================================== --- incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Version.java (added) +++ incubator/oscar/trunk/src/org/apache/osgi/bundle/bundlerepository/R4Version.java Tue Aug 16 11:33:34 2005 @@ -0,0 +1,216 @@ +/* + * Copyright 2005 The Apache Software Foundation + * + * Licensed 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.osgi.bundle.bundlerepository; + +import java.util.StringTokenizer; + +import org.apache.osgi.service.bundlerepository.IVersion; + +public class R4Version implements Comparable, IVersion +{ + private int m_major = 0; + private int m_minor = 0; + private int m_micro = 0; + private String m_qualifier = ""; + private boolean m_isInclusive = true; + + private static final String SEPARATOR = "."; + + public R4Version(String versionString) + { + this(versionString, true); + } + + public R4Version(String versionString, boolean isInclusive) + { + if (versionString == null) + { + versionString = "0.0.0"; + } + Object[] objs = parseVersion(versionString); + m_major = ((Integer) objs[0]).intValue(); + m_minor = ((Integer) objs[1]).intValue(); + m_micro = ((Integer) objs[2]).intValue(); + m_qualifier = (String) objs[3]; + m_isInclusive = isInclusive; + } + + private static Object[] parseVersion(String versionString) + { + String s = versionString.trim(); + Object[] objs = new Object[4]; + objs[0] = objs[1] = objs[2] = new Integer(0); + objs[3] = ""; + StringTokenizer tok = new StringTokenizer(s, SEPARATOR); + try + { + objs[0] = Integer.valueOf(tok.nextToken()); + if (tok.hasMoreTokens()) + { + objs[1] = Integer.valueOf(tok.nextToken()); + if (tok.hasMoreTokens()) + { + objs[2] = Integer.valueOf(tok.nextToken()); + if (tok.hasMoreTokens()) + { + objs[3] = tok.nextToken(); + } + } + } + } + catch (NumberFormatException ex) + { + throw new IllegalArgumentException("Invalid version: " + versionString); + } + + if ((((Integer) objs[0]).intValue() < 0) || + (((Integer) objs[0]).intValue() < 0) || + (((Integer) objs[0]).intValue() < 0)) + { + throw new IllegalArgumentException("Invalid version: " + versionString); + } + + return objs; + } + + /* (non-Javadoc) + * @see org.ungoverned.osgi.service.bundlerepository.Version#equals(java.lang.Object) + **/ + public boolean equals(Object object) + { + if (!(object instanceof R4Version)) + { + return false; + } + IVersion v = (IVersion) object; + return + (v.getMajorComponent() == m_major) && + (v.getMinorComponent() == m_minor) && + (v.getMicroComponent() == m_micro) && + (v.getQualifierComponent().equals(m_qualifier)); + } + + /* (non-Javadoc) + * @see org.ungoverned.osgi.service.bundlerepository.Version#getMajorComponent() + **/ + public int getMajorComponent() + { + return m_major; + } + + /* (non-Javadoc) + * @see org.ungoverned.osgi.service.bundlerepository.Version#getMinorComponent() + **/ + public int getMinorComponent() + { + return m_minor; + } + + /* (non-Javadoc) + * @see org.ungoverned.osgi.service.bundlerepository.Version#getMicroComponent() + **/ + public int getMicroComponent() + { + return m_micro; + } + + /* (non-Javadoc) + * @see org.ungoverned.osgi.service.bundlerepository.Version#getQualifierComponent() + **/ + public String getQualifierComponent() + { + return m_qualifier; + } + + /* (non-Javadoc) + * @see org.ungoverned.osgi.service.bundlerepository.Version#isInclusive() + **/ + public boolean isInclusive() + { + return m_isInclusive; + } + + /* (non-Javadoc) + * @see org.ungoverned.osgi.service.bundlerepository.Version#compareTo(java.lang.Object) + **/ + public int compareTo(Object o) + { + if (!(o instanceof R4Version)) + throw new ClassCastException(); + + if (equals(o)) + return 0; + + if (isGreaterThan((IVersion) o)) + return 1; + + return -1; + } + + private boolean isGreaterThan(IVersion v) + { + if (v == null) + { + return false; + } + + if (m_major > v.getMajorComponent()) + { + return true; + } + if (m_major < v.getMajorComponent()) + { + return false; + } + if (m_minor > v.getMinorComponent()) + { + return true; + } + if (m_minor < v.getMinorComponent()) + { + return false; + } + if (m_micro > v.getMicroComponent()) + { + return true; + } + if (m_micro < v.getMicroComponent()) + { + return false; + } + if (m_qualifier.compareTo(v.getQualifierComponent()) > 0) + { + return true; + } + else + { + return false; + } + } + + /* (non-Javadoc) + * @see org.ungoverned.osgi.service.bundlerepository.Version#toString() + **/ + public String toString() + { + if (m_qualifier.length() == 0) + { + return m_major + "." + m_minor + "." + m_micro; + } + return m_major + "." + m_minor + "." + m_micro + "." + m_qualifier; + } +} \ No newline at end of file