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