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: 937957 $, $Date: 2010-04-26 10:00:08 +0200 (Mon, 26 Apr 2010) $
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        }
164    }