001 /** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package org.apache.geronimo.schema; 020 021 import java.util.HashMap; 022 import java.util.Map; 023 024 import javax.xml.namespace.QName; 025 026 import org.apache.geronimo.xbeans.j2ee.ApplicationClientDocument; 027 import org.apache.geronimo.xbeans.j2ee.ApplicationDocument; 028 import org.apache.geronimo.xbeans.j2ee.ConnectorDocument; 029 import org.apache.geronimo.xbeans.j2ee.EjbJarDocument; 030 import org.apache.geronimo.xbeans.j2ee.WebAppDocument; 031 import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil; 032 import org.apache.xmlbeans.SchemaType; 033 import org.apache.xmlbeans.XmlCursor; 034 import org.apache.xmlbeans.XmlDocumentProperties; 035 import org.apache.xmlbeans.XmlException; 036 import org.apache.xmlbeans.XmlObject; 037 038 /** 039 * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $ 040 */ 041 public class SchemaConversionUtils { 042 public static final String J2EE_NAMESPACE = "http://java.sun.com/xml/ns/j2ee"; 043 public static final String JAVAEE_NAMESPACE = "http://java.sun.com/xml/ns/javaee"; 044 045 static final String GERONIMO_NAMING_NAMESPACE = "http://geronimo.apache.org/xml/ns/naming-1.2"; 046 private static final String GERONIMO_SECURITY_NAMESPACE = "http://geronimo.apache.org/xml/ns/security-1.2"; 047 private static final String GERONIMO_SERVICE_NAMESPACE = "http://geronimo.apache.org/xml/ns/deployment-1.2"; 048 049 private static final Map GERONIMO_SCHEMA_CONVERSIONS = new HashMap(); 050 051 static { 052 053 GERONIMO_SCHEMA_CONVERSIONS.put("gbean-ref", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE)); 054 GERONIMO_SCHEMA_CONVERSIONS.put("ejb-ref", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE)); 055 GERONIMO_SCHEMA_CONVERSIONS.put("ejb-local-ref", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE)); 056 GERONIMO_SCHEMA_CONVERSIONS.put("service-ref", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE)); 057 GERONIMO_SCHEMA_CONVERSIONS.put("resource-ref", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE)); 058 GERONIMO_SCHEMA_CONVERSIONS.put("resource-env-ref", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE)); 059 GERONIMO_SCHEMA_CONVERSIONS.put("message-destination", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE)); 060 GERONIMO_SCHEMA_CONVERSIONS.put("cmp-connection-factory", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE)); 061 GERONIMO_SCHEMA_CONVERSIONS.put("workmanager", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE)); 062 GERONIMO_SCHEMA_CONVERSIONS.put("resource-adapter", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE)); 063 GERONIMO_SCHEMA_CONVERSIONS.put("web-container", new NamespaceElementConverter(GERONIMO_NAMING_NAMESPACE)); 064 065 GERONIMO_SCHEMA_CONVERSIONS.put("security", new SecurityElementConverter()); 066 GERONIMO_SCHEMA_CONVERSIONS.put("default-principal", new NamespaceElementConverter(GERONIMO_SECURITY_NAMESPACE)); 067 068 GERONIMO_SCHEMA_CONVERSIONS.put("gbean", new GBeanElementConverter()); 069 GERONIMO_SCHEMA_CONVERSIONS.put("environment", new NamespaceElementConverter(GERONIMO_SERVICE_NAMESPACE)); 070 GERONIMO_SCHEMA_CONVERSIONS.put("client-environment", new NamespaceElementConverter(GERONIMO_SERVICE_NAMESPACE)); 071 GERONIMO_SCHEMA_CONVERSIONS.put("server-environment", new NamespaceElementConverter(GERONIMO_SERVICE_NAMESPACE)); 072 } 073 074 private SchemaConversionUtils() { 075 } 076 077 public static void registerNamespaceConversions(Map conversions) { 078 GERONIMO_SCHEMA_CONVERSIONS.putAll(conversions); 079 } 080 081 public static void convertToGeronimoSubSchemas(XmlCursor cursor) { 082 cursor.toStartDoc(); 083 XmlCursor end = cursor.newCursor(); 084 try { 085 while (cursor.hasNextToken()) { 086 convertSingleElementToGeronimoSubSchemas(cursor, end); 087 cursor.toNextToken(); 088 } 089 } finally { 090 end.dispose(); 091 } 092 } 093 094 public static boolean convertSingleElementToGeronimoSubSchemas(XmlCursor cursor, XmlCursor end) { 095 if (cursor.isStart()) { 096 String localName = cursor.getName().getLocalPart(); 097 ElementConverter converter = (ElementConverter) GERONIMO_SCHEMA_CONVERSIONS.get(localName); 098 if (converter != null) { 099 converter.convertElement(cursor, end); 100 return true; 101 } 102 return false; 103 } 104 //you should only call this method at a start token 105 return false; 106 } 107 108 public static XmlObject fixGeronimoSchema(XmlObject rawPlan, QName desiredElement, SchemaType desiredType) throws XmlException { 109 XmlCursor cursor = rawPlan.newCursor(); 110 try { 111 if (findNestedElement(cursor, desiredElement)) { 112 cursor.push(); 113 convertToGeronimoSubSchemas(cursor); 114 cursor.pop(); 115 XmlObject temp = cursor.getObject(); 116 117 XmlObject result = temp.changeType(desiredType); 118 if (result == null || result.schemaType() != desiredType) { 119 result = temp.copy().changeType(desiredType); 120 } 121 XmlBeansUtil.validateDD(result); 122 return result; 123 } else { 124 return null; 125 } 126 } finally { 127 cursor.dispose(); 128 } 129 } 130 131 public static XmlObject getNestedObject(XmlObject xmlObject, QName desiredElement) { 132 XmlCursor cursor = xmlObject.newCursor(); 133 try { 134 if (findNestedElement(cursor, desiredElement)) { 135 XmlObject child = cursor.getObject(); 136 //The copy seems to be needed to make the type change work for some documents! 137 return child.copy(); 138 } 139 } finally { 140 cursor.dispose(); 141 } 142 throw new IllegalArgumentException("xmlobject did not have desired element: " + desiredElement + "/n" + xmlObject); 143 } 144 145 public static boolean findNestedElement(XmlCursor cursor, QName desiredElement) { 146 while (cursor.hasNextToken()) { 147 if (cursor.isStart()) { 148 QName element = cursor.getName(); 149 if (element.equals(desiredElement)) { 150 return true; 151 } 152 } 153 cursor.toNextToken(); 154 } 155 return false; 156 } 157 158 public static boolean findNestedElement(XmlCursor cursor, String desiredElement) { 159 while (cursor.hasNextToken()) { 160 if (cursor.isStart()) { 161 String element = cursor.getName().getLocalPart(); 162 if (element.equals(desiredElement)) { 163 return true; 164 } 165 } 166 cursor.toNextToken(); 167 } 168 return false; 169 } 170 171 public static XmlObject getNestedObjectAsType(XmlObject xmlObject, QName desiredElement, SchemaType type) { 172 XmlCursor cursor = xmlObject.newCursor(); 173 try { 174 if (findNestedElement(cursor, desiredElement)) { 175 XmlObject child = cursor.getObject(); 176 //The copy seems to be needed to make the type change work for some documents! 177 XmlObject result = child.copy().changeType(type); 178 assert result.schemaType() == type; 179 return result; 180 } 181 } finally { 182 cursor.dispose(); 183 } 184 throw new IllegalArgumentException("xmlobject did not have desired element: " + desiredElement + "\n" + xmlObject); 185 } 186 187 188 public static boolean convertToSchema(XmlCursor cursor, String namespace, String schemaLocationURL, String version) { 189 //remove dtd 190 XmlDocumentProperties xmlDocumentProperties = cursor.documentProperties(); 191 xmlDocumentProperties.remove(XmlDocumentProperties.DOCTYPE_NAME); 192 xmlDocumentProperties.remove(XmlDocumentProperties.DOCTYPE_PUBLIC_ID); 193 xmlDocumentProperties.remove(XmlDocumentProperties.DOCTYPE_SYSTEM_ID); 194 //convert namespace 195 boolean isFirstStart = true; 196 while (cursor.hasNextToken()) { 197 if (cursor.isStart()) { 198 if (namespace.equals(cursor.getName().getNamespaceURI())) { 199 //already has correct schema, exit 200 return false; 201 } 202 cursor.setName(new QName(namespace, cursor.getName().getLocalPart())); 203 cursor.toNextToken(); 204 if (isFirstStart) { 205 cursor.insertNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"); 206 cursor.insertAttributeWithValue(new QName("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation", "xsi"), namespace + schemaLocationURL); 207 cursor.insertAttributeWithValue(new QName("version"), version); 208 isFirstStart = false; 209 } 210 } else { 211 cursor.toNextToken(); 212 } 213 } 214 return true; 215 } 216 217 public static boolean convertSchemaVersion (XmlCursor cursor, String namespace, String schemaLocationURL, String version) { 218 boolean isFirstStart = true; 219 220 221 while (cursor.hasNextToken()) { 222 if (cursor.isStart()) { 223 //convert namespace of each starting element 224 cursor.setName(new QName(namespace, cursor.getName().getLocalPart())); 225 if (isFirstStart) { 226 //if we are at the first element in the document, reset the version number ... 227 cursor.setAttributeText(new QName("version"), version); 228 //... and also set the xsi:schemaLocation 229 cursor.setAttributeText(new QName("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation", "xsi"), namespace + " "+schemaLocationURL); 230 isFirstStart = false; 231 } 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 convertToJNDIEnvironmentRefsGroup(String namespace, XmlCursor cursor, XmlCursor moveable) { 257 moveElements("env-entry", namespace, moveable, cursor); 258 moveElements("ejb-ref", namespace, moveable, cursor); 259 moveElements("ejb-local-ref", namespace, moveable, cursor); 260 moveElements("resource-ref", namespace, moveable, cursor); 261 moveElements("resource-env-ref", namespace, moveable, cursor); 262 moveElements("message-destination-ref", namespace, moveable, cursor); 263 if (cursor.toPrevSibling()) { 264 do { 265 String name = cursor.getName().getLocalPart(); 266 if ("env-entry".equals(name)) { 267 cursor.push(); 268 cursor.toFirstChild(); 269 convertToDescriptionGroup(namespace, cursor, moveable); 270 convertToEnvEntryGroup(namespace, cursor, moveable); 271 cursor.pop(); 272 } 273 } while (cursor.toPrevSibling()); 274 } 275 } 276 277 public static void convertToEnvEntryGroup(String namespace, XmlCursor cursor, XmlCursor moveable) { 278 moveElements("env-entry-name", namespace, moveable, cursor); 279 moveElements("env-entry-type", namespace, moveable, cursor); 280 moveElements("env-entry-value", namespace, moveable, cursor); 281 } 282 283 private static void moveElements(String localName, String namespace, XmlCursor moveable, XmlCursor toHere) { 284 QName name = new QName(namespace, localName); 285 //skip elements already in the correct order. 286 while (name.equals(toHere.getName()) && toHere.toNextSibling()) { 287 } 288 moveable.toCursor(toHere); 289 while (moveable.toNextSibling(name)) { 290 moveable.moveXml(toHere); 291 } 292 } 293 294 }