sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cziege...@apache.org
Subject svn commit: r656526 - in /incubator/sling/trunk/commons/osgi/src: main/java/org/apache/sling/commons/osgi/ test/ test/java/ test/java/org/ test/java/org/apache/ test/java/org/apache/sling/ test/java/org/apache/sling/commons/ test/java/org/apache/sling/...
Date Thu, 15 May 2008 07:10:04 GMT
Author: cziegeler
Date: Thu May 15 00:10:03 2008
New Revision: 656526

URL: http://svn.apache.org/viewvc?rev=656526&view=rev
Log:
SLING-456: Add manifest header parser and junit test.

Added:
    incubator/sling/trunk/commons/osgi/src/main/java/org/apache/sling/commons/osgi/ManifestHeader.java
  (with props)
    incubator/sling/trunk/commons/osgi/src/test/
    incubator/sling/trunk/commons/osgi/src/test/java/
    incubator/sling/trunk/commons/osgi/src/test/java/org/
    incubator/sling/trunk/commons/osgi/src/test/java/org/apache/
    incubator/sling/trunk/commons/osgi/src/test/java/org/apache/sling/
    incubator/sling/trunk/commons/osgi/src/test/java/org/apache/sling/commons/
    incubator/sling/trunk/commons/osgi/src/test/java/org/apache/sling/commons/osgi/
    incubator/sling/trunk/commons/osgi/src/test/java/org/apache/sling/commons/osgi/ManifestHeaderTest.java
  (with props)

Added: incubator/sling/trunk/commons/osgi/src/main/java/org/apache/sling/commons/osgi/ManifestHeader.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/commons/osgi/src/main/java/org/apache/sling/commons/osgi/ManifestHeader.java?rev=656526&view=auto
==============================================================================
--- incubator/sling/trunk/commons/osgi/src/main/java/org/apache/sling/commons/osgi/ManifestHeader.java
(added)
+++ incubator/sling/trunk/commons/osgi/src/main/java/org/apache/sling/commons/osgi/ManifestHeader.java
Thu May 15 00:10:03 2008
@@ -0,0 +1,309 @@
+/*
+ * 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.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 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 {
+
+        /**
+         * The value of the entry.
+         */
+        String getValue();
+
+        /**
+         * The attributes specified for this entry.
+         */
+        NameValuePair[] getAttributes();
+
+        /**
+         * The directives for this entry.
+         */
+        NameValuePair[] getDirectives();
+    }
+
+    /** 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 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
+     */
+    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<pathCount;i++) {
+            paths[i] = new PathImpl(pieces[i]);
+        }
+
+        // Parse the directives/attributes.
+        final Map<String, ManifestHeader.NameValuePair> dirsMap = new HashMap<String,
ManifestHeader.NameValuePair>();
+        final Map<String, ManifestHeader.NameValuePair> attrsMap = new HashMap<String,
ManifestHeader.NameValuePair>();
+
+        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 (dirsMap.get(key) != null) {
+                    throw new IllegalArgumentException("Duplicate directive: " + key);
+                }
+                dirsMap.put(key, new ManifestHeader.NameValuePair(key, value));
+            } else {
+                // Check for duplicates.
+                if (attrsMap.get(key) != null) {
+                    throw new IllegalArgumentException("Duplicate attribute: " + key);
+                }
+                attrsMap.put(key, new ManifestHeader.NameValuePair(key, value));
+            }
+        }
+        // Create directive array.
+        ManifestHeader.NameValuePair[] dirs =
+            dirsMap.values().toArray(new ManifestHeader.NameValuePair[dirsMap.size()]);
+
+        // Create attribute array.
+        ManifestHeader.NameValuePair[] attrs =
+            attrsMap.values().toArray(new ManifestHeader.NameValuePair[attrsMap.size()]);
+
+        // now set attributes and directives for each path
+        for(int i=0;i<pathCount;i++) {
+            paths[i].init(dirs, attrs);
+        }
+
+        return paths;
+    }
+
+    private static final int CHAR = 1;
+    private static final int DELIMITER = 2;
+    private static final int STARTQUOTE = 4;
+    private static final int ENDQUOTE = 8;
+
+    /**
+     * Parses delimited string and returns an array containing the tokens. This
+     * parser obeys quotes, so the delimiter character will be ignored if it is
+     * inside of a quote. This method assumes that the quote character is not
+     * included in the set of delimiter characters.
+     * @param value the delimited string to parse.
+     * @param delim the characters delimiting the tokens.
+     * @return an array of string tokens or null if there were no tokens.
+     **/
+    private static String[] parseDelimitedString(String value, String delim) {
+        if (value == null) {
+           value = "";
+        }
+
+        final List<String> list = new ArrayList<String>();
+
+        final StringBuffer sb = new StringBuffer();
+
+        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;
+        }
+
+    }
+}

