All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.sling.commons.osgi.ManifestHeader Maven / Gradle / Ivy

/*
 * 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.sling.commons.osgi;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * This is a helper class to parse manifest header entries.
 */
public class ManifestHeader {

    /**
     * A header can have several entries separated by comma.
     */
    public interface Entry {

        /**
         * @return The value of the entry.
         */
        String getValue();

        /**
         * @return The attributes specified for this entry.
         */
        NameValuePair[] getAttributes();

        /**
         * @return The directives for this entry.
         */
        NameValuePair[] getDirectives();

        String getAttributeValue(String name);

        String getDirectiveValue(String name);
    }

    /** The entries for this header. */
    private Entry[] entries = new Entry[0];

    /**
     * Add new entries from parsing.
     */
    private void add(Entry[] paths) {
        if ( paths != null && paths.length > 0 ) {
            final Entry[] copy = new Entry[this.entries.length + paths.length];
            System.arraycopy(this.entries, 0, copy, 0, this.entries.length);
            System.arraycopy(paths, 0, copy, this.entries.length, paths.length);
            this.entries = copy;
        }
    }

    /**
     * @return Return the entries for this header.
     */
    public Entry[] getEntries() {
        return this.entries;
    }

    /**
     * Directives and attributes are simple name/value pairs.
     */
    public final static class NameValuePair {

        private final String name;
        private final String value;

        public NameValuePair(String name, String value) {
            this.name = name;
            this.value = value;
        }

        public String getName() {
            return name;
        }

        public String getValue() {
            return value;
        }
    }

    private static final String CLASS_PATH_SEPARATOR = ",";
    private static final String PACKAGE_SEPARATOR = ";";
    private static final String DIRECTIVE_SEPARATOR = ":=";
    private static final String ATTRIBUTE_SEPARATOR = "=";

    /**
     * Parse headers
     * Like this: path; path; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2,
     *            path; path; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2
     * The returned object maintains the order of entries (paths), directives and attributes.
     * @param header Header name
     * @return Parsed header or null if not found
     */
    public static ManifestHeader parse(String header) {
        final ManifestHeader entry = new ManifestHeader();

        if (header != null) {
            if (header.length() == 0) {
                throw new IllegalArgumentException("A header cannot be an empty string.");
            }

            final String[] clauseStrings = parseDelimitedString(header, CLASS_PATH_SEPARATOR);
            if ( clauseStrings != null ) {
                for(final String clause : clauseStrings) {
                    entry.add(parseStandardHeaderClause(clause));
                }
            }
        }

        return (entry.getEntries().length == 0) ? null : entry;
    }

    /**
     * Parse a clause
     * Like this: path; path; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2
     */
    private static ManifestHeader.Entry[] parseStandardHeaderClause(String clauseString)
    throws IllegalArgumentException {
        // Break string into semi-colon delimited pieces.
        String[] pieces = parseDelimitedString(clauseString, PACKAGE_SEPARATOR);

        // Count the number of different paths; paths
        // will not have an '=' in their string. This assumes
        // that paths come first, before directives and
        // attributes.
        int pathCount = 0;
        for (int pieceIdx = 0; pieceIdx < pieces.length; pieceIdx++) {
            if (pieces[pieceIdx].indexOf('=') >= 0) {
                break;
            }
            pathCount++;
        }

        // Error if no paths were specified.
        if (pathCount == 0) {
            throw new IllegalArgumentException(
                "No paths specified in header: " + clauseString);
        }

        // Create an array of paths.
        PathImpl[] paths = new PathImpl[pathCount];
        for(int i=0;i dirsList = new ArrayList();
        final Set dirsNames = new HashSet();
        final List attrsList = new ArrayList();
        final Set attrsNames = new HashSet();

        int idx = -1;
        String sep = null;
        for (int pieceIdx = pathCount; pieceIdx < pieces.length; pieceIdx++) {

            if ((idx = pieces[pieceIdx].indexOf(DIRECTIVE_SEPARATOR)) >= 0) {
                sep = DIRECTIVE_SEPARATOR;
            } else if ((idx = pieces[pieceIdx].indexOf(ATTRIBUTE_SEPARATOR)) >= 0) {
                sep = ATTRIBUTE_SEPARATOR;
            } else {
                throw new IllegalArgumentException("Not a directive/attribute: " + clauseString);
            }

            final String key = pieces[pieceIdx].substring(0, idx).trim();
            String value = pieces[pieceIdx].substring(idx + sep.length()).trim();

            // Remove quotes, if value is quoted.
            if (value.startsWith("\"") && value.endsWith("\"")) {
                value = value.substring(1, value.length() - 1);
            }

            // Save the directive/attribute in the appropriate array.
            if (sep.equals(DIRECTIVE_SEPARATOR)) {
                // Check for duplicates.
                if (dirsNames.contains(key)) {
                    throw new IllegalArgumentException("Duplicate directive: " + key);
                }
                dirsList.add(new ManifestHeader.NameValuePair(key, value));
                dirsNames.add(key);
            } else {
                // Check for duplicates.
                if (attrsNames.contains(key)) {
                    throw new IllegalArgumentException("Duplicate attribute: " + key);
                }
                attrsList.add(new ManifestHeader.NameValuePair(key, value));
                attrsNames.add(key);
            }
        }
        // Create directive array.
        ManifestHeader.NameValuePair[] dirs =
            dirsList.toArray(new ManifestHeader.NameValuePair[dirsList.size()]);

        // Create attribute array.
        ManifestHeader.NameValuePair[] attrs =
            attrsList.toArray(new ManifestHeader.NameValuePair[attrsList.size()]);

        // now set attributes and directives for each path
        for(int i=0;i list = new ArrayList();

        final StringBuilder sb = new StringBuilder();

        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());
        }

        if ( list.size() == 0 ) {
            return null;
        }
        return list.toArray(new String[list.size()]);
    }

    protected static final class PathImpl implements ManifestHeader.Entry {

        private final String value;

        private NameValuePair[] attributes;
        private NameValuePair[] directives;

        public PathImpl(final String path) {
            this.value = path;
        }

        public void init(NameValuePair[] dirs, NameValuePair[] attrs) {
            this.directives = dirs;
            this.attributes = attrs;
        }

        /**
         * @see org.apache.sling.commons.osgi.ManifestHeader.Entry#getAttributes()
         */
        public NameValuePair[] getAttributes() {
            return this.attributes;
        }

        /**
         * @see org.apache.sling.commons.osgi.ManifestHeader.Entry#getDirectives()
         */
        public NameValuePair[] getDirectives() {
            return this.directives;
        }

        /**
         * @see org.apache.sling.commons.osgi.ManifestHeader.Entry#getValue()
         */
        public String getValue() {
            return this.value;
        }

        public String getAttributeValue(String name) {
            String v = null;
            int index = 0;
            while ( v == null && index < attributes.length ) {
                if ( attributes[index].getName().equals(name) ) {
                    v = attributes[index].getValue();
                }
                index++;
            }
            return v;
        }

        public String getDirectiveValue(String name) {
            String v = null;
            int index = 0;
            while ( v == null && index < directives.length ) {
                if ( directives[index].getName().equals(name) ) {
                    v = directives[index].getValue();
                }
                index++;
            }
            return v;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy