001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.xbean.osgi.bundle.util; 020 021import java.util.ArrayList; 022import java.util.HashMap; 023import java.util.List; 024import java.util.Map; 025 026/** 027 * Utility class to parse standard OSGi headers. 028 * 029 * @version $Rev: 1167021 $, $Date: 2011-09-09 09:01:22 +0200 (Fri, 09 Sep 2011) $ 030 */ 031public class HeaderParser { 032 033 /** 034 * Parse a given OSGi header into a list of header elements. 035 * 036 * @param header the OSGi header to parse 037 * @return the list of header elements extracted from this header 038 */ 039 public static List<HeaderElement> parseHeader(String header) { 040 List<HeaderElement> elements = new ArrayList<HeaderElement>(); 041 if (header == null || header.trim().length() == 0) { 042 return elements; 043 } 044 List<String> clauses = parseDelimitedString(header, ",", false); 045 for (String clause : clauses) { 046 String[] tokens = clause.split(";"); 047 if (tokens.length < 1) { 048 throw new IllegalArgumentException("Invalid header clause: " + clause); 049 } 050 HeaderElement elem = new HeaderElement(tokens[0].trim()); 051 elements.add(elem); 052 int beginIndex = elements.size() - 1; 053 for (int i = 1; i < tokens.length; i++) { 054 int pos = tokens[i].indexOf('='); 055 if (pos != -1) { 056 if (pos > 0 && tokens[i].charAt(pos - 1) == ':') { 057 String name = tokens[i].substring(0, pos - 1).trim(); 058 String value = tokens[i].substring(pos + 1).trim(); 059 elem.addDirective(name, value); 060 } else { 061 String name = tokens[i].substring(0, pos).trim(); 062 String value = tokens[i].substring(pos + 1).trim(); 063 elem.addAttribute(name, value); 064 } 065 } else { 066 elem = new HeaderElement(tokens[i].trim()); 067 elements.add(elem); 068 } 069 } 070 for (; beginIndex < elements.size() - 1; beginIndex++) { 071 HeaderElement headerElement = elements.get(beginIndex); 072 headerElement.getAttributes().putAll(elem.getAttributes()); 073 headerElement.getDirectives().putAll(elem.getDirectives()); 074 } 075 } 076 return elements; 077 } 078 079 private static List<String> parseDelimitedString(String value, String delim, boolean includeQuotes) { 080 if (value == null) { 081 value = ""; 082 } 083 084 List<String> list = new ArrayList<String>(); 085 086 int CHAR = 1; 087 int DELIMITER = 2; 088 int STARTQUOTE = 4; 089 int ENDQUOTE = 8; 090 091 StringBuffer sb = new StringBuffer(); 092 093 int expecting = (CHAR | DELIMITER | STARTQUOTE); 094 095 for (int i = 0; i < value.length(); i++) { 096 char c = value.charAt(i); 097 098 boolean isDelimiter = (delim.indexOf(c) >= 0); 099 boolean isQuote = (c == '"'); 100 101 if (isDelimiter && ((expecting & DELIMITER) > 0)) { 102 list.add(sb.toString().trim()); 103 sb.delete(0, sb.length()); 104 expecting = (CHAR | DELIMITER | STARTQUOTE); 105 } else if (isQuote && ((expecting & STARTQUOTE) > 0)) { 106 if (includeQuotes) { 107 sb.append(c); 108 } 109 expecting = CHAR | ENDQUOTE; 110 } else if (isQuote && ((expecting & ENDQUOTE) > 0)) { 111 if (includeQuotes) { 112 sb.append(c); 113 } 114 expecting = (CHAR | STARTQUOTE | DELIMITER); 115 } else if ((expecting & CHAR) > 0) { 116 sb.append(c); 117 } else { 118 throw new IllegalArgumentException("Invalid delimited string: " + value); 119 } 120 } 121 122 if (sb.length() > 0) { 123 list.add(sb.toString().trim()); 124 } 125 126 return list; 127 } 128 129 public static class HeaderElement { 130 131 private String path; 132 private Map<String, String> attributes; 133 private Map<String, String> directives; 134 135 public HeaderElement(String path) { 136 this.path = path; 137 this.attributes = new HashMap<String, String>(); 138 this.directives = new HashMap<String, String>(); 139 } 140 141 public String getName() { 142 return this.path; 143 } 144 145 public Map<String, String> getAttributes() { 146 return attributes; 147 } 148 149 public String getAttribute(String name) { 150 return attributes.get(name); 151 } 152 153 public void addAttribute(String name, String value) { 154 attributes.put(name, value); 155 } 156 157 public Map<String, String> getDirectives() { 158 return directives; 159 } 160 161 public String getDirective(String name) { 162 return directives.get(name); 163 } 164 165 public void addDirective(String name, String value) { 166 directives.put(name, value); 167 } 168 169 @Override 170 public String toString() { 171 return "HeaderElement [path=" + path + ", attributes=" + attributes + ", directives=" + directives + "]"; 172 } 173 174 @Override 175 public int hashCode() { 176 final int prime = 31; 177 int result = 1; 178 result = prime * result + ((attributes == null) ? 0 : attributes.hashCode()); 179 result = prime * result + ((directives == null) ? 0 : directives.hashCode()); 180 result = prime * result + ((path == null) ? 0 : path.hashCode()); 181 return result; 182 } 183 184 @Override 185 public boolean equals(Object obj) { 186 if (this == obj) 187 return true; 188 if (obj == null) 189 return false; 190 if (getClass() != obj.getClass()) 191 return false; 192 HeaderElement other = (HeaderElement) obj; 193 if (attributes == null) { 194 if (other.attributes != null) 195 return false; 196 } else if (!attributes.equals(other.attributes)) 197 return false; 198 if (directives == null) { 199 if (other.directives != null) 200 return false; 201 } else if (!directives.equals(other.directives)) 202 return false; 203 if (path == null) { 204 if (other.path != null) 205 return false; 206 } else if (!path.equals(other.path)) 207 return false; 208 return true; 209 } 210 } 211}