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.upgrade;
018    
019    import java.io.InputStream;
020    import java.io.IOException;
021    import java.io.Writer;
022    import java.util.Map;
023    import java.util.HashMap;
024    import java.util.ArrayList;
025    import java.util.Collection;
026    
027    import javax.xml.namespace.QName;
028    import javax.management.ObjectName;
029    import javax.management.MalformedObjectNameException;
030    
031    import org.apache.xmlbeans.XmlObject;
032    import org.apache.xmlbeans.XmlException;
033    import org.apache.xmlbeans.XmlOptions;
034    import org.apache.xmlbeans.XmlCursor;
035    import org.apache.geronimo.kernel.repository.Artifact;
036    import org.apache.geronimo.kernel.repository.Environment;
037    import org.apache.geronimo.kernel.repository.ImportType;
038    import org.apache.geronimo.deployment.xbeans.EnvironmentType;
039    import org.apache.geronimo.deployment.service.EnvironmentBuilder;
040    
041    /**
042     * @version $Rev: 562176 $ $Date: 2007-08-02 12:31:43 -0400 (Thu, 02 Aug 2007) $
043     */
044    public class Upgrade1_0To1_1 {
045    
046        private static final Map NAMESPACE_UPDATES = new HashMap();
047    
048        static {
049            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/application-client", "http://geronimo.apache.org/xml/ns/j2ee/application-client-2.0");
050            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/application-client-1.1", "http://geronimo.apache.org/xml/ns/j2ee/application-client-2.0");
051            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/application-client-1.2", "http://geronimo.apache.org/xml/ns/j2ee/application-client-2.0");
052            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/application", "http://geronimo.apache.org/xml/ns/j2ee/application-2.0");
053            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/application-1.1", "http://geronimo.apache.org/xml/ns/j2ee/application-2.0");
054            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/application-1.2", "http://geronimo.apache.org/xml/ns/j2ee/application-2.0");
055            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/deployment", "http://geronimo.apache.org/xml/ns/deployment-1.2");
056            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/deployment-1.0", "http://geronimo.apache.org/xml/ns/deployment-1.2");
057            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/deployment-1.1", "http://geronimo.apache.org/xml/ns/deployment-1.2");
058            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/connector", "http://geronimo.apache.org/xml/ns/j2ee/connector-1.2");
059            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/connector-1.0", "http://geronimo.apache.org/xml/ns/j2ee/connector-1.2");
060            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/connector-1.1", "http://geronimo.apache.org/xml/ns/j2ee/connector-1.2");
061            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/deployment/javabean", "http://geronimo.apache.org/xml/ns/deployment/javabean-1.0");
062            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/loginconfig", "http://geronimo.apache.org/xml/ns/loginconfig-1.0");
063            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/loginconfig-1.0", "http://geronimo.apache.org/xml/ns/loginconfig-1.0");
064            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/loginconfig-1.1", "http://geronimo.apache.org/xml/ns/loginconfig-1.0");
065            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/naming", "http://geronimo.apache.org/xml/ns/naming-1.2");
066            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/naming-1.0", "http://geronimo.apache.org/xml/ns/naming-1.2");
067            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/naming-1.1", "http://geronimo.apache.org/xml/ns/naming-1.2");
068            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/security", "http://geronimo.apache.org/xml/ns/security-1.2");
069            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/security-1.0", "http://geronimo.apache.org/xml/ns/security-1.2");
070            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/security-1.1", "http://geronimo.apache.org/xml/ns/security-1.2");
071            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/web", "http://geronimo.apache.org/xml/ns/j2ee/web-2.0");
072            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web-1.0", "http://geronimo.apache.org/xml/ns/j2ee/web-2.0");
073            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web-1.1", "http://geronimo.apache.org/xml/ns/j2ee/web-2.0");
074            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web-1.2", "http://geronimo.apache.org/xml/ns/j2ee/web-2.0");
075            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/web-1.0", "http://geronimo.apache.org/xml/ns/j2ee/web-2.0");
076            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/web/jetty", "http://geronimo.apache.org/xml/ns/j2ee/web/jetty-1.2");
077            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/web/jetty-1.0", "http://geronimo.apache.org/xml/ns/j2ee/web/jetty-2.0");
078            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web/jetty-1.0", "http://geronimo.apache.org/xml/ns/j2ee/web/jetty-2.0");
079            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web/jetty-1.1", "http://geronimo.apache.org/xml/ns/j2ee/web/jetty-2.0");
080            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web/jetty-1.2", "http://geronimo.apache.org/xml/ns/j2ee/web/jetty-2.0");
081            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/web/jetty/config", "http://geronimo.apache.org/xml/ns/j2ee/web/jetty/config-1.0");
082            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/web/tomcat", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0");
083            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/web/tomcat-1.0", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0");
084            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-1.0", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0");
085            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-1.1", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0");
086            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-1.2", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0");
087            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/web/tomcat/config", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat/config-1.0");
088            NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/openejb-jar", "http://www.openejb.org/xml/ns/openejb-jar-2.2");
089            NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/openejb-jar-2.0", "http://www.openejb.org/xml/ns/openejb-jar-2.2");
090            NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/openejb-jar-2.1", "http://www.openejb.org/xml/ns/openejb-jar-2.2");
091            NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/pkgen", "http://www.openejb.org/xml/ns/pkgen-2.0");
092            NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/corba-css-config_1_0", "http://www.openejb.org/xml/ns/corba-css-config-2.0");
093            NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/corba-tss-config_1_0", "http://www.openejb.org/xml/ns/corba-tss-config-2.0");
094        }
095    
096        private static final QName ENVIRONMENT_QNAME = new QName("http://geronimo.apache.org/xml/ns/deployment-1.2", "environment");
097        private static final String DEFAULT_GROUPID = "default";
098        private static final String DEFAULT_VERSION = "1-default";
099        private static final QName CLIENT_ENVIRONMENT_QNAME = new QName("http://geronimo.apache.org/xml/ns/deployment-1.2", "client-environment");
100        private static final QName SERVER_ENVIRONMENT_QNAME = new QName("http://geronimo.apache.org/xml/ns/deployment-1.2", "server-environment");
101        private static final QName PATTERN_QNAME = new QName("http://geronimo.apache.org/xml/ns/naming-1.2", "pattern");
102        private static final QName GROUP_QNAME = new QName("http://geronimo.apache.org/xml/ns/naming-1.2", "groupId");
103        private static final QName ARTIFACT_QNAME = new QName("http://geronimo.apache.org/xml/ns/naming-1.2", "artifactId");
104        private static final QName MODULE_QNAME = new QName("http://geronimo.apache.org/xml/ns/naming-1.2", "module");
105        private static final QName NAME_QNAME = new QName("http://geronimo.apache.org/xml/ns/naming-1.2", "name");
106        private static final QName NAME_QNAME2 = new QName("http://geronimo.apache.org/xml/ns/deployment-1.2", "name");
107        private static final QName GBEAN_NAME_QNAME = new QName(null, "gbeanName");
108    
109        public void upgrade(InputStream source, Writer target) throws IOException, XmlException {
110            XmlObject xmlObject = parse(source);
111            xmlObject = upgrade(xmlObject);
112    
113            XmlOptions xmlOptions = new XmlOptions();
114            xmlOptions.setSavePrettyPrint();
115            xmlObject.save(target, xmlOptions);
116    
117        }
118    
119        public XmlObject upgrade(XmlObject xmlObject) throws XmlException {
120            XmlCursor cursor = xmlObject.newCursor();
121            XmlCursor.TokenType token;
122            while ((token = cursor.toNextToken()) != XmlCursor.TokenType.ENDDOC) {
123                if (token == XmlCursor.TokenType.START) {
124                    Artifact configId = extractArtifact("configId", cursor);
125                    Artifact parentId = extractArtifact("parentId", cursor);
126                    Artifact clientConfigId = extractArtifact("clientConfigId", cursor);
127                    Artifact clientParentId = extractArtifact("clientParentId", cursor);
128                    boolean suppressDefaultEnvironment = extractSuppressDefaultEnvironment(cursor);
129                    if (clientConfigId != null) {
130    
131                        insertEnvironment(clientConfigId, clientParentId, cursor, CLIENT_ENVIRONMENT_QNAME, suppressDefaultEnvironment);
132    
133                        insertEnvironment(configId, parentId, cursor, SERVER_ENVIRONMENT_QNAME, false);
134    
135                    } else if (configId != null) {
136    
137                        insertEnvironment(configId, parentId, cursor, ENVIRONMENT_QNAME, suppressDefaultEnvironment);
138                    } else {
139                        cleanContextPriorityClassLoader(cursor);
140                        cleanRef(cursor);
141                    }
142                    checkInvalid(cursor);
143                }
144            }
145            return xmlObject;
146        }
147    
148        private void cleanContextPriorityClassLoader(XmlCursor cursor) {
149            String localName = getLocalName(cursor);
150            if ("context-priority-classloader".equals(localName)) {
151                String value = cursor.getTextValue();
152                if ("false".equals(value)) {
153                    cursor.removeXml();
154                } else if ("true".equals("true")) {
155                    cursor.removeXml();
156                    cursor.insertComment("YOU MUST INSERT THE ELEMENT <inverse-classloading/> INTO THE ENVIRONMENT ELEMENT FOR THIS MODULE");
157                }
158            }
159        }
160    
161        private static void checkInvalid(XmlCursor cursor) throws XmlException {
162            String localName = getLocalName(cursor);
163            if ("gbean".equals(localName)) {
164                if (cursor.getAttributeText(GBEAN_NAME_QNAME) != null) {
165                    throw new XmlException("You must replace the gbeanName attribute manually: " + cursor.getAttributeText(GBEAN_NAME_QNAME));
166                }
167            }
168        }
169    
170        private static void cleanRef(XmlCursor cursor) throws XmlException {
171            String localName = getLocalName(cursor);
172            if ("ejb-ref".equals(localName)) {
173                cursor.toFirstChild();
174                String application = null;
175                String module = null;
176                String name = null;
177                while (cursor.getName() != null) {
178                    localName = cursor.getName().getLocalPart();
179                    if ("ref-name".equals(localName)) {
180    //                    cursor.toNextSibling();
181                    } else if ("domain".equals(localName)) {
182                        cursor.removeXml();
183                    } else if ("server".equals(localName)) {
184                        cursor.removeXml();
185                    } else if ("application".equals(localName)) {
186                        application = cursor.getTextValue();
187                        if ("null".equals(application)) {
188                            application = null;
189                        }
190                        cursor.removeXml();
191                    } else if ("module".equals(localName)) {
192                        if (application == null) {
193                            //this is a configuration name
194                            application = cursor.getTextValue();
195                        } else {
196                            module = cursor.getTextValue();
197                        }
198                        cursor.removeXml();
199                    } else if ("type".equals(localName)) {
200                        cursor.removeXml();
201                    } else if ("name".equals(localName)) {
202                        name = cursor.getTextValue();
203                        cursor.removeXml();
204                    } else if ("ejb-link".equals(localName)) {
205                        break;
206                    } else if ("target-name".equals(localName)) {
207                        ObjectName targetName = extractObjectName(cursor);
208                        name = targetName.getKeyProperty("name");
209                        application = targetName.getKeyProperty("J2EEApplication");
210                        if ("null".equals(application)) {
211                            application = targetName.getKeyProperty("EJBModule");
212                        } else {
213                            module = targetName.getKeyProperty("EJBModule");
214                        }
215    
216                    } else if ("ns-corbaloc".equals(localName)) {
217                        cursor.toNextSibling();
218    //                    cursor.toNextSibling();
219                    } else if ("css".equals(localName)) {
220                        //TODO fix this
221    //                    cursor.toNextSibling();
222                    } else if ("css-link".equals(localName)) {
223    //                    cursor.toNextSibling();
224                    } else if ("css-name".equals(localName)) {
225    //                    cursor.toNextSibling();
226                    } else {
227                        throw new IllegalStateException("unrecognized element: " + cursor.getTextValue());
228                    }
229                    if (!cursor.toNextSibling()) {
230                        break;
231                    }
232                }
233                if (name != null) {
234                    cursor.beginElement(PATTERN_QNAME);
235                    if (application != null) {
236                        try {
237                            Artifact artifact = Artifact.create(application);
238                            cursor.insertElementWithText(GROUP_QNAME, artifact.getGroupId());
239                            cursor.insertElementWithText(ARTIFACT_QNAME, artifact.getArtifactId());
240                        } catch (Exception e) {
241                            cursor.insertElementWithText(ARTIFACT_QNAME, application.replace('/', '_'));
242                        }
243    //                    cursor.insertElementWithText(VERSION_QNAME, artifact.getVersion().toString());
244                    }
245                    if (module != null) {
246                        cursor.insertElementWithText(MODULE_QNAME, module);
247                    }
248                    cursor.insertElementWithText(NAME_QNAME, name);
249                    cursor.toNextToken();
250                }
251            } else if ("gbean-name".equals(localName)) {
252                ObjectName targetName = extractObjectName(cursor);
253                String name = targetName.getKeyProperty("name");
254                cursor.insertComment("CHECK THAT THE TARGET GBEAN IS IN THE ANCESTOR SET OF THIS MODULE AND THAT THE NAME UNIQUELY IDENTIFIES IT");
255                cursor.insertElementWithText(NAME_QNAME2, name);
256            }
257        }
258    
259        private static ObjectName extractObjectName(XmlCursor cursor) throws XmlException {
260            String targetNameString = cursor.getTextValue();
261            cursor.removeXml();
262            ObjectName targetName;
263            try {
264                targetName = ObjectName.getInstance(targetNameString);
265            } catch (MalformedObjectNameException e) {
266                throw (XmlException)new XmlException("Invalid object name: " + targetNameString).initCause(e);
267            }
268            return targetName;
269        }
270    
271        private static String getLocalName(XmlCursor cursor) {
272            QName name = cursor.getName();
273            return name == null ? null : name.getLocalPart();
274        }
275    
276        private static void insertEnvironment(Artifact configId, Artifact parentId, XmlCursor cursor, QName environmentQname, boolean suppressDefaultEnvironment) {
277            positionEnvironment(cursor);
278            Environment environment = new Environment();
279            environment.setConfigId(configId);
280            if (parentId != null) {
281                environment.addDependency(parentId, ImportType.ALL);
282            }
283            environment.setSuppressDefaultEnvironment(suppressDefaultEnvironment);
284            extractDependencies(cursor, environment);
285            EnvironmentType environmentType = EnvironmentBuilder.buildEnvironmentType(environment);
286            cursor.beginElement(environmentQname);
287            XmlCursor element = environmentType.newCursor();
288            try {
289                element.copyXmlContents(cursor);
290            } finally {
291                element.dispose();
292            }
293        }
294    
295        private static void extractDependencies(XmlCursor cursor, Environment environment) {
296            if (cursor.getName() == null) {
297                //no dependencies, do nothing
298                return;
299            }
300            do {
301                String localPart = getLocalName(cursor);
302                if (localPart.equals("dependency") || localPart.equals("import")) {
303                    extractDependency(cursor, environment);
304                } else {
305                    break;
306                }
307            } while (cursor.toNextSibling());
308        }
309    
310        private static void extractDependency(XmlCursor cursor, Environment environment) {
311            cursor.push();
312            cursor.toFirstChild();
313            Artifact artifact;
314            if (cursor.getName().getLocalPart().equals("uri")) {
315                String uri = cursor.getTextValue();
316                artifact = toArtifact(uri);
317            } else {
318                checkName(cursor, "groupId");
319                String groupId = cursor.getTextValue();
320                cursor.toNextSibling();
321                String type = "jar";
322                if (cursor.getName().getLocalPart().equals("type")) {
323                    type = cursor.getTextValue();
324                    cursor.toNextSibling();
325                }
326                checkName(cursor, "artifactId");
327                String artifactId = cursor.getTextValue();
328                cursor.toNextSibling();
329                checkName(cursor, "version");
330                String version = cursor.getTextValue();
331                artifact = new Artifact(groupId, artifactId, version, type);
332            }
333            environment.addDependency(artifact, ImportType.ALL);
334            cursor.pop();
335            cursor.removeXml();
336        }
337    
338        private static void checkName(XmlCursor cursor, String localName) {
339            if (!cursor.getName().getLocalPart().equals(localName)) {
340                throw new IllegalArgumentException("Expected element: " + localName + " but actually: " + cursor.getName().getLocalPart());
341            }
342    
343        }
344    
345        private static void positionEnvironment(XmlCursor cursor) {
346            XmlCursor.TokenType token;
347            while ((token = cursor.toNextToken()) != XmlCursor.TokenType.START && token != XmlCursor.TokenType.END) {
348                //keep going
349            }
350        }
351    
352        private static Artifact extractArtifact(String attrName, XmlCursor cursor) {
353            String attrValue;
354            QName attrQName = new QName(null, attrName);
355            if ((attrValue = cursor.getAttributeText(attrQName)) != null) {
356                cursor.removeAttribute(attrQName);
357                return toArtifact(attrValue);
358            }
359            return null;
360        }
361    
362        private static Artifact toArtifact(String attrValue) {
363            try {
364                return Artifact.create(attrValue);
365            } catch (Exception e) {
366                return new Artifact(DEFAULT_GROUPID, attrValue.replace('/', '_'), DEFAULT_VERSION, "car");
367            }
368        }
369    
370        private static boolean extractSuppressDefaultEnvironment(XmlCursor cursor) {
371            String attrValue;
372            QName attrQName = new QName(null, "suppressDefaultParentId");
373            if ((attrValue = cursor.getAttributeText(attrQName)) != null) {
374                cursor.removeAttribute(attrQName);
375                return Boolean.valueOf(attrValue).booleanValue();
376            }
377            return false;
378        }
379    
380        public static XmlObject parse(InputStream is) throws IOException, XmlException {
381            ArrayList errors = new ArrayList();
382            XmlObject parsed = XmlObject.Factory.parse(is, createXmlOptions(errors));
383            if (errors.size() != 0) {
384                throw new XmlException(errors.toArray().toString());
385            }
386            return parsed;
387        }
388    
389        public static XmlOptions createXmlOptions(Collection errors) {
390            XmlOptions options = new XmlOptions();
391            options.setLoadLineNumbers();
392            options.setErrorListener(errors);
393            options.setLoadSubstituteNamespaces(NAMESPACE_UPDATES);
394            return options;
395        }
396    
397    }