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
018 package org.apache.geronimo.schema;
019
020 import java.util.HashMap;
021 import java.util.Map;
022
023 import javax.xml.namespace.QName;
024
025 import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
026 import org.apache.xmlbeans.SchemaType;
027 import org.apache.xmlbeans.XmlCursor;
028 import org.apache.xmlbeans.XmlDocumentProperties;
029 import org.apache.xmlbeans.XmlException;
030 import org.apache.xmlbeans.XmlObject;
031
032 /**
033 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
034 */
035 public class SchemaConversionUtils {
036 public static final String J2EE_NAMESPACE = "http://java.sun.com/xml/ns/j2ee";
037 public static final String JAVAEE_NAMESPACE = "http://java.sun.com/xml/ns/javaee";
038
039 static final String GERONIMO_NAMING_NAMESPACE = "http://geronimo.apache.org/xml/ns/naming-1.2";
040 private static final String GERONIMO_SECURITY_NAMESPACE = "http://geronimo.apache.org/xml/ns/security-2.0";
041 private static final String GERONIMO_SERVICE_NAMESPACE = "http://geronimo.apache.org/xml/ns/deployment-1.2";
042 private static final String JPA_PERSISTENCE_NAMESPACE = "http://java.sun.com/xml/ns/persistence";
043
044 private static final Map<String, ElementConverter> GERONIMO_SCHEMA_CONVERSIONS = new HashMap<String, ElementConverter>();
045
046 static {
047
048 GERONIMO_SCHEMA_CONVERSIONS.put("gbean-ref", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE));
049 GERONIMO_SCHEMA_CONVERSIONS.put("ejb-ref", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE));
050 GERONIMO_SCHEMA_CONVERSIONS.put("ejb-local-ref", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE));
051 GERONIMO_SCHEMA_CONVERSIONS.put("service-ref", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE));
052 GERONIMO_SCHEMA_CONVERSIONS.put("resource-ref", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE));
053 GERONIMO_SCHEMA_CONVERSIONS.put("resource-env-ref", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE));
054 GERONIMO_SCHEMA_CONVERSIONS.put("message-destination", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE));
055 GERONIMO_SCHEMA_CONVERSIONS.put("cmp-connection-factory", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE));
056 GERONIMO_SCHEMA_CONVERSIONS.put("workmanager", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE));
057 GERONIMO_SCHEMA_CONVERSIONS.put("resource-adapter", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE));
058 GERONIMO_SCHEMA_CONVERSIONS.put("web-container", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE));
059
060 GERONIMO_SCHEMA_CONVERSIONS.put("security", new SecurityElementConverter());
061 GERONIMO_SCHEMA_CONVERSIONS.put("default-subject", new NamespaceElementConverter(GERONIMO_SECURITY_NAMESPACE));
062
063 GERONIMO_SCHEMA_CONVERSIONS.put("gbean", new GBeanElementConverter());
064 GERONIMO_SCHEMA_CONVERSIONS.put("environment", new NamespaceElementConverter(GERONIMO_SERVICE_NAMESPACE));
065 GERONIMO_SCHEMA_CONVERSIONS.put("client-environment", new NamespaceElementConverter(GERONIMO_SERVICE_NAMESPACE));
066 GERONIMO_SCHEMA_CONVERSIONS.put("server-environment", new NamespaceElementConverter(GERONIMO_SERVICE_NAMESPACE));
067 GERONIMO_SCHEMA_CONVERSIONS.put("persistence", new NamespaceElementConverter(JPA_PERSISTENCE_NAMESPACE));
068 }
069
070 private SchemaConversionUtils() {
071 }
072
073 public static void registerNamespaceConversions(Map conversions) {
074 GERONIMO_SCHEMA_CONVERSIONS.putAll(conversions);
075 }
076
077 public static void convertToGeronimoSubSchemas(XmlCursor cursor) {
078 cursor.toStartDoc();
079 XmlCursor end = cursor.newCursor();
080 try {
081 while (cursor.hasNextToken()) {
082 convertSingleElementToGeronimoSubSchemas(cursor, end);
083 cursor.toNextToken();
084 }
085 } finally {
086 end.dispose();
087 }
088 }
089
090 public static boolean convertSingleElementToGeronimoSubSchemas(XmlCursor cursor, XmlCursor end) {
091 if (cursor.isStart()) {
092 String localName = cursor.getName().getLocalPart();
093 ElementConverter converter = (ElementConverter) GERONIMO_SCHEMA_CONVERSIONS.get(localName);
094 if (converter != null) {
095 converter.convertElement(cursor, end);
096 return true;
097 }
098 return false;
099 }
100 //you should only call this method at a start token
101 return false;
102 }
103
104 public static XmlObject fixGeronimoSchema(XmlObject rawPlan, QName desiredElement, SchemaType desiredType) throws XmlException {
105 XmlCursor cursor = rawPlan.newCursor();
106 try {
107 if (findNestedElement(cursor, desiredElement)) {
108 cursor.push();
109 convertToGeronimoSubSchemas(cursor);
110 cursor.pop();
111 XmlObject temp = cursor.getObject();
112
113 XmlObject result = temp.changeType(desiredType);
114 if (result == null || result.schemaType() != desiredType) {
115 result = temp.copy().changeType(desiredType);
116 }
117 XmlBeansUtil.validateDD(result);
118 return result;
119 } else {
120 return null;
121 }
122 } finally {
123 cursor.dispose();
124 }
125 }
126
127 public static XmlObject getNestedObject(XmlObject xmlObject, QName desiredElement) {
128 XmlCursor cursor = xmlObject.newCursor();
129 try {
130 if (findNestedElement(cursor, desiredElement)) {
131 XmlObject child = cursor.getObject();
132 //The copy seems to be needed to make the type change work for some documents!
133 return child.copy();
134 }
135 } finally {
136 cursor.dispose();
137 }
138 throw new IllegalArgumentException("xmlobject did not have desired element: " + desiredElement + "/n" + xmlObject);
139 }
140
141 public static boolean findNestedElement(XmlCursor cursor, QName desiredElement) {
142 while (cursor.hasNextToken()) {
143 if (cursor.isStart()) {
144 QName element = cursor.getName();
145 if (element.equals(desiredElement)) {
146 return true;
147 }
148 }
149 cursor.toNextToken();
150 }
151 return false;
152 }
153
154 public static boolean findNestedElement(XmlCursor cursor, String desiredElement) {
155 while (cursor.hasNextToken()) {
156 if (cursor.isStart()) {
157 String element = cursor.getName().getLocalPart();
158 if (element.equals(desiredElement)) {
159 return true;
160 }
161 }
162 cursor.toNextToken();
163 }
164 return false;
165 }
166
167 public static XmlObject getNestedObjectAsType(XmlObject xmlObject, QName desiredElement, SchemaType type) {
168 XmlCursor cursor = xmlObject.newCursor();
169 try {
170 if (findNestedElement(cursor, desiredElement)) {
171 XmlObject child = cursor.getObject();
172 //The copy seems to be needed to make the type change work for some documents!
173 XmlObject result = child.copy().changeType(type);
174 assert result.schemaType() == type;
175 return result;
176 }
177 } finally {
178 cursor.dispose();
179 }
180 throw new IllegalArgumentException("xmlobject did not have desired element: " + desiredElement + "\n" + xmlObject);
181 }
182
183
184 public static boolean convertToSchema(XmlCursor cursor, String namespace, String schemaLocationURL, String version) {
185 //remove dtd
186 XmlDocumentProperties xmlDocumentProperties = cursor.documentProperties();
187 xmlDocumentProperties.remove(XmlDocumentProperties.DOCTYPE_NAME);
188 xmlDocumentProperties.remove(XmlDocumentProperties.DOCTYPE_PUBLIC_ID);
189 xmlDocumentProperties.remove(XmlDocumentProperties.DOCTYPE_SYSTEM_ID);
190 //convert namespace
191 boolean isFirstStart = true;
192 while (cursor.hasNextToken()) {
193 if (cursor.isStart()) {
194 if (namespace.equals(cursor.getName().getNamespaceURI())) {
195 //already has correct schema, exit
196 return false;
197 }
198 cursor.setName(new QName(namespace, cursor.getName().getLocalPart()));
199 cursor.toNextToken();
200 if (isFirstStart) {
201 cursor.insertNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
202 cursor.insertAttributeWithValue(new QName("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation", "xsi"), namespace + " " + schemaLocationURL);
203 cursor.insertAttributeWithValue(new QName("version"), version);
204 isFirstStart = false;
205 }
206 } else {
207 cursor.toNextToken();
208 }
209 }
210 return true;
211 }
212
213 public static boolean convertSchemaVersion (XmlCursor cursor, String namespace, String schemaLocationURL, String version) {
214 boolean isFirstStart = true;
215
216
217 while (cursor.hasNextToken()) {
218 if (cursor.isStart()) {
219 if (isFirstStart) {
220 //HACK to work around digester's difficulty with namespaces
221 if (cursor.getAttributeText(new QName("xmlns")) != null) {
222 cursor.removeAttribute(new QName("xmlns"));
223 }
224 //if we are at the first element in the document, reset the version number ...
225 cursor.setAttributeText(new QName("version"), version);
226 //... and also set the xsi:schemaLocation
227 cursor.setAttributeText(new QName("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation", "xsi"), namespace + " "+schemaLocationURL);
228 isFirstStart = false;
229 }
230 //convert namespace of each starting element
231 cursor.setName(new QName(namespace, cursor.getName().getLocalPart()));
232 cursor.toNextToken();
233
234 } else {
235 cursor.toNextToken();
236 }
237 }
238
239
240 return true;
241 }
242
243 /**
244 * Reorders elements to match descriptionGroup
245 *
246 * @param namespace
247 * @param cursor XmlCursor positioned at first element of "group" to be reordered
248 */
249 public static void convertToDescriptionGroup(String namespace, XmlCursor cursor, XmlCursor moveable) {
250 moveable.toCursor(cursor);
251 moveElements("description", namespace, moveable, cursor);
252 moveElements("display-name", namespace, moveable, cursor);
253 moveElements("icon", namespace, moveable, cursor);
254 }
255
256 public static void convertToTldTag(String namespace, XmlCursor cursor, XmlCursor moveable) {
257 moveable.toCursor(cursor);
258 moveElements("description", namespace, moveable, cursor);
259 moveElements("display-name", namespace, moveable, cursor);
260 moveElements("icon", namespace, moveable, cursor);
261 moveElements("name", namespace, moveable, cursor);
262 moveElements("tag-class", namespace, moveable, cursor);
263 moveElements("tei-class", namespace, moveable, cursor);
264 moveElements("body-content", namespace, moveable, cursor);
265 moveElements("variable", namespace, moveable, cursor);
266 moveElements("attribute", namespace, moveable, cursor);
267 moveElements("dynamic-attributes", namespace, moveable, cursor);
268 moveElements("example", namespace, moveable, cursor);
269 moveElements("tag-extension", namespace, moveable, cursor);
270 }
271
272 public static void convertToTldAttribute(String namespace, XmlCursor cursor, XmlCursor moveable) {
273 moveable.toCursor(cursor);
274 moveElements("description", namespace, moveable, cursor);
275 moveElements("name", namespace, moveable, cursor);
276 moveElements("required", namespace, moveable, cursor);
277 moveElements("rtexprvalue", namespace, moveable, cursor);
278 moveElements("type", namespace, moveable, cursor);
279 moveElements("fragment", namespace, moveable, cursor);
280 }
281
282 public static void convertToTldInitParam(String namespace, XmlCursor cursor, XmlCursor moveable) {
283 moveable.toCursor(cursor);
284 moveElements("description", namespace, moveable, cursor);
285 moveElements("param-name", namespace, moveable, cursor);
286 moveElements("param-value", namespace, moveable, cursor);
287 }
288
289 public static void convertToTldValidator(String namespace, XmlCursor cursor, XmlCursor moveable) {
290 moveable.toCursor(cursor);
291 moveElements("description", namespace, moveable, cursor);
292 moveElements("validator-class", namespace, moveable, cursor);
293 moveElements("init-param", namespace, moveable, cursor);
294
295 do {
296 String name = cursor.getName().getLocalPart();
297 if ("init-param".equals(name)) {
298 cursor.push();
299 cursor.toFirstChild();
300 convertToTldInitParam(namespace, cursor, moveable);
301 cursor.pop();
302 }
303 } while (cursor.toPrevSibling());
304 }
305
306 public static void convertToTldVariable(String namespace, XmlCursor cursor, XmlCursor moveable) {
307 moveable.toCursor(cursor);
308 moveElements("description", namespace, moveable, cursor);
309 moveElements("name-given", namespace, moveable, cursor);
310 moveElements("name-from-attribute", namespace, moveable, cursor);
311 moveElements("variable-class", namespace, moveable, cursor);
312 moveElements("declare", namespace, moveable, cursor);
313 moveElements("scope", namespace, moveable, cursor);
314 }
315
316 public static void convertToJNDIEnvironmentRefsGroup(String namespace, XmlCursor cursor, XmlCursor moveable) {
317 moveElements("env-entry", namespace, moveable, cursor);
318 moveElements("ejb-ref", namespace, moveable, cursor);
319 moveElements("ejb-local-ref", namespace, moveable, cursor);
320 moveElements("resource-ref", namespace, moveable, cursor);
321 moveElements("resource-env-ref", namespace, moveable, cursor);
322 moveElements("message-destination-ref", namespace, moveable, cursor);
323
324 do {
325 String name = cursor.getName().getLocalPart();
326 if ("env-entry".equals(name)) {
327 cursor.push();
328 cursor.toFirstChild();
329 convertToDescriptionGroup(namespace, cursor, moveable);
330 convertToEnvEntryGroup(namespace, cursor, moveable);
331 cursor.pop();
332 }
333 } while (cursor.toPrevSibling());
334 }
335
336 public static void convertToEnvEntryGroup(String namespace, XmlCursor cursor, XmlCursor moveable) {
337 moveElements("env-entry-name", namespace, moveable, cursor);
338 moveElements("env-entry-type", namespace, moveable, cursor);
339 moveElements("env-entry-value", namespace, moveable, cursor);
340 }
341
342 private static void moveElements(String localName, String namespace, XmlCursor moveable, XmlCursor toHere) {
343 QName name = new QName(namespace, localName);
344 //skip elements already in the correct order.
345 while (name.equals(toHere.getName()) && toHere.toNextSibling()) {
346 }
347 moveable.toCursor(toHere);
348 while (moveable.toNextSibling(name)) {
349 moveable.moveXml(toHere);
350 }
351 }
352
353 }