001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.builder.xml;
018    
019    import java.util.HashMap;
020    import java.util.HashSet;
021    import java.util.Iterator;
022    import java.util.Map;
023    import java.util.Map.Entry;
024    import java.util.Set;
025    import javax.xml.namespace.NamespaceContext;
026    import javax.xml.xpath.XPathFactory;
027    
028    import org.apache.camel.spi.NamespaceAware;
029    import org.apache.camel.util.CastUtils;
030    
031    /**
032     * An implementation of {@link NamespaceContext} which uses a simple Map where
033     * the keys are the prefixes and the values are the URIs
034     */
035    public class DefaultNamespaceContext implements NamespaceContext, NamespaceAware {
036    
037        private final Map<String, String> map;
038        private final NamespaceContext parent;
039    
040        public DefaultNamespaceContext() {
041            this(XPathFactory.newInstance());
042        }
043    
044        public DefaultNamespaceContext(XPathFactory factory) {
045            this.parent = factory.newXPath().getNamespaceContext();
046            this.map = new HashMap<String, String>();
047        }
048    
049        public DefaultNamespaceContext(NamespaceContext parent, Map<String, String> map) {
050            this.parent = parent;
051            this.map = map;
052        }
053    
054        /**
055         * A helper method to make it easy to create newly populated instances
056         */
057        public DefaultNamespaceContext add(String prefix, String uri) {
058            map.put(prefix, uri);
059            return this;
060        }
061    
062        public String getNamespaceURI(String prefix) {
063            String answer = map.get(prefix);
064            if (answer == null && parent != null) {
065                return parent.getNamespaceURI(prefix);
066            }
067            return answer;
068        }
069    
070        public String getPrefix(String namespaceURI) {
071            for (Entry<String, String> entry : map.entrySet()) {
072                if (namespaceURI.equals(entry.getValue())) {
073                    return entry.getKey();
074                }
075            }
076            if (parent != null) {
077                return parent.getPrefix(namespaceURI);
078            }
079            return null;
080        }
081    
082        public Iterator<String> getPrefixes(String namespaceURI) {
083            Set<String> set = new HashSet<String>();
084            for (Entry<String, String> entry : map.entrySet()) {
085                if (namespaceURI.equals(entry.getValue())) {
086                    set.add(entry.getKey());
087                }
088            }
089            if (parent != null) {
090                Iterator<String> iter = CastUtils.cast(parent.getPrefixes(namespaceURI));
091                while (iter.hasNext()) {
092                    set.add(iter.next());
093                }
094            }
095            return set.iterator();
096        }
097    
098        public void setNamespaces(Map<String, String> namespaces) {
099            map.putAll(namespaces);
100        }
101    
102        /**
103         * toString() implementation that outputs the namespace mappings with the following format: "[me: {prefix -> value}, {prefix -> value}], [parent: {prefix -> value}, {prefix -> value}].
104         * Recurses up the parent's chain.
105         */
106        @Override
107        public String toString() {
108            StringBuilder sb = new StringBuilder("[me: ");
109            for (Entry<String, String> nsEntry : map.entrySet()) {
110                sb.append("{" + nsEntry.getKey() + " -> " + nsEntry.getValue() + "},");
111            }
112            if (!map.isEmpty()) {
113                // remove the last comma
114                sb.deleteCharAt(sb.length() - 1);
115            }
116            sb.append("]");
117    
118            // Get the parent's namespace mappings
119            if (parent != null) {
120                sb.append(", [parent: ");
121                sb.append(parent.toString());
122                sb.append("]");
123            }
124            return sb.toString();
125        }
126    
127    }