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.geronimo.deployment.xmlbeans;
018    
019    import java.io.File;
020    import java.io.IOException;
021    import java.io.InputStream;
022    import java.net.URL;
023    import java.util.ArrayList;
024    import java.util.Collection;
025    import java.util.HashMap;
026    import java.util.Iterator;
027    import java.util.List;
028    import java.util.Map;
029    
030    import javax.xml.namespace.QName;
031    
032    import org.apache.xmlbeans.QNameSet;
033    import org.apache.xmlbeans.SchemaType;
034    import org.apache.xmlbeans.XmlException;
035    import org.apache.xmlbeans.XmlObject;
036    import org.apache.xmlbeans.XmlOptions;
037    import org.apache.xmlbeans.XmlValidationError;
038    import org.w3c.dom.Element;
039    
040    /**
041     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
042     */
043    public class XmlBeansUtil {
044        private static final Map<String, String> NAMESPACE_UPDATES = new HashMap<String, String>();
045        //TODO thread safe? conncurrentReaderMap?
046        private static final Map<QName, QNameSet> substitutionGroups = new HashMap<QName, QNameSet>();
047        private static final XmlObject[] NO_ELEMENTS = new XmlObject[]{};
048    
049        private XmlBeansUtil() {
050        }
051    
052        public static void registerNamespaceUpdates(Map<String, String> updates) {
053            NAMESPACE_UPDATES.putAll(updates);
054        }
055    
056        public static void unregisterNamespaceUpdates(Map<String, String> updates) {
057            NAMESPACE_UPDATES.entrySet().removeAll(updates.entrySet());
058        }
059    
060        public static XmlObject parse(File file) throws IOException, XmlException {
061            ArrayList errors = new ArrayList();
062            XmlObject parsed = XmlObject.Factory.parse(file, createXmlOptions(errors));
063            if (errors.size() != 0) {
064                throw new XmlException(errors.toArray().toString());
065            }
066            return parsed;
067        }
068    
069        public static XmlObject parse(URL url, ClassLoader cl) throws IOException, XmlException {
070            ArrayList errors = new ArrayList();
071            Thread currentThread = Thread.currentThread();
072            ClassLoader oldcl = currentThread.getContextClassLoader();
073            currentThread.setContextClassLoader(cl);
074            XmlObject parsed;
075            try {
076                parsed = XmlObject.Factory.parse(url, createXmlOptions(errors));
077            } finally {
078                currentThread.setContextClassLoader(oldcl);
079            }
080            if (errors.size() != 0) {
081                throw new XmlException(errors.toArray().toString());
082            }
083            return parsed;
084        }
085    
086        public static XmlObject parse(InputStream is) throws IOException, XmlException {
087            ArrayList errors = new ArrayList();
088            XmlObject parsed = XmlObject.Factory.parse(is, createXmlOptions(errors));
089            if (errors.size() != 0) {
090                throw new XmlException(errors.toArray().toString());
091            }
092            return parsed;
093        }
094    
095        public static XmlObject parse(String xml) throws XmlException {
096            ArrayList errors = new ArrayList();
097            XmlObject parsed = XmlObject.Factory.parse(xml, createXmlOptions(errors));
098            if (errors.size() != 0) {
099                throw new XmlException(errors.toArray().toString());
100            }
101            return parsed;
102        }
103    
104        public static XmlObject parse(Element element) throws XmlException {
105            ArrayList errors = new ArrayList();
106            XmlObject parsed = XmlObject.Factory.parse(element, createXmlOptions(errors));
107            if (errors.size() != 0) {
108                throw new XmlException(errors.toArray().toString());
109            }
110            return parsed;
111        }
112    
113        public static XmlOptions createXmlOptions(Collection errors) {
114            XmlOptions options = new XmlOptions();
115            options.setLoadLineNumbers();
116            options.setErrorListener(errors);
117            options.setLoadSubstituteNamespaces(NAMESPACE_UPDATES);
118            return options;
119        }
120    
121        public static void registerSubstitutionGroupElements(QName substitutionGroup, QNameSet substitutions) {
122            QNameSet oldSubstitutions = substitutionGroups.get(substitutionGroup);
123            if (oldSubstitutions != null) {
124                substitutions = oldSubstitutions.union(substitutions);
125            }
126            substitutionGroups.put(substitutionGroup, substitutions);
127        }
128    
129        public static void unregisterSubstitutionGroupElements(QName substitutionGroup, QNameSet substitutions) {
130            QNameSet oldSubstitutions = substitutionGroups.get(substitutionGroup);
131            if (oldSubstitutions != null && substitutions != null) {
132                QNameSet difference = oldSubstitutions.intersect(substitutions.inverse());
133                substitutionGroups.put(substitutionGroup, difference);
134            }
135        }
136    
137        public static QNameSet getQNameSetForSubstitutionGroup(QName substitutionGroup) {
138            return substitutionGroups.get(substitutionGroup);
139        }
140    
141        public static XmlObject[] selectSubstitutionGroupElements(QName substitutionGroup, XmlObject container) {
142            QNameSet substitutionGroupMembers = getQNameSetForSubstitutionGroup(substitutionGroup);
143            if (substitutionGroupMembers == null) {
144                return NO_ELEMENTS;
145            }
146            return container.selectChildren(substitutionGroupMembers);
147        }
148    
149        public static XmlObject typedCopy(XmlObject in, SchemaType type) throws XmlException {
150            XmlObject out = in.copy().changeType(type);
151            validateDD(out);
152            return out;
153        }
154    
155        public static void validateDD(XmlObject dd) throws XmlException {
156            XmlOptions xmlOptions = new XmlOptions();
157            xmlOptions.setLoadLineNumbers();
158            Collection errors = new ArrayList();
159            xmlOptions.setErrorListener(errors);
160            try {
161                if (!dd.validate(xmlOptions)) {
162    
163                    for (Iterator iterator = errors.iterator(); iterator.hasNext();) {
164                        Object o = iterator.next();
165                        if (o instanceof XmlValidationError) {
166                            XmlValidationError validationError = (XmlValidationError) o;
167                            List<QName> expected = validationError.getExpectedQNames();
168                            QName actual = validationError.getOffendingQName();
169                            if (expected != null) {
170                                for (QName expectedQName : expected) {
171                                    QNameSet substitutions = getQNameSetForSubstitutionGroup(expectedQName);
172                                    if (substitutions != null && substitutions.contains(actual)) {
173                                        iterator.remove();
174                                        break;
175                                    }
176                                }
177                            }
178                        }
179                    }
180    
181                    if (!errors.isEmpty()) {
182                        StringBuffer buf = new StringBuffer("Invalid deployment descriptor: errors:\n\n");
183                        for (Object o: errors) {
184                            buf.append(o).append("\n\n");
185                        }
186                        buf.append("Descriptor:\n").append(dd.toString()).append("\n");
187                        throw new XmlException(buf.toString(), null, errors);
188                    }
189                }
190            } catch (NullPointerException e) {
191                //ignore
192            } catch (AssertionError e) {
193                //ignore.  Would be the NPE above if assertions were turned off
194            }
195    //        System.out.println("descriptor: " + dd.toString());
196        }
197    }