blob: a1b43009f9f50286041829c2acb1b810fa20aacf [file] [log] [blame]
/**
* 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.karaf.testing;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
/**
* Utility class to parse a standard OSGi header with paths.
*
* @author <a href="mailto:dev@geronimo.apache.org">Apache Geronimo Project</a>
* @version $Rev: 786132 $, $Date: 2009-06-18 17:47:58 +0200 (Thu, 18 Jun 2009) $
*/
public final class HeaderParser {
// Private constructor for static final class
private HeaderParser() {
}
public static InputStream wireTapManifest( InputStream is, Manifest mf ) throws IOException {
BufferedInputStream bis = new BufferedInputStream( is, 64 * 1024 );
bis.mark( 64 * 1024 );
JarInputStream jis = new JarInputStream( bis );
mf.getMainAttributes().putAll( jis.getManifest().getMainAttributes() );
mf.getEntries().putAll( jis.getManifest().getEntries() );
bis.reset();
return bis;
}
/**
* Parse a given OSGi header into a list of paths
*
* @param header the OSGi header to parse
* @return the list of paths extracted from this header
*/
public static List<PathElement> parseHeader(String header) {
List<PathElement> elements = new ArrayList<PathElement>();
if (header == null || header.trim().length() == 0) {
return elements;
}
String[] clauses = parseDelimitedString(header, ",");
for (String clause : clauses) {
String[] tokens = clause.split(";");
if (tokens.length < 1) {
throw new IllegalArgumentException("Invalid header clause: " + clause);
}
PathElement elem = new PathElement(tokens[0].trim());
elements.add(elem);
for (int i = 1; i < tokens.length; i++) {
int pos = tokens[i].indexOf('=');
if (pos != -1) {
if (pos > 0 && tokens[i].charAt(pos - 1) == ':') {
String name = tokens[i].substring(0, pos - 1).trim();
String value = tokens[i].substring(pos + 1).trim();
if (value.startsWith("\"") && value.endsWith("\"")) {
value = value.substring(1, value.length() - 1);
}
elem.addDirective(name, value);
} else {
String name = tokens[i].substring(0, pos).trim();
String value = tokens[i].substring(pos + 1).trim();
if (value.startsWith("\"") && value.endsWith("\"")) {
value = value.substring(1, value.length() - 1);
}
elem.addAttribute(name, value);
}
} else {
elem = new PathElement(tokens[i].trim());
elements.add(elem);
}
}
}
return elements;
}
/**
* 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()]);
}
public static class PathElement {
private String path;
private Map<String, String> attributes;
private Map<String, String> directives;
public PathElement(String path) {
this.path = path;
this.attributes = new HashMap<String, String>();
this.directives = new HashMap<String, String>();
}
public String getName() {
return this.path;
}
public Map<String, String> getAttributes() {
return attributes;
}
public String getAttribute(String name) {
return attributes.get(name);
}
public void addAttribute(String name, String value) {
attributes.put(name, value);
}
public Map<String, String> getDirectives() {
return directives;
}
public String getDirective(String name) {
return directives.get(name);
}
public void addDirective(String name, String value) {
directives.put(name, value);
}
public String toString() {
StringBuilder sb = new StringBuilder(this.path);
for (Map.Entry<String,String> directive : this.directives.entrySet()) {
sb.append(";").append(directive.getKey()).append(":=").append(directive.getValue());
}
for (Map.Entry<String,String> attribute : this.attributes.entrySet()) {
sb.append(";").append(attribute.getKey()).append("=").append(attribute.getValue());
}
return sb.toString();
}
}
}