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