Propchange: incubator/sling/trunk/commons/osgi/src/main/java/org/apache/sling/commons/osgi/ManifestHeader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/sling/trunk/commons/osgi/src/main/java/org/apache/sling/commons/osgi/ManifestHeader.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: incubator/sling/trunk/commons/osgi/src/test/java/org/apache/sling/commons/osgi/ManifestHeaderTest.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/commons/osgi/src/test/java/org/apache/sling/commons/osgi/ManifestHeaderTest.java?rev=656526&view=auto
==============================================================================
--- incubator/sling/trunk/commons/osgi/src/test/java/org/apache/sling/commons/osgi/ManifestHeaderTest.java
(added)
+++ incubator/sling/trunk/commons/osgi/src/test/java/org/apache/sling/commons/osgi/ManifestHeaderTest.java
Thu May 15 00:10:03 2008
@@ -0,0 +1,89 @@
+/*
+ * 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 junit.framework.TestCase;
+
+/**
+ * Tests for the manifest header parsing.
+ */
+public class ManifestHeaderTest extends TestCase {
+
+    public void testNonExisting() {
+        String header = null;
+        final ManifestHeader entry = ManifestHeader.parse(header);
+        assertNull(entry);
+    }
+
+    public void testSinglePath() {
+        String header = "something";
+        final ManifestHeader entry = ManifestHeader.parse(header);
+        assertEquals(1, entry.getEntries().length);
+        assertEquals(header, entry.getEntries()[0].getValue());
+        assertEquals(0, entry.getEntries()[0].getAttributes().length);
+        assertEquals(0, entry.getEntries()[0].getDirectives().length);
+    }
+
+    public void testSeveralPaths() {
+        String header = "one,two,   three    ,\n   four, \n   five";
+        final ManifestHeader entry = ManifestHeader.parse(header);
+        assertEquals(5, entry.getEntries().length);
+        assertEquals("one", entry.getEntries()[0].getValue());
+        assertEquals(0, entry.getEntries()[0].getAttributes().length);
+        assertEquals(0, entry.getEntries()[0].getDirectives().length);
+        assertEquals("two", entry.getEntries()[1].getValue());
+        assertEquals(0, entry.getEntries()[1].getAttributes().length);
+        assertEquals(0, entry.getEntries()[1].getDirectives().length);
+        assertEquals("three", entry.getEntries()[2].getValue());
+        assertEquals(0, entry.getEntries()[2].getAttributes().length);
+        assertEquals(0, entry.getEntries()[2].getDirectives().length);
+        assertEquals("four", entry.getEntries()[3].getValue());
+        assertEquals(0, entry.getEntries()[3].getAttributes().length);
+        assertEquals(0, entry.getEntries()[3].getDirectives().length);
+        assertEquals("five", entry.getEntries()[4].getValue());
+        assertEquals(0, entry.getEntries()[4].getAttributes().length);
+        assertEquals(0, entry.getEntries()[4].getDirectives().length);
+    }
+
+    public void testAttributes() {
+        String header = "one;a=1;b=2";
+        final ManifestHeader entry = ManifestHeader.parse(header);
+        assertEquals(1, entry.getEntries().length);
+        assertEquals("one", entry.getEntries()[0].getValue());
+        assertEquals(2, entry.getEntries()[0].getAttributes().length);
+        assertEquals(0, entry.getEntries()[0].getDirectives().length);
+        assertEquals("a", entry.getEntries()[0].getAttributes()[0].getName());
+        assertEquals("b", entry.getEntries()[0].getAttributes()[1].getName());
+        assertEquals("1", entry.getEntries()[0].getAttributes()[0].getValue());
+        assertEquals("2", entry.getEntries()[0].getAttributes()[1].getValue());
+    }
+
+    public void testDirectives() {
+        String header = "one;a:=1;b:=2";
+        final ManifestHeader entry = ManifestHeader.parse(header);
+        assertEquals(1, entry.getEntries().length);
+        assertEquals("one", entry.getEntries()[0].getValue());
+        assertEquals(2, entry.getEntries()[0].getDirectives().length);
+        assertEquals(0, entry.getEntries()[0].getAttributes().length);
+        assertEquals("a", entry.getEntries()[0].getDirectives()[0].getName());
+        assertEquals("b", entry.getEntries()[0].getDirectives()[1].getName());
+        assertEquals("1", entry.getEntries()[0].getDirectives()[0].getValue());
+        assertEquals("2", entry.getEntries()[0].getDirectives()[1].getValue());
+    }
+}

Propchange: incubator/sling/trunk/commons/osgi/src/test/java/org/apache/sling/commons/osgi/ManifestHeaderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/sling/trunk/commons/osgi/src/test/java/org/apache/sling/commons/osgi/ManifestHeaderTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url



Mime
View raw message