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 }