/****************************************************************************** | |
* 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; | |
} | |
} |