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 }