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 */
019 package org.apache.xbean.osgi.bundle.util;
020
021 import java.util.ArrayList;
022 import java.util.HashMap;
023 import java.util.List;
024 import java.util.Map;
025
026 /**
027 * Utility class to parse standard OSGi headers.
028 *
029 * @version $Rev: 1160977 $, $Date: 2011-08-24 13:02:21 +0800 (Wed, 24 Aug 2011) $
030 */
031 public 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 for (int i = 1; i < tokens.length; i++) {
053 int pos = tokens[i].indexOf('=');
054 if (pos != -1) {
055 if (pos > 0 && tokens[i].charAt(pos - 1) == ':') {
056 String name = tokens[i].substring(0, pos - 1).trim();
057 String value = tokens[i].substring(pos + 1).trim();
058 elem.addDirective(name, value);
059 } else {
060 String name = tokens[i].substring(0, pos).trim();
061 String value = tokens[i].substring(pos + 1).trim();
062 elem.addAttribute(name, value);
063 }
064 } else {
065 elem = new HeaderElement(tokens[i].trim());
066 elements.add(elem);
067 }
068 }
069 }
070 return elements;
071 }
072
073 private static List<String> parseDelimitedString(String value, String delim, boolean includeQuotes) {
074 if (value == null) {
075 value = "";
076 }
077
078 List<String> list = new ArrayList<String>();
079
080 int CHAR = 1;
081 int DELIMITER = 2;
082 int STARTQUOTE = 4;
083 int ENDQUOTE = 8;
084
085 StringBuffer sb = new StringBuffer();
086
087 int expecting = (CHAR | DELIMITER | STARTQUOTE);
088
089 for (int i = 0; i < value.length(); i++) {
090 char c = value.charAt(i);
091
092 boolean isDelimiter = (delim.indexOf(c) >= 0);
093 boolean isQuote = (c == '"');
094
095 if (isDelimiter && ((expecting & DELIMITER) > 0)) {
096 list.add(sb.toString().trim());
097 sb.delete(0, sb.length());
098 expecting = (CHAR | DELIMITER | STARTQUOTE);
099 } else if (isQuote && ((expecting & STARTQUOTE) > 0)) {
100 if (includeQuotes) {
101 sb.append(c);
102 }
103 expecting = CHAR | ENDQUOTE;
104 } else if (isQuote && ((expecting & ENDQUOTE) > 0)) {
105 if (includeQuotes) {
106 sb.append(c);
107 }
108 expecting = (CHAR | STARTQUOTE | DELIMITER);
109 } else if ((expecting & CHAR) > 0) {
110 sb.append(c);
111 } else {
112 throw new IllegalArgumentException("Invalid delimited string: " + value);
113 }
114 }
115
116 if (sb.length() > 0) {
117 list.add(sb.toString().trim());
118 }
119
120 return list;
121 }
122
123 public static class HeaderElement {
124
125 private String path;
126 private Map<String, String> attributes;
127 private Map<String, String> directives;
128
129 public HeaderElement(String path) {
130 this.path = path;
131 this.attributes = new HashMap<String, String>();
132 this.directives = new HashMap<String, String>();
133 }
134
135 public String getName() {
136 return this.path;
137 }
138
139 public Map<String, String> getAttributes() {
140 return attributes;
141 }
142
143 public String getAttribute(String name) {
144 return attributes.get(name);
145 }
146
147 public void addAttribute(String name, String value) {
148 attributes.put(name, value);
149 }
150
151 public Map<String, String> getDirectives() {
152 return directives;
153 }
154
155 public String getDirective(String name) {
156 return directives.get(name);
157 }
158
159 public void addDirective(String name, String value) {
160 directives.put(name, value);
161 }
162
163 @Override
164 public String toString() {
165 return "HeaderElement [path=" + path + ", attributes=" + attributes + ", directives=" + directives + "]";
166 }
167
168 @Override
169 public int hashCode() {
170 final int prime = 31;
171 int result = 1;
172 result = prime * result + ((attributes == null) ? 0 : attributes.hashCode());
173 result = prime * result + ((directives == null) ? 0 : directives.hashCode());
174 result = prime * result + ((path == null) ? 0 : path.hashCode());
175 return result;
176 }
177
178 @Override
179 public boolean equals(Object obj) {
180 if (this == obj)
181 return true;
182 if (obj == null)
183 return false;
184 if (getClass() != obj.getClass())
185 return false;
186 HeaderElement other = (HeaderElement) obj;
187 if (attributes == null) {
188 if (other.attributes != null)
189 return false;
190 } else if (!attributes.equals(other.attributes))
191 return false;
192 if (directives == null) {
193 if (other.directives != null)
194 return false;
195 } else if (!directives.equals(other.directives))
196 return false;
197 if (path == null) {
198 if (other.path != null)
199 return false;
200 } else if (!path.equals(other.path))
201 return false;
202 return true;
203 }
204 }
205 }