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