blob: 46787d2a81a21c160cc560543ed28e56cc6329da [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2006, 2010 VMware Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
* is available at http://www.opensource.org/licenses/apache2.0.php.
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
* VMware Inc.
*****************************************************************************/
package org.eclipse.gemini.blueprint.io.internal;
import java.util.ArrayList;
import java.util.List;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import org.springframework.util.StringUtils;
/**
* Utility class for handling various header operations such as splitting a
* manifest header into packages or extracting the version from a certain entry.
*
* @author Costin Leau
*
*/
public abstract class OsgiHeaderUtils {
private static final char ROUND_BRACKET_CHAR = '(';
private static final char SQUARE_BRACKET_CHAR = '[';
private static final char QUOTE_CHAR = '\"';
private static final char COMMA_CHAR = ',';
private static final String SEMI_COLON = ";";
private static final String DOUBLE_QUOTE = "\"";
private static final String DEFAULT_VERSION = "0.0.0";
public static String[] getBundleClassPath(Bundle bundle) {
return getHeaderAsTrimmedStringArray(bundle, Constants.BUNDLE_CLASSPATH);
}
public static String[] getRequireBundle(Bundle bundle) {
return getHeaderWithAttributesAsTrimmedStringArray(bundle, Constants.REQUIRE_BUNDLE);
}
private static String[] getHeaderAsTrimmedStringArray(Bundle bundle, String header) {
if (bundle == null || !StringUtils.hasText(header))
return new String[0];
String headerContent = (String) bundle.getHeaders().get(header);
String[] entries = StringUtils.commaDelimitedListToStringArray(headerContent);
for (int i = 0; i < entries.length; i++) {
entries[i] = entries[i].trim();
}
return entries;
}
private static String[] getHeaderWithAttributesAsTrimmedStringArray(Bundle bundle, String header) {
if (bundle == null || !StringUtils.hasText(header))
return new String[0];
String headerContent = (String) bundle.getHeaders().get(header);
if (!StringUtils.hasText(headerContent))
return new String[0];
// consider , as a delimiter only if a quote is not encountered
List<String> tokens = new ArrayList<String>(2);
StringBuilder token = new StringBuilder();
boolean ignoreComma = false;
for (int stringIndex = 0; stringIndex < headerContent.length(); stringIndex++) {
char currentChar = headerContent.charAt(stringIndex);
if (currentChar == COMMA_CHAR) {
if (ignoreComma) {
token.append(currentChar);
}
else {
tokens.add(token.toString().trim());
token.delete(0, token.length());
ignoreComma = false;
}
}
else {
if (currentChar == QUOTE_CHAR) {
ignoreComma = !ignoreComma;
}
token.append(currentChar);
}
}
tokens.add(token.toString().trim());
return tokens.toArray(new String[tokens.size()]);
}
/**
* Parses the required bundle entry to determine the bundle symbolic name
* and version.
*
* @param string required bundle entry
* @return returns an array of strings with 2 entries, the first being the
* bundle sym name, the second the version (or 0.0.0 if nothing is
* specified).
*/
public static String[] parseRequiredBundleString(String entry) {
String[] value = new String[2];
// determine the bundle symbolic name
int index = entry.indexOf(SEMI_COLON);
// there is at least one flag so extract the sym name
if (index > 0) {
value[0] = entry.substring(0, index);
}
// no flag, short circuit
else {
value[0] = entry;
value[1] = DEFAULT_VERSION;
return value;
}
// look for bundle-version
index = entry.indexOf(Constants.BUNDLE_VERSION_ATTRIBUTE);
if (index > 0) {
// skip the =
int firstQuoteIndex = index + Constants.BUNDLE_VERSION_ATTRIBUTE.length() + 1;
// check if the version is quoted
boolean isQuoted = entry.charAt(firstQuoteIndex) == QUOTE_CHAR;
// no quote means automatically no range
if (!isQuoted) {
int nextAttribute = entry.indexOf(SEMI_COLON, firstQuoteIndex);
value[1] = (nextAttribute > -1 ? entry.substring(firstQuoteIndex, nextAttribute)
: entry.substring(firstQuoteIndex));
}
else {
// check if a range or a number is specified
char testChar = entry.charAt(firstQuoteIndex + 1);
boolean isRange = (testChar == SQUARE_BRACKET_CHAR || testChar == ROUND_BRACKET_CHAR);
int secondQuoteStartIndex = (isRange ? firstQuoteIndex + 4 : firstQuoteIndex + 1);
int numberStart = (isRange ? firstQuoteIndex + 2 : firstQuoteIndex + 1);
int numberEnd = entry.indexOf(DOUBLE_QUOTE, secondQuoteStartIndex) - (isRange ? 1 : 0);
value[1] = entry.substring(numberStart, numberEnd);
// if it's a range, append the interval notation
if (isRange) {
value[1] = entry.charAt(firstQuoteIndex + 1) + value[1] + entry.charAt(numberEnd);
}
}
}
else {
value[1] = DEFAULT_VERSION;
}
return value;
}
}