cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aadamc...@apache.org
Subject [3/3] cayenne git commit: CAY-2026 Java 7
Date Sat, 12 Sep 2015 05:50:40 GMT
CAY-2026 Java 7

* DBCP migration - getting rid of DBCP1, renaming DBCP2 classes to use the old DBCP1 names for
  upgrade simplification


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/84a83fe1
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/84a83fe1
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/84a83fe1

Branch: refs/heads/master
Commit: 84a83fe1e8c3b1b95ab2a31149980549f493130c
Parents: de6b038
Author: aadamchik <aadamchik@apache.org>
Authored: Sat Sep 12 08:35:09 2015 +0300
Committer: aadamchik <aadamchik@apache.org>
Committed: Sat Sep 12 08:49:13 2015 +0300

----------------------------------------------------------------------
 assembly/pom.xml                                |  20 +-
 cayenne-dbcp2/pom.xml                           |  15 -
 .../server/DBCP2DataSourceFactory.java          |  93 --
 .../server/DBCPDataSourceFactory.java           |  86 ++
 .../server/DBCP2DataSourceFactoryTest.java      |   6 +-
 ...XMLDataChannelDescriptorLoader_V3_0_0_1.java | 554 ++++++------
 .../upgrade/v7/ProjectUpgrader_V7Test.java      | 900 +++++++++----------
 cayenne-server/pom.xml                          |  12 -
 .../server/DBCPDataSourceFactory.java           | 127 ---
 .../server/DBCPDataSourceFactoryTest.java       | 115 ---
 cayenne-tools/pom.xml                           |  12 -
 docs/doc/pom.xml                                |  12 -
 docs/doc/src/main/resources/UPGRADE.txt         |  19 +-
 modeler/cayenne-modeler/pom.xml                 |  12 -
 .../editor/datanode/DBCPDataSourceEditor.java   |  53 --
 .../editor/datanode/DBCPDataSourceView.java     |  55 --
 .../editor/datanode/MainDataNodeEditor.java     | 571 ++++++------
 pom.xml                                         |  50 +-
 18 files changed, 1094 insertions(+), 1618 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/84a83fe1/assembly/pom.xml
----------------------------------------------------------------------
diff --git a/assembly/pom.xml b/assembly/pom.xml
index 9b2b630..55752dd 100644
--- a/assembly/pom.xml
+++ b/assembly/pom.xml
@@ -72,6 +72,12 @@
 			<version>${project.version}</version>
 		</dependency>
 
+		 <dependency>
+            <groupId>org.apache.cayenne</groupId>
+            <artifactId>cayenne-dbcp2</artifactId>
+            <version>${project.version}</version>
+         </dependency>
+
 		<dependency>
 			<groupId>org.apache.cayenne.modeler</groupId>
 			<artifactId>cayenne-modeler</artifactId>
@@ -369,19 +375,5 @@
                 </dependency>
             </dependencies>
         </profile>
-        <profile>
-            <!-- DBCP2 assembly (can only be run on Java7 and higher) -->
-            <id>dbcp2</id>
-            <activation>
-                <jdk>[1.7,)</jdk>
-            </activation>
-            <dependencies>
-                <dependency>
-                    <groupId>org.apache.cayenne</groupId>
-                    <artifactId>cayenne-dbcp2</artifactId>
-                    <version>${project.version}</version>
-                </dependency>
-            </dependencies>
-        </profile>
 	</profiles>
 </project>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/84a83fe1/cayenne-dbcp2/pom.xml
----------------------------------------------------------------------
diff --git a/cayenne-dbcp2/pom.xml b/cayenne-dbcp2/pom.xml
index 41fde60..f51dfb5 100644
--- a/cayenne-dbcp2/pom.xml
+++ b/cayenne-dbcp2/pom.xml
@@ -22,21 +22,6 @@
     <name>Cayenne DBCP2 Extension</name>
     <packaging>jar</packaging>
 
-    <dependencyManagement>
-        <dependencies>
-            <dependency>
-                <groupId>org.apache.commons</groupId>
-                <artifactId>commons-dbcp2</artifactId>
-                <version>2.1</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.commons</groupId>
-                <artifactId>commons-pool2</artifactId>
-                <version>2.4.2</version>
-            </dependency>
-        </dependencies>
-    </dependencyManagement>
-
     <dependencies>
 
         <!-- Compile dependencies -->

http://git-wip-us.apache.org/repos/asf/cayenne/blob/84a83fe1/cayenne-dbcp2/src/main/java/org/apache/cayenne/configuration/server/DBCP2DataSourceFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-dbcp2/src/main/java/org/apache/cayenne/configuration/server/DBCP2DataSourceFactory.java b/cayenne-dbcp2/src/main/java/org/apache/cayenne/configuration/server/DBCP2DataSourceFactory.java
deleted file mode 100644
index e530bf9..0000000
--- a/cayenne-dbcp2/src/main/java/org/apache/cayenne/configuration/server/DBCP2DataSourceFactory.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-package org.apache.cayenne.configuration.server;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.configuration.DataNodeDescriptor;
-import org.apache.cayenne.resource.Resource;
-import org.apache.commons.dbcp2.BasicDataSourceFactory;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import javax.sql.DataSource;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-/**
- * A {@link DataSourceFactory} based on DBCP2 connection pool library.
- *
- * @since 4.0.M3
- */
-public class DBCP2DataSourceFactory implements DataSourceFactory {
-
-    private static final String DBCP2_PROPERTIES = "dbcp2.properties";
-
-    private static final Log logger = LogFactory.getLog(DBCP2DataSourceFactory.class);
-
-    @Override
-    public DataSource getDataSource(DataNodeDescriptor nodeDescriptor) throws Exception {
-
-        String location = nodeDescriptor.getParameters();
-        if (location == null) {
-            logger.debug("No explicit DBCP2 config location, will use default location: "
-                    + DBCP2_PROPERTIES);
-            location = DBCP2_PROPERTIES;
-        }
-
-        Resource baseConfiguration = nodeDescriptor.getConfigurationSource();
-        if (baseConfiguration == null) {
-            throw new CayenneRuntimeException(
-                    "Null 'configurationSource' for nodeDescriptor '%s'",
-                    nodeDescriptor.getName());
-        }
-
-        Resource dbcp2Configuration = baseConfiguration.getRelativeResource(location);
-        if (dbcp2Configuration == null) {
-            throw new CayenneRuntimeException(
-                    "Missing DBCP2 configuration '%s' for nodeDescriptor '%s'",
-                    location,
-                    nodeDescriptor.getName());
-        }
-
-        Properties properties = getProperties(dbcp2Configuration);
-        if (logger.isDebugEnabled()) {
-            logger.debug("DBCP2 Properties: " + properties);
-        }
-
-        return BasicDataSourceFactory.createDataSource(properties);
-    }
-
-    private Properties getProperties(Resource dbcp2Configuration) throws IOException {
-        Properties properties = new Properties();
-        InputStream in = dbcp2Configuration.getURL().openStream();
-        try {
-            properties.load(in);
-        }
-        finally {
-            try {
-                in.close();
-            }
-            catch (IOException e) {
-            }
-        }
-
-        return properties;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/84a83fe1/cayenne-dbcp2/src/main/java/org/apache/cayenne/configuration/server/DBCPDataSourceFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-dbcp2/src/main/java/org/apache/cayenne/configuration/server/DBCPDataSourceFactory.java b/cayenne-dbcp2/src/main/java/org/apache/cayenne/configuration/server/DBCPDataSourceFactory.java
new file mode 100644
index 0000000..ecdc59d
--- /dev/null
+++ b/cayenne-dbcp2/src/main/java/org/apache/cayenne/configuration/server/DBCPDataSourceFactory.java
@@ -0,0 +1,86 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.configuration.server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import javax.sql.DataSource;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.configuration.DataNodeDescriptor;
+import org.apache.cayenne.resource.Resource;
+import org.apache.commons.dbcp2.BasicDataSourceFactory;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * A {@link DataSourceFactory} based on DBCP2 connection pool library.
+ */
+public class DBCPDataSourceFactory implements DataSourceFactory {
+
+	private static final String DBCP2_PROPERTIES = "dbcp2.properties";
+
+	private static final Log logger = LogFactory.getLog(DBCPDataSourceFactory.class);
+
+	@Override
+	public DataSource getDataSource(DataNodeDescriptor nodeDescriptor) throws Exception {
+
+		String location = nodeDescriptor.getParameters();
+		if (location == null) {
+			logger.debug("No explicit DBCP2 config location, will use default location: " + DBCP2_PROPERTIES);
+			location = DBCP2_PROPERTIES;
+		}
+
+		Resource baseConfiguration = nodeDescriptor.getConfigurationSource();
+		if (baseConfiguration == null) {
+			throw new CayenneRuntimeException("Null 'configurationSource' for nodeDescriptor '%s'",
+					nodeDescriptor.getName());
+		}
+
+		Resource dbcp2Configuration = baseConfiguration.getRelativeResource(location);
+		if (dbcp2Configuration == null) {
+			throw new CayenneRuntimeException("Missing DBCP2 configuration '%s' for nodeDescriptor '%s'", location,
+					nodeDescriptor.getName());
+		}
+
+		Properties properties = getProperties(dbcp2Configuration);
+		if (logger.isDebugEnabled()) {
+			logger.debug("DBCP2 Properties: " + properties);
+		}
+
+		return BasicDataSourceFactory.createDataSource(properties);
+	}
+
+	private Properties getProperties(Resource dbcp2Configuration) throws IOException {
+		Properties properties = new Properties();
+		InputStream in = dbcp2Configuration.getURL().openStream();
+		try {
+			properties.load(in);
+		} finally {
+			try {
+				in.close();
+			} catch (IOException e) {
+			}
+		}
+
+		return properties;
+	}
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/84a83fe1/cayenne-dbcp2/src/test/java/org/apache/cayenne/configuration/server/DBCP2DataSourceFactoryTest.java
----------------------------------------------------------------------
diff --git a/cayenne-dbcp2/src/test/java/org/apache/cayenne/configuration/server/DBCP2DataSourceFactoryTest.java b/cayenne-dbcp2/src/test/java/org/apache/cayenne/configuration/server/DBCP2DataSourceFactoryTest.java
index 3a5516b..62ca6ca 100644
--- a/cayenne-dbcp2/src/test/java/org/apache/cayenne/configuration/server/DBCP2DataSourceFactoryTest.java
+++ b/cayenne-dbcp2/src/test/java/org/apache/cayenne/configuration/server/DBCP2DataSourceFactoryTest.java
@@ -46,7 +46,7 @@ public class DBCP2DataSourceFactoryTest {
         nodeDescriptor.setConfigurationSource(new URLResource(url));
         nodeDescriptor.setParameters("testDBCP2.properties");
 
-        DBCP2DataSourceFactory factory = new DBCP2DataSourceFactory();
+        DBCPDataSourceFactory factory = new DBCPDataSourceFactory();
         DataSource dataSource = factory.getDataSource(nodeDescriptor);
         assertNotNull(dataSource);
 
@@ -63,7 +63,7 @@ public class DBCP2DataSourceFactoryTest {
         assertEquals("select 1 from xyz;", basicDataSource.getValidationQuery());
 
 
-        System.out.println(DBCP2DataSourceFactory.class.getName());
+        System.out.println(DBCPDataSourceFactory.class.getName());
     }
 
     @Test
@@ -77,7 +77,7 @@ public class DBCP2DataSourceFactoryTest {
         nodeDescriptor.setConfigurationSource(new URLResource(url));
         nodeDescriptor.setParameters("testDBCP2.properties.nosuchfile");
 
-        DBCP2DataSourceFactory factory = new DBCP2DataSourceFactory();
+        DBCPDataSourceFactory factory = new DBCPDataSourceFactory();
 
         try {
             factory.getDataSource(nodeDescriptor);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/84a83fe1/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/v6/XMLDataChannelDescriptorLoader_V3_0_0_1.java
----------------------------------------------------------------------
diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/v6/XMLDataChannelDescriptorLoader_V3_0_0_1.java b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/v6/XMLDataChannelDescriptorLoader_V3_0_0_1.java
index f7b58fd..fef935f 100644
--- a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/v6/XMLDataChannelDescriptorLoader_V3_0_0_1.java
+++ b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/v6/XMLDataChannelDescriptorLoader_V3_0_0_1.java
@@ -31,7 +31,6 @@ import org.apache.cayenne.ConfigurationException;
 import org.apache.cayenne.configuration.DataChannelDescriptor;
 import org.apache.cayenne.configuration.DataNodeDescriptor;
 import org.apache.cayenne.configuration.SAXNestedTagHandler;
-import org.apache.cayenne.configuration.server.DBCPDataSourceFactory;
 import org.apache.cayenne.configuration.server.JNDIDataSourceFactory;
 import org.apache.cayenne.configuration.server.XMLPoolingDataSourceFactory;
 import org.apache.cayenne.conn.DataSourceInfo;
@@ -50,300 +49,261 @@ import org.xml.sax.XMLReader;
  */
 class XMLDataChannelDescriptorLoader_V3_0_0_1 {
 
-    private static Log logger = LogFactory
-            .getLog(XMLDataChannelDescriptorLoader_V3_0_0_1.class);
-
-    static final String DOMAINS_TAG = "domains";
-    static final String DOMAIN_TAG = "domain";
-    static final String MAP_TAG = "map";
-    static final String NODE_TAG = "node";
-    static final String PROPERTY_TAG = "property";
-    static final String MAP_REF_TAG = "map-ref";
-
-    private static final Map<String, String> dataSourceFactoryLegacyNameMapping;
-
-    static {
-        dataSourceFactoryLegacyNameMapping = new HashMap<String, String>();
-        dataSourceFactoryLegacyNameMapping.put(
-                "org.apache.cayenne.conf.DriverDataSourceFactory",
-                XMLPoolingDataSourceFactory.class.getName());
-        dataSourceFactoryLegacyNameMapping.put(
-                "org.apache.cayenne.conf.JNDIDataSourceFactory",
-                JNDIDataSourceFactory.class.getName());
-        dataSourceFactoryLegacyNameMapping.put(
-                "org.apache.cayenne.conf.DBCPDataSourceFactory",
-                DBCPDataSourceFactory.class.getName());
-    }
-
-    // implementation is statically typed and is intentionally not DI-provided
-    protected XMLDataMapLoader_V3_0_0_1 mapLoader;
-    protected XMLDataSourceInfoLoader_V3_0_0_1 dataSourceInfoLoader;
-
-    XMLDataChannelDescriptorLoader_V3_0_0_1() {
-        mapLoader = new XMLDataMapLoader_V3_0_0_1();
-        dataSourceInfoLoader = new XMLDataSourceInfoLoader_V3_0_0_1();
-    }
-
-    List<DataChannelDescriptor> load(Resource configurationSource)
-            throws ConfigurationException {
-
-        if (configurationSource == null) {
-            throw new NullPointerException("Null configurationSource");
-        }
-
-        URL configurationURL = configurationSource.getURL();
-
-        List<DataChannelDescriptor> domains = new ArrayList<DataChannelDescriptor>();
-        InputStream in = null;
-
-        try {
-            in = configurationURL.openStream();
-            XMLReader parser = Util.createXmlReader();
-
-            DomainsHandler rootHandler = new DomainsHandler(
-                    configurationSource,
-                    domains,
-                    parser);
-            parser.setContentHandler(rootHandler);
-            parser.setErrorHandler(rootHandler);
-            parser.parse(new InputSource(in));
-        }
-        catch (Exception e) {
-            throw new ConfigurationException(
-                    "Error loading configuration from %s",
-                    e,
-                    configurationURL);
-        }
-        finally {
-            try {
-                if (in != null) {
-                    in.close();
-                }
-            }
-            catch (IOException ioex) {
-                logger.info("failure closing input stream for "
-                        + configurationURL
-                        + ", ignoring", ioex);
-            }
-        }
-
-        return domains;
-    }
-
-    /**
-     * Make sure the domain name is only made up of Java-identifier-safe characters.
-     */
-    protected String scrubDomainName(String name) {
-        if (name == null || name.length() == 0) {
-            return name;
-        }
-
-        StringBuilder buffer = new StringBuilder(name.length());
-
-        for (int i = 0; i < name.length(); i++) {
-            char c = name.charAt(i);
-            if (i == 0 && !Character.isJavaIdentifierStart(c)) {
-                buffer.append('_');
-            }
-            else if (i > 0 && !Character.isJavaIdentifierPart(c)) {
-                buffer.append('_');
-            }
-            else {
-                buffer.append(c);
-            }
-        }
-
-        return buffer.toString();
-    }
-
-    /**
-     * Converts the names of standard Cayenne-supplied DataSourceFactories from the legacy
-     * names to the current names.
-     */
-    private String convertDataSourceFactory(String dataSourceFactory) {
-
-        if (dataSourceFactory == null) {
-            return null;
-        }
-
-        String converted = dataSourceFactoryLegacyNameMapping.get(dataSourceFactory);
-        return converted != null ? converted : dataSourceFactory;
-    }
-
-    final class DomainsHandler extends SAXNestedTagHandler {
-
-        private Collection<DataChannelDescriptor> domains;
-        private Resource configurationSource;
-
-        DomainsHandler(Resource configurationSource,
-                Collection<DataChannelDescriptor> domains, XMLReader parser) {
-            super(parser, null);
-            this.domains = domains;
-            this.configurationSource = configurationSource;
-        }
-
-        @Override
-        protected ContentHandler createChildTagHandler(
-                String namespaceURI,
-                String localName,
-                String qName,
-                Attributes attributes) {
-
-            if (localName.equals(DOMAINS_TAG)) {
-                return new DomainsChildrenHandler(parser, this);
-            }
-
-            return super
-                    .createChildTagHandler(namespaceURI, localName, qName, attributes);
-        }
-    }
-
-    final class DomainsChildrenHandler extends SAXNestedTagHandler {
-
-        private Collection<DataChannelDescriptor> domains;
-        private Resource configurationSource;
-
-        DomainsChildrenHandler(XMLReader parser, DomainsHandler parent) {
-            super(parser, parent);
-            this.domains = parent.domains;
-            this.configurationSource = parent.configurationSource;
-        }
-
-        @Override
-        protected ContentHandler createChildTagHandler(
-                String namespaceURI,
-                String localName,
-                String name,
-                Attributes attributes) {
-
-            if (localName.equals(DOMAIN_TAG)) {
-
-                String domainName = attributes.getValue("", "name");
-                DataChannelDescriptor descriptor = new DataChannelDescriptor();
-                descriptor.setName(scrubDomainName(domainName));
-                descriptor.setConfigurationSource(configurationSource);
-
-                domains.add(descriptor);
-                return new DataChannelChildrenHandler(descriptor, parser, this);
-            }
-
-            logger.info(unexpectedTagMessage(localName, DOMAIN_TAG));
-            return super.createChildTagHandler(namespaceURI, localName, name, attributes);
-        }
-    }
-
-    final class DataChannelChildrenHandler extends SAXNestedTagHandler {
-
-        private DataChannelDescriptor descriptor;
-
-        DataChannelChildrenHandler(DataChannelDescriptor descriptor, XMLReader parser,
-                DomainsChildrenHandler parentHandler) {
-            super(parser, parentHandler);
-            this.descriptor = descriptor;
-        }
-
-        @Override
-        protected ContentHandler createChildTagHandler(
-                String namespaceURI,
-                String localName,
-                String name,
-                Attributes attributes) {
-
-            if (localName.equals(PROPERTY_TAG)) {
-
-                String key = attributes.getValue("", "name");
-                String value = attributes.getValue("", "value");
-                if (key != null && value != null) {
-                    descriptor.getProperties().put(key, value);
-                }
-            }
-            else if (localName.equals(MAP_TAG)) {
-
-                String dataMapName = attributes.getValue("", "name");
-                Resource baseResource = descriptor.getConfigurationSource();
-
-                String dataMapLocation = attributes.getValue("", "location");
-                Resource dataMapResource = baseResource
-                        .getRelativeResource(dataMapLocation);
-
-                DataMap dataMap = mapLoader.load(dataMapResource);
-                dataMap.setName(dataMapName);
-                dataMap.setLocation(dataMapLocation);
-                dataMap.setConfigurationSource(dataMapResource);
-
-                descriptor.getDataMaps().add(dataMap);
-            }
-            else if (localName.equals(NODE_TAG)) {
-
-                String nodeName = attributes.getValue("", "name");
-                if (nodeName == null) {
-                    // TODO: assign dummy name?
-                    throw new ConfigurationException("Error: <node> without 'name'.");
-                }
-
-                DataNodeDescriptor nodeDescriptor = new DataNodeDescriptor();
-                nodeDescriptor.setName(nodeName);
-
-                String dataSourceFactory = attributes.getValue("", "factory");
-                String dataSourceFactory6 = convertDataSourceFactory(dataSourceFactory);
-                nodeDescriptor.setDataSourceFactoryType(dataSourceFactory6);
-
-                // depending on the factory, "datasource" attribute is interpreted
-                // differently
-                String datasource = attributes.getValue("", "datasource");
-                if (XMLPoolingDataSourceFactory.class
-                        .getName()
-                        .equals(dataSourceFactory6)) {
-                    Resource baseResource = descriptor.getConfigurationSource();
-                    Resource dataNodeResource = baseResource
-                            .getRelativeResource(datasource);
-                    nodeDescriptor.setConfigurationSource(dataNodeResource);
-
-                    DataSourceInfo dataSourceInfo = dataSourceInfoLoader
-                            .load(dataNodeResource);
-                    nodeDescriptor.setDataSourceDescriptor(dataSourceInfo);
-                }
-                else {
-                    nodeDescriptor.setParameters(datasource);
-                }
-
-                descriptor.getNodeDescriptors().add(nodeDescriptor);
-                nodeDescriptor.setAdapterType(attributes.getValue("", "adapter"));
-                nodeDescriptor.setSchemaUpdateStrategyType(attributes.getValue(
-                        "",
-                        "schema-update-strategy"));
-
-                return new DataNodeChildrenHandler(parser, this, nodeDescriptor);
-            }
-
-            return super.createChildTagHandler(namespaceURI, localName, name, attributes);
-        }
-    }
-
-    final class DataNodeChildrenHandler extends SAXNestedTagHandler {
-
-        private DataNodeDescriptor nodeDescriptor;
-
-        DataNodeChildrenHandler(XMLReader parser, SAXNestedTagHandler parentHandler,
-                DataNodeDescriptor nodeDescriptor) {
-            super(parser, parentHandler);
-            this.nodeDescriptor = nodeDescriptor;
-        }
-
-        @Override
-        protected ContentHandler createChildTagHandler(
-                String namespaceURI,
-                String localName,
-                String name,
-                Attributes attributes) {
-
-            if (localName.equals(MAP_REF_TAG)) {
-
-                String mapName = attributes.getValue("", "name");
-                nodeDescriptor.getDataMapNames().add(mapName);
-            }
-
-            return super.createChildTagHandler(namespaceURI, localName, name, attributes);
-        }
-    }
+	static final String DBCP_DATA_SOURCE_FACTORY = "org.apache.cayenne.configuration.server.DBCPDataSourceFactory";
+
+	private static Log logger = LogFactory.getLog(XMLDataChannelDescriptorLoader_V3_0_0_1.class);
+
+	static final String DOMAINS_TAG = "domains";
+	static final String DOMAIN_TAG = "domain";
+	static final String MAP_TAG = "map";
+	static final String NODE_TAG = "node";
+	static final String PROPERTY_TAG = "property";
+	static final String MAP_REF_TAG = "map-ref";
+
+	private static final Map<String, String> dataSourceFactoryLegacyNameMapping;
+
+	static {
+		dataSourceFactoryLegacyNameMapping = new HashMap<String, String>();
+		dataSourceFactoryLegacyNameMapping.put("org.apache.cayenne.conf.DriverDataSourceFactory",
+				XMLPoolingDataSourceFactory.class.getName());
+		dataSourceFactoryLegacyNameMapping.put("org.apache.cayenne.conf.JNDIDataSourceFactory",
+				JNDIDataSourceFactory.class.getName());
+		dataSourceFactoryLegacyNameMapping.put("org.apache.cayenne.conf.DBCPDataSourceFactory",
+				DBCP_DATA_SOURCE_FACTORY);
+	}
+
+	// implementation is statically typed and is intentionally not DI-provided
+	protected XMLDataMapLoader_V3_0_0_1 mapLoader;
+	protected XMLDataSourceInfoLoader_V3_0_0_1 dataSourceInfoLoader;
+
+	XMLDataChannelDescriptorLoader_V3_0_0_1() {
+		mapLoader = new XMLDataMapLoader_V3_0_0_1();
+		dataSourceInfoLoader = new XMLDataSourceInfoLoader_V3_0_0_1();
+	}
+
+	List<DataChannelDescriptor> load(Resource configurationSource) throws ConfigurationException {
+
+		if (configurationSource == null) {
+			throw new NullPointerException("Null configurationSource");
+		}
+
+		URL configurationURL = configurationSource.getURL();
+
+		List<DataChannelDescriptor> domains = new ArrayList<DataChannelDescriptor>();
+		InputStream in = null;
+
+		try {
+			in = configurationURL.openStream();
+			XMLReader parser = Util.createXmlReader();
+
+			DomainsHandler rootHandler = new DomainsHandler(configurationSource, domains, parser);
+			parser.setContentHandler(rootHandler);
+			parser.setErrorHandler(rootHandler);
+			parser.parse(new InputSource(in));
+		} catch (Exception e) {
+			throw new ConfigurationException("Error loading configuration from %s", e, configurationURL);
+		} finally {
+			try {
+				if (in != null) {
+					in.close();
+				}
+			} catch (IOException ioex) {
+				logger.info("failure closing input stream for " + configurationURL + ", ignoring", ioex);
+			}
+		}
+
+		return domains;
+	}
+
+	/**
+	 * Make sure the domain name is only made up of Java-identifier-safe
+	 * characters.
+	 */
+	protected String scrubDomainName(String name) {
+		if (name == null || name.length() == 0) {
+			return name;
+		}
+
+		StringBuilder buffer = new StringBuilder(name.length());
+
+		for (int i = 0; i < name.length(); i++) {
+			char c = name.charAt(i);
+			if (i == 0 && !Character.isJavaIdentifierStart(c)) {
+				buffer.append('_');
+			} else if (i > 0 && !Character.isJavaIdentifierPart(c)) {
+				buffer.append('_');
+			} else {
+				buffer.append(c);
+			}
+		}
+
+		return buffer.toString();
+	}
+
+	/**
+	 * Converts the names of standard Cayenne-supplied DataSourceFactories from
+	 * the legacy names to the current names.
+	 */
+	private String convertDataSourceFactory(String dataSourceFactory) {
+
+		if (dataSourceFactory == null) {
+			return null;
+		}
+
+		String converted = dataSourceFactoryLegacyNameMapping.get(dataSourceFactory);
+		return converted != null ? converted : dataSourceFactory;
+	}
+
+	final class DomainsHandler extends SAXNestedTagHandler {
+
+		private Collection<DataChannelDescriptor> domains;
+		private Resource configurationSource;
+
+		DomainsHandler(Resource configurationSource, Collection<DataChannelDescriptor> domains, XMLReader parser) {
+			super(parser, null);
+			this.domains = domains;
+			this.configurationSource = configurationSource;
+		}
+
+		@Override
+		protected ContentHandler createChildTagHandler(String namespaceURI, String localName, String qName,
+				Attributes attributes) {
+
+			if (localName.equals(DOMAINS_TAG)) {
+				return new DomainsChildrenHandler(parser, this);
+			}
+
+			return super.createChildTagHandler(namespaceURI, localName, qName, attributes);
+		}
+	}
+
+	final class DomainsChildrenHandler extends SAXNestedTagHandler {
+
+		private Collection<DataChannelDescriptor> domains;
+		private Resource configurationSource;
+
+		DomainsChildrenHandler(XMLReader parser, DomainsHandler parent) {
+			super(parser, parent);
+			this.domains = parent.domains;
+			this.configurationSource = parent.configurationSource;
+		}
+
+		@Override
+		protected ContentHandler createChildTagHandler(String namespaceURI, String localName, String name,
+				Attributes attributes) {
+
+			if (localName.equals(DOMAIN_TAG)) {
+
+				String domainName = attributes.getValue("", "name");
+				DataChannelDescriptor descriptor = new DataChannelDescriptor();
+				descriptor.setName(scrubDomainName(domainName));
+				descriptor.setConfigurationSource(configurationSource);
+
+				domains.add(descriptor);
+				return new DataChannelChildrenHandler(descriptor, parser, this);
+			}
+
+			logger.info(unexpectedTagMessage(localName, DOMAIN_TAG));
+			return super.createChildTagHandler(namespaceURI, localName, name, attributes);
+		}
+	}
+
+	final class DataChannelChildrenHandler extends SAXNestedTagHandler {
+
+		private DataChannelDescriptor descriptor;
+
+		DataChannelChildrenHandler(DataChannelDescriptor descriptor, XMLReader parser,
+				DomainsChildrenHandler parentHandler) {
+			super(parser, parentHandler);
+			this.descriptor = descriptor;
+		}
+
+		@Override
+		protected ContentHandler createChildTagHandler(String namespaceURI, String localName, String name,
+				Attributes attributes) {
+
+			if (localName.equals(PROPERTY_TAG)) {
+
+				String key = attributes.getValue("", "name");
+				String value = attributes.getValue("", "value");
+				if (key != null && value != null) {
+					descriptor.getProperties().put(key, value);
+				}
+			} else if (localName.equals(MAP_TAG)) {
+
+				String dataMapName = attributes.getValue("", "name");
+				Resource baseResource = descriptor.getConfigurationSource();
+
+				String dataMapLocation = attributes.getValue("", "location");
+				Resource dataMapResource = baseResource.getRelativeResource(dataMapLocation);
+
+				DataMap dataMap = mapLoader.load(dataMapResource);
+				dataMap.setName(dataMapName);
+				dataMap.setLocation(dataMapLocation);
+				dataMap.setConfigurationSource(dataMapResource);
+
+				descriptor.getDataMaps().add(dataMap);
+			} else if (localName.equals(NODE_TAG)) {
+
+				String nodeName = attributes.getValue("", "name");
+				if (nodeName == null) {
+					// TODO: assign dummy name?
+					throw new ConfigurationException("Error: <node> without 'name'.");
+				}
+
+				DataNodeDescriptor nodeDescriptor = new DataNodeDescriptor();
+				nodeDescriptor.setName(nodeName);
+
+				String dataSourceFactory = attributes.getValue("", "factory");
+				String dataSourceFactory6 = convertDataSourceFactory(dataSourceFactory);
+				nodeDescriptor.setDataSourceFactoryType(dataSourceFactory6);
+
+				// depending on the factory, "datasource" attribute is
+				// interpreted
+				// differently
+				String datasource = attributes.getValue("", "datasource");
+				if (XMLPoolingDataSourceFactory.class.getName().equals(dataSourceFactory6)) {
+					Resource baseResource = descriptor.getConfigurationSource();
+					Resource dataNodeResource = baseResource.getRelativeResource(datasource);
+					nodeDescriptor.setConfigurationSource(dataNodeResource);
+
+					DataSourceInfo dataSourceInfo = dataSourceInfoLoader.load(dataNodeResource);
+					nodeDescriptor.setDataSourceDescriptor(dataSourceInfo);
+				} else {
+					nodeDescriptor.setParameters(datasource);
+				}
+
+				descriptor.getNodeDescriptors().add(nodeDescriptor);
+				nodeDescriptor.setAdapterType(attributes.getValue("", "adapter"));
+				nodeDescriptor.setSchemaUpdateStrategyType(attributes.getValue("", "schema-update-strategy"));
+
+				return new DataNodeChildrenHandler(parser, this, nodeDescriptor);
+			}
+
+			return super.createChildTagHandler(namespaceURI, localName, name, attributes);
+		}
+	}
+
+	final class DataNodeChildrenHandler extends SAXNestedTagHandler {
+
+		private DataNodeDescriptor nodeDescriptor;
+
+		DataNodeChildrenHandler(XMLReader parser, SAXNestedTagHandler parentHandler, DataNodeDescriptor nodeDescriptor) {
+			super(parser, parentHandler);
+			this.nodeDescriptor = nodeDescriptor;
+		}
+
+		@Override
+		protected ContentHandler createChildTagHandler(String namespaceURI, String localName, String name,
+				Attributes attributes) {
+
+			if (localName.equals(MAP_REF_TAG)) {
+
+				String mapName = attributes.getValue("", "name");
+				nodeDescriptor.getDataMapNames().add(mapName);
+			}
+
+			return super.createChildTagHandler(namespaceURI, localName, name, attributes);
+		}
+	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/84a83fe1/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/v7/ProjectUpgrader_V7Test.java
----------------------------------------------------------------------
diff --git a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/v7/ProjectUpgrader_V7Test.java b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/v7/ProjectUpgrader_V7Test.java
index 2cbd9af..250ae29 100644
--- a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/v7/ProjectUpgrader_V7Test.java
+++ b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/v7/ProjectUpgrader_V7Test.java
@@ -18,11 +18,28 @@
  ****************************************************************/
 package org.apache.cayenne.project.upgrade.v7;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathFactory;
+
 import org.apache.cayenne.configuration.ConfigurationNameMapper;
 import org.apache.cayenne.configuration.DataMapLoader;
 import org.apache.cayenne.configuration.DefaultConfigurationNameMapper;
 import org.apache.cayenne.configuration.XMLDataMapLoader;
-import org.apache.cayenne.configuration.server.DBCPDataSourceFactory;
 import org.apache.cayenne.configuration.server.JNDIDataSourceFactory;
 import org.apache.cayenne.configuration.server.XMLPoolingDataSourceFactory;
 import org.apache.cayenne.di.AdhocObjectFactory;
@@ -47,466 +64,449 @@ import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import javax.xml.xpath.XPathFactory;
-import java.io.File;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
 public class ProjectUpgrader_V7Test extends Project2Case {
 
-    @Test
-    public void testMetadata_3_0_0_1() {
-
-        String baseUrl = getClass().getPackage().getName().replace('.', '/');
-        URL url = getClass().getClassLoader().getResource(baseUrl + "/3_0_0_1a/cayenne.xml");
-        assertNotNull(url);
-
-        Module testModule = new Module() {
-
-            public void configure(Binder binder) {
-                binder.bind(ProjectSaver.class).to(FileProjectSaver.class);
-                binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
-            }
-        };
-
-        ProjectUpgrader_V7 upgrader = new ProjectUpgrader_V7();
-        Injector injector = DIBootstrap.createInjector(testModule);
-        injector.injectMembers(upgrader);
-
-        Resource source = new URLResource(url);
-        UpgradeHandler handler = upgrader.getUpgradeHandler(source);
-
-        assertNotNull(handler);
-        assertSame(source, handler.getProjectSource());
-
-        UpgradeMetaData md = handler.getUpgradeMetaData();
-        assertNotNull(md);
-
-        assertSame(UpgradeType.UPGRADE_NEEDED, md.getUpgradeType());
-        // assertEquals("6", md.getIntermediateUpgradeVersion());
-        assertNull(md.getIntermediateUpgradeVersion());
-        assertEquals("3.0.0.1", md.getProjectVersion());
-        assertEquals("7", md.getSupportedVersion());
-    }
-
-    @Test
-    public void testMetadata_Type2_0() {
-        String baseUrl = getClass().getPackage().getName().replace('.', '/');
-        URL url = getClass().getClassLoader().getResource(baseUrl + "/2_0a/cayenne.xml");
-        assertNotNull(url);
-
-        Module testModule = new Module() {
-
-            public void configure(Binder binder) {
-                binder.bind(ProjectSaver.class).to(FileProjectSaver.class);
-                binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
-            }
-        };
-
-        ProjectUpgrader_V7 upgrader = new ProjectUpgrader_V7();
-        Injector injector = DIBootstrap.createInjector(testModule);
-        injector.injectMembers(upgrader);
-
-        Resource source = new URLResource(url);
-        UpgradeHandler handler = upgrader.getUpgradeHandler(source);
-
-        assertNotNull(handler);
-        assertSame(source, handler.getProjectSource());
-
-        UpgradeMetaData md = handler.getUpgradeMetaData();
-        assertNotNull(md);
-        assertSame(UpgradeType.INTERMEDIATE_UPGRADE_NEEDED, md.getUpgradeType());
-        assertEquals("3.0.0.1", md.getIntermediateUpgradeVersion());
-        assertEquals("2.0", md.getProjectVersion());
-        assertEquals("7", md.getSupportedVersion());
-    }
-
-    @Test
-    public void testMetadata_Type6() {
-        String baseUrl = getClass().getPackage().getName().replace('.', '/');
-        URL url = getClass().getClassLoader().getResource(baseUrl + "/6a/cayenne-PROJECT1.xml");
-        assertNotNull(url);
-
-        Module testModule = new Module() {
-
-            public void configure(Binder binder) {
-                binder.bind(ProjectSaver.class).to(FileProjectSaver.class);
-                binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
-            }
-        };
-
-        ProjectUpgrader_V7 upgrader = new ProjectUpgrader_V7();
-        Injector injector = DIBootstrap.createInjector(testModule);
-        injector.injectMembers(upgrader);
-
-        Resource source = new URLResource(url);
-        UpgradeHandler handler = upgrader.getUpgradeHandler(source);
-
-        assertNotNull(handler);
-        assertSame(source, handler.getProjectSource());
-
-        UpgradeMetaData md = handler.getUpgradeMetaData();
-        assertNotNull(md);
-        assertSame(UpgradeType.UPGRADE_NEEDED, md.getUpgradeType());
-        assertNull(md.getIntermediateUpgradeVersion());
-        assertEquals("6", md.getProjectVersion());
-        assertEquals("7", md.getSupportedVersion());
-    }
-
-    @Test
-    public void testMetadata_Type7() {
-        String baseUrl = getClass().getPackage().getName().replace('.', '/');
-        URL url = getClass().getClassLoader().getResource(baseUrl + "/7a/cayenne-PROJECT1.xml");
-        assertNotNull(url);
-
-        Module testModule = new Module() {
-
-            public void configure(Binder binder) {
-                binder.bind(ProjectSaver.class).to(FileProjectSaver.class);
-                binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
-            }
-        };
-
-        ProjectUpgrader_V7 upgrader = new ProjectUpgrader_V7();
-        Injector injector = DIBootstrap.createInjector(testModule);
-        injector.injectMembers(upgrader);
-
-        Resource source = new URLResource(url);
-        UpgradeHandler handler = upgrader.getUpgradeHandler(source);
-
-        assertNotNull(handler);
-        assertSame(source, handler.getProjectSource());
-
-        UpgradeMetaData md = handler.getUpgradeMetaData();
-        assertNotNull(md);
-        assertSame(UpgradeType.UPGRADE_NOT_NEEDED, md.getUpgradeType());
-        assertNull(md.getIntermediateUpgradeVersion());
-        assertEquals("7", md.getProjectVersion());
-        assertEquals("7", md.getSupportedVersion());
-    }
-
-    @Test
-    public void testPerformUpgradeFrom3() throws Exception {
-
-        File testFolder = setupTestDirectory("testPerformUpgrade_3_0_0_1");
-        String sourceUrl = getClass().getPackage().getName().replace('.', '/') + "/3_0_0_1a/";
-
-        List<String> sources = new ArrayList<String>();
-
-        sources.add("cayenne.xml");
-        sources.add("d1Map1.map.xml");
-        sources.add("d1Map2.map.xml");
-        sources.add("d1NodeDriver.driver.xml");
-
-        // upgrades are done in-place, so copy it first
-        List<File> targetsBefore = new ArrayList<File>();
-        for (String source : sources) {
-
-            URL url = getClass().getClassLoader().getResource(sourceUrl + source);
-            File target = new File(testFolder, source);
-            assertNotNull(source);
-            ResourceUtil.copyResourceToFile(url, target);
-            targetsBefore.add(target);
-        }
-
-        Module testModule = new Module() {
-
-            public void configure(Binder binder) {
-                binder.bind(ClassLoaderManager.class).to(DefaultClassLoaderManager.class);
-                binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
-                binder.bind(ProjectSaver.class).to(FileProjectSaver.class);
-                binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
-                binder.bind(DataMapLoader.class).to(XMLDataMapLoader.class);
-            }
-        };
-
-        ProjectUpgrader_V7 upgrader = new ProjectUpgrader_V7();
-        Injector injector = DIBootstrap.createInjector(testModule);
-        injector.injectMembers(upgrader);
-
-        Resource source = new URLResource(targetsBefore.get(0).toURL());
-        UpgradeHandler handler = upgrader.getUpgradeHandler(source);
-
-        Resource upgraded = handler.performUpgrade();
-        assertNotNull(upgraded);
-        assertNotSame(source, upgrader);
-
-        // check that all the new files are created...
-        String[] targetsAfterNames = new String[] { "cayenne-d1.xml", "cayenne-d2.xml", "d1Map1.map.xml",
-                "d1Map2.map.xml" };
-
-        File[] targetsAfter = new File[targetsAfterNames.length];
-        for (int i = 0; i < targetsAfter.length; i++) {
-            targetsAfter[i] = new File(testFolder, targetsAfterNames[i]);
-            assertTrue("File was not created: " + targetsAfter[i].getAbsolutePath(), targetsAfter[i].exists());
-        }
-
-        // DataMap files should remain the same; all others need to be deleted
-        for (File file : targetsBefore) {
-            if (file.getName().endsWith(".map.xml")) {
-                assertTrue("DataMap file disappeared: " + file.getAbsolutePath(), file.exists());
-            } else {
-                assertFalse("File expected to be deleted: " + file.getAbsolutePath(), file.exists());
-            }
-        }
-
-        // assert XML structure of the generated files
-        assertPerformUpgrade_3_0_0_1_cayenne_d1(targetsAfter[0]);
-        assertPerformUpgrade_3_0_0_1_cayenne_d2(targetsAfter[1]);
-        assertPerformUpgrade_3_0_0_1_d1Map1(targetsAfter[2]);
-        assertPerformUpgrade_3_0_0_1_d1Map2(targetsAfter[3]);
-    }
-
-    private void assertPerformUpgrade_3_0_0_1_cayenne_d1(File file) throws Exception {
-        Document document = toDOMTree(file);
-
-        XPath xpath = XPathFactory.newInstance().newXPath();
-        assertEquals("", xpath.evaluate("/domain/@name", document));
-        assertEquals("7", xpath.evaluate("/domain/@project-version", document));
-
-        NodeList maps = (NodeList) xpath.evaluate("/domain/map", document, XPathConstants.NODESET);
-        assertNotNull(maps);
-        assertEquals(2, maps.getLength());
-
-        Node map1 = maps.item(0);
-        Node map2 = maps.item(1);
-
-        assertEquals("d1Map1", xpath.evaluate("@name", map1));
-        assertEquals("d1Map2", xpath.evaluate("@name", map2));
-
-        NodeList nodes = (NodeList) xpath.evaluate("/domain/node", document, XPathConstants.NODESET);
-        assertNotNull(nodes);
-        assertEquals(1, nodes.getLength());
-
-        Node node1 = nodes.item(0);
-
-        assertEquals("d1NodeDriver", xpath.evaluate("@name", node1));
-        assertEquals(XMLPoolingDataSourceFactory.class.getName(), xpath.evaluate("@factory", node1));
-
-        NodeList mapRefs = (NodeList) xpath.evaluate("map-ref", node1, XPathConstants.NODESET);
-        assertNotNull(mapRefs);
-        assertEquals(2, mapRefs.getLength());
-
-        assertEquals("d1Map1", xpath.evaluate("@name", mapRefs.item(0)));
-        assertEquals("d1Map2", xpath.evaluate("@name", mapRefs.item(1)));
-
-        NodeList dataSources = (NodeList) xpath.evaluate("data-source", node1, XPathConstants.NODESET);
-        assertNotNull(dataSources);
-        assertEquals(1, dataSources.getLength());
-
-        Node ds = dataSources.item(0);
-        assertEquals("org.hsqldb.jdbcDriver", xpath.evaluate("driver/@value", ds));
-        assertEquals("jdbc:hsqldb:mem:xdb", xpath.evaluate("url/@value", ds));
-    }
-
-    private void assertPerformUpgrade_3_0_0_1_cayenne_d2(File file) throws Exception {
-        Document document = toDOMTree(file);
-
-        XPath xpath = XPathFactory.newInstance().newXPath();
-        assertEquals("", xpath.evaluate("/domain/@name", document));
-        assertEquals("7", xpath.evaluate("/domain/@project-version", document));
-
-        NodeList maps = (NodeList) xpath.evaluate("/domain/map", document, XPathConstants.NODESET);
-        assertNotNull(maps);
-        assertEquals(0, maps.getLength());
-
-        NodeList nodes = (NodeList) xpath.evaluate("/domain/node", document, XPathConstants.NODESET);
-        assertNotNull(nodes);
-        assertEquals(2, nodes.getLength());
-
-        Node node1 = nodes.item(0);
-        Node node2 = nodes.item(1);
-
-        assertEquals("d2NodeDBCP", xpath.evaluate("@name", node1));
-        assertEquals("dbcpx", xpath.evaluate("@parameters", node1));
-        assertEquals(DBCPDataSourceFactory.class.getName(), xpath.evaluate("@factory", node1));
-
-        NodeList dataSources1 = (NodeList) xpath.evaluate("data-source", node1, XPathConstants.NODESET);
-        assertNotNull(dataSources1);
-        assertEquals(0, dataSources1.getLength());
-
-        assertEquals("d2NodeJNDI", xpath.evaluate("@name", node2));
-        assertEquals("jndi/x", xpath.evaluate("@parameters", node2));
-        assertEquals(JNDIDataSourceFactory.class.getName(), xpath.evaluate("@factory", node2));
-
-        NodeList dataSources2 = (NodeList) xpath.evaluate("data-source", node2, XPathConstants.NODESET);
-        assertNotNull(dataSources2);
-        assertEquals(0, dataSources2.getLength());
-    }
-
-    private void assertPerformUpgrade_3_0_0_1_d1Map1(File file) throws Exception {
-        Document document = toDOMTree(file);
-
-        XPath xpath = XPathFactory.newInstance().newXPath();
-        assertEquals("7", xpath.evaluate("/data-map/@project-version", document));
-    }
-
-    private void assertPerformUpgrade_3_0_0_1_d1Map2(File file) throws Exception {
-        Document document = toDOMTree(file);
-
-        XPath xpath = XPathFactory.newInstance().newXPath();
-        assertEquals("7", xpath.evaluate("/data-map/@project-version", document));
-    }
-
-    @Test
-    public void testPerformUpgradeFrom6() throws Exception {
-        File testFolder = setupTestDirectory("testUpgrade6a");
-        String sourceUrl = getClass().getPackage().getName().replace('.', '/') + "/6a/";
-        Module testModule = new Module() {
+	@Test
+	public void testMetadata_3_0_0_1() {
+
+		String baseUrl = getClass().getPackage().getName().replace('.', '/');
+		URL url = getClass().getClassLoader().getResource(baseUrl + "/3_0_0_1a/cayenne.xml");
+		assertNotNull(url);
+
+		Module testModule = new Module() {
+
+			public void configure(Binder binder) {
+				binder.bind(ProjectSaver.class).to(FileProjectSaver.class);
+				binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
+			}
+		};
+
+		ProjectUpgrader_V7 upgrader = new ProjectUpgrader_V7();
+		Injector injector = DIBootstrap.createInjector(testModule);
+		injector.injectMembers(upgrader);
+
+		Resource source = new URLResource(url);
+		UpgradeHandler handler = upgrader.getUpgradeHandler(source);
+
+		assertNotNull(handler);
+		assertSame(source, handler.getProjectSource());
+
+		UpgradeMetaData md = handler.getUpgradeMetaData();
+		assertNotNull(md);
+
+		assertSame(UpgradeType.UPGRADE_NEEDED, md.getUpgradeType());
+		// assertEquals("6", md.getIntermediateUpgradeVersion());
+		assertNull(md.getIntermediateUpgradeVersion());
+		assertEquals("3.0.0.1", md.getProjectVersion());
+		assertEquals("7", md.getSupportedVersion());
+	}
+
+	@Test
+	public void testMetadata_Type2_0() {
+		String baseUrl = getClass().getPackage().getName().replace('.', '/');
+		URL url = getClass().getClassLoader().getResource(baseUrl + "/2_0a/cayenne.xml");
+		assertNotNull(url);
+
+		Module testModule = new Module() {
+
+			public void configure(Binder binder) {
+				binder.bind(ProjectSaver.class).to(FileProjectSaver.class);
+				binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
+			}
+		};
+
+		ProjectUpgrader_V7 upgrader = new ProjectUpgrader_V7();
+		Injector injector = DIBootstrap.createInjector(testModule);
+		injector.injectMembers(upgrader);
+
+		Resource source = new URLResource(url);
+		UpgradeHandler handler = upgrader.getUpgradeHandler(source);
+
+		assertNotNull(handler);
+		assertSame(source, handler.getProjectSource());
+
+		UpgradeMetaData md = handler.getUpgradeMetaData();
+		assertNotNull(md);
+		assertSame(UpgradeType.INTERMEDIATE_UPGRADE_NEEDED, md.getUpgradeType());
+		assertEquals("3.0.0.1", md.getIntermediateUpgradeVersion());
+		assertEquals("2.0", md.getProjectVersion());
+		assertEquals("7", md.getSupportedVersion());
+	}
+
+	@Test
+	public void testMetadata_Type6() {
+		String baseUrl = getClass().getPackage().getName().replace('.', '/');
+		URL url = getClass().getClassLoader().getResource(baseUrl + "/6a/cayenne-PROJECT1.xml");
+		assertNotNull(url);
+
+		Module testModule = new Module() {
+
+			public void configure(Binder binder) {
+				binder.bind(ProjectSaver.class).to(FileProjectSaver.class);
+				binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
+			}
+		};
+
+		ProjectUpgrader_V7 upgrader = new ProjectUpgrader_V7();
+		Injector injector = DIBootstrap.createInjector(testModule);
+		injector.injectMembers(upgrader);
+
+		Resource source = new URLResource(url);
+		UpgradeHandler handler = upgrader.getUpgradeHandler(source);
+
+		assertNotNull(handler);
+		assertSame(source, handler.getProjectSource());
+
+		UpgradeMetaData md = handler.getUpgradeMetaData();
+		assertNotNull(md);
+		assertSame(UpgradeType.UPGRADE_NEEDED, md.getUpgradeType());
+		assertNull(md.getIntermediateUpgradeVersion());
+		assertEquals("6", md.getProjectVersion());
+		assertEquals("7", md.getSupportedVersion());
+	}
+
+	@Test
+	public void testMetadata_Type7() {
+		String baseUrl = getClass().getPackage().getName().replace('.', '/');
+		URL url = getClass().getClassLoader().getResource(baseUrl + "/7a/cayenne-PROJECT1.xml");
+		assertNotNull(url);
+
+		Module testModule = new Module() {
+
+			public void configure(Binder binder) {
+				binder.bind(ProjectSaver.class).to(FileProjectSaver.class);
+				binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
+			}
+		};
+
+		ProjectUpgrader_V7 upgrader = new ProjectUpgrader_V7();
+		Injector injector = DIBootstrap.createInjector(testModule);
+		injector.injectMembers(upgrader);
+
+		Resource source = new URLResource(url);
+		UpgradeHandler handler = upgrader.getUpgradeHandler(source);
+
+		assertNotNull(handler);
+		assertSame(source, handler.getProjectSource());
+
+		UpgradeMetaData md = handler.getUpgradeMetaData();
+		assertNotNull(md);
+		assertSame(UpgradeType.UPGRADE_NOT_NEEDED, md.getUpgradeType());
+		assertNull(md.getIntermediateUpgradeVersion());
+		assertEquals("7", md.getProjectVersion());
+		assertEquals("7", md.getSupportedVersion());
+	}
+
+	@Test
+	public void testPerformUpgradeFrom3() throws Exception {
+
+		File testFolder = setupTestDirectory("testPerformUpgrade_3_0_0_1");
+		String sourceUrl = getClass().getPackage().getName().replace('.', '/') + "/3_0_0_1a/";
+
+		List<String> sources = new ArrayList<String>();
+
+		sources.add("cayenne.xml");
+		sources.add("d1Map1.map.xml");
+		sources.add("d1Map2.map.xml");
+		sources.add("d1NodeDriver.driver.xml");
+
+		// upgrades are done in-place, so copy it first
+		List<File> targetsBefore = new ArrayList<File>();
+		for (String source : sources) {
+
+			URL url = getClass().getClassLoader().getResource(sourceUrl + source);
+			File target = new File(testFolder, source);
+			assertNotNull(source);
+			ResourceUtil.copyResourceToFile(url, target);
+			targetsBefore.add(target);
+		}
+
+		Module testModule = new Module() {
+
+			public void configure(Binder binder) {
+				binder.bind(ClassLoaderManager.class).to(DefaultClassLoaderManager.class);
+				binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
+				binder.bind(ProjectSaver.class).to(FileProjectSaver.class);
+				binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
+				binder.bind(DataMapLoader.class).to(XMLDataMapLoader.class);
+			}
+		};
+
+		ProjectUpgrader_V7 upgrader = new ProjectUpgrader_V7();
+		Injector injector = DIBootstrap.createInjector(testModule);
+		injector.injectMembers(upgrader);
+
+		Resource source = new URLResource(targetsBefore.get(0).toURL());
+		UpgradeHandler handler = upgrader.getUpgradeHandler(source);
+
+		Resource upgraded = handler.performUpgrade();
+		assertNotNull(upgraded);
+		assertNotSame(source, upgrader);
+
+		// check that all the new files are created...
+		String[] targetsAfterNames = new String[] { "cayenne-d1.xml", "cayenne-d2.xml", "d1Map1.map.xml",
+				"d1Map2.map.xml" };
+
+		File[] targetsAfter = new File[targetsAfterNames.length];
+		for (int i = 0; i < targetsAfter.length; i++) {
+			targetsAfter[i] = new File(testFolder, targetsAfterNames[i]);
+			assertTrue("File was not created: " + targetsAfter[i].getAbsolutePath(), targetsAfter[i].exists());
+		}
+
+		// DataMap files should remain the same; all others need to be deleted
+		for (File file : targetsBefore) {
+			if (file.getName().endsWith(".map.xml")) {
+				assertTrue("DataMap file disappeared: " + file.getAbsolutePath(), file.exists());
+			} else {
+				assertFalse("File expected to be deleted: " + file.getAbsolutePath(), file.exists());
+			}
+		}
+
+		// assert XML structure of the generated files
+		assertPerformUpgrade_3_0_0_1_cayenne_d1(targetsAfter[0]);
+		assertPerformUpgrade_3_0_0_1_cayenne_d2(targetsAfter[1]);
+		assertPerformUpgrade_3_0_0_1_d1Map1(targetsAfter[2]);
+		assertPerformUpgrade_3_0_0_1_d1Map2(targetsAfter[3]);
+	}
+
+	private void assertPerformUpgrade_3_0_0_1_cayenne_d1(File file) throws Exception {
+		Document document = toDOMTree(file);
+
+		XPath xpath = XPathFactory.newInstance().newXPath();
+		assertEquals("", xpath.evaluate("/domain/@name", document));
+		assertEquals("7", xpath.evaluate("/domain/@project-version", document));
+
+		NodeList maps = (NodeList) xpath.evaluate("/domain/map", document, XPathConstants.NODESET);
+		assertNotNull(maps);
+		assertEquals(2, maps.getLength());
+
+		Node map1 = maps.item(0);
+		Node map2 = maps.item(1);
+
+		assertEquals("d1Map1", xpath.evaluate("@name", map1));
+		assertEquals("d1Map2", xpath.evaluate("@name", map2));
+
+		NodeList nodes = (NodeList) xpath.evaluate("/domain/node", document, XPathConstants.NODESET);
+		assertNotNull(nodes);
+		assertEquals(1, nodes.getLength());
+
+		Node node1 = nodes.item(0);
+
+		assertEquals("d1NodeDriver", xpath.evaluate("@name", node1));
+		assertEquals(XMLPoolingDataSourceFactory.class.getName(), xpath.evaluate("@factory", node1));
+
+		NodeList mapRefs = (NodeList) xpath.evaluate("map-ref", node1, XPathConstants.NODESET);
+		assertNotNull(mapRefs);
+		assertEquals(2, mapRefs.getLength());
+
+		assertEquals("d1Map1", xpath.evaluate("@name", mapRefs.item(0)));
+		assertEquals("d1Map2", xpath.evaluate("@name", mapRefs.item(1)));
+
+		NodeList dataSources = (NodeList) xpath.evaluate("data-source", node1, XPathConstants.NODESET);
+		assertNotNull(dataSources);
+		assertEquals(1, dataSources.getLength());
+
+		Node ds = dataSources.item(0);
+		assertEquals("org.hsqldb.jdbcDriver", xpath.evaluate("driver/@value", ds));
+		assertEquals("jdbc:hsqldb:mem:xdb", xpath.evaluate("url/@value", ds));
+	}
+
+	private void assertPerformUpgrade_3_0_0_1_cayenne_d2(File file) throws Exception {
+		Document document = toDOMTree(file);
+
+		XPath xpath = XPathFactory.newInstance().newXPath();
+		assertEquals("", xpath.evaluate("/domain/@name", document));
+		assertEquals("7", xpath.evaluate("/domain/@project-version", document));
+
+		NodeList maps = (NodeList) xpath.evaluate("/domain/map", document, XPathConstants.NODESET);
+		assertNotNull(maps);
+		assertEquals(0, maps.getLength());
+
+		NodeList nodes = (NodeList) xpath.evaluate("/domain/node", document, XPathConstants.NODESET);
+		assertNotNull(nodes);
+		assertEquals(2, nodes.getLength());
+
+		Node node1 = nodes.item(0);
+		Node node2 = nodes.item(1);
+
+		assertEquals("d2NodeDBCP", xpath.evaluate("@name", node1));
+		assertEquals("dbcpx", xpath.evaluate("@parameters", node1));
+		assertEquals("org.apache.cayenne.configuration.server.DBCPDataSourceFactory", xpath.evaluate("@factory", node1));
+
+		NodeList dataSources1 = (NodeList) xpath.evaluate("data-source", node1, XPathConstants.NODESET);
+		assertNotNull(dataSources1);
+		assertEquals(0, dataSources1.getLength());
+
+		assertEquals("d2NodeJNDI", xpath.evaluate("@name", node2));
+		assertEquals("jndi/x", xpath.evaluate("@parameters", node2));
+		assertEquals(JNDIDataSourceFactory.class.getName(), xpath.evaluate("@factory", node2));
+
+		NodeList dataSources2 = (NodeList) xpath.evaluate("data-source", node2, XPathConstants.NODESET);
+		assertNotNull(dataSources2);
+		assertEquals(0, dataSources2.getLength());
+	}
+
+	private void assertPerformUpgrade_3_0_0_1_d1Map1(File file) throws Exception {
+		Document document = toDOMTree(file);
+
+		XPath xpath = XPathFactory.newInstance().newXPath();
+		assertEquals("7", xpath.evaluate("/data-map/@project-version", document));
+	}
+
+	private void assertPerformUpgrade_3_0_0_1_d1Map2(File file) throws Exception {
+		Document document = toDOMTree(file);
+
+		XPath xpath = XPathFactory.newInstance().newXPath();
+		assertEquals("7", xpath.evaluate("/data-map/@project-version", document));
+	}
+
+	@Test
+	public void testPerformUpgradeFrom6() throws Exception {
+		File testFolder = setupTestDirectory("testUpgrade6a");
+		String sourceUrl = getClass().getPackage().getName().replace('.', '/') + "/6a/";
+		Module testModule = new Module() {
 
-            public void configure(Binder binder) {
-                binder.bind(ClassLoaderManager.class).to(DefaultClassLoaderManager.class);
-                binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
+			public void configure(Binder binder) {
+				binder.bind(ClassLoaderManager.class).to(DefaultClassLoaderManager.class);
+				binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
 
-                binder.bind(ProjectSaver.class).to(FileProjectSaver.class);
-                binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
-                binder.bind(DataMapLoader.class).to(XMLDataMapLoader.class);
-            }
-        };
+				binder.bind(ProjectSaver.class).to(FileProjectSaver.class);
+				binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
+				binder.bind(DataMapLoader.class).to(XMLDataMapLoader.class);
+			}
+		};
 
-        String[] resources = { "cayenne-PROJECT1.xml", "testProjectMap1_1.map.xml", "testProjectMap1_2.map.xml" };
-        List<File> files = new ArrayList<File>();
+		String[] resources = { "cayenne-PROJECT1.xml", "testProjectMap1_1.map.xml", "testProjectMap1_2.map.xml" };
+		List<File> files = new ArrayList<File>();
 
-        for (String name : resources) {
-            URL xmlUrl = getClass().getClassLoader().getResource(sourceUrl + name);
-            File target = new File(testFolder, name);
-            ResourceUtil.copyResourceToFile(xmlUrl, target);
-            files.add(target);
-        }
+		for (String name : resources) {
+			URL xmlUrl = getClass().getClassLoader().getResource(sourceUrl + name);
+			File target = new File(testFolder, name);
+			ResourceUtil.copyResourceToFile(xmlUrl, target);
+			files.add(target);
+		}
 
-        Injector injector = DIBootstrap.createInjector(testModule);
-        ProjectUpgrader_V7 upgrader = new ProjectUpgrader_V7();
-        injector.injectMembers(upgrader);
+		Injector injector = DIBootstrap.createInjector(testModule);
+		ProjectUpgrader_V7 upgrader = new ProjectUpgrader_V7();
+		injector.injectMembers(upgrader);
 
-        Resource source = new URLResource(files.get(0).toURL());
-        assertNotNull(source);
-        UpgradeHandler handler = upgrader.getUpgradeHandler(source);
-        assertNotNull(handler);
+		Resource source = new URLResource(files.get(0).toURL());
+		assertNotNull(source);
+		UpgradeHandler handler = upgrader.getUpgradeHandler(source);
+		assertNotNull(handler);
 
-        Resource upgraded = handler.performUpgrade();
-        assertNotNull(upgraded);
-        assertNotSame(source, upgraded);
+		Resource upgraded = handler.performUpgrade();
+		assertNotNull(upgraded);
+		assertNotSame(source, upgraded);
 
-        assertPerformUpgrade6Cayenne(files.get(0));
-        assertPerformUpgrade6Map1(files.get(1));
-        assertPerformUpgradeMap2(files.get(2));
-    }
-
-    private void assertPerformUpgrade6Map1(File file) throws Exception {
-        Document document = toDOMTree(file);
-
-        XPath xpath = XPathFactory.newInstance().newXPath();
-        assertEquals("7", xpath.evaluate("/data-map/@project-version", document));
-
-        NodeList maps = (NodeList) xpath.evaluate("/data-map/obj-entity/entity-listener", document,
-                XPathConstants.NODESET);
-        assertNotNull(maps);
-        assertEquals(0, maps.getLength());
-    }
-
-    private void assertPerformUpgrade6Cayenne(File file) throws Exception {
-        Document document = toDOMTree(file);
-
-        XPath xpath = XPathFactory.newInstance().newXPath();
-        assertEquals("7", xpath.evaluate("/domain/@project-version", document));
-    }
-
-    private void assertPerformUpgradeMap2(File file) throws Exception {
-        Document document = toDOMTree(file);
-
-        XPath xpath = XPathFactory.newInstance().newXPath();
-        assertEquals("7", xpath.evaluate("/data-map/@project-version", document));
-    }
-
-    @Test
-    public void testObjAttributeDelete() throws Exception {
-
-        File testFolder = setupTestDirectory("testObjAttribute");
-        String sourceUrl = getClass().getPackage().getName().replace('.', '/') + "/6a/delete_shadow_attributes/";
-
-        Module testModule = new Module() {
-
-            public void configure(Binder binder) {
-                binder.bind(ProjectSaver.class).to(FileProjectSaver.class);
-                binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
-                binder.bind(ClassLoaderManager.class).to(DefaultClassLoaderManager.class);
-                binder.bind(DataMapLoader.class).to(XMLDataMapLoader.class);
-                binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
-            }
-        };
-
-        ArrayList<String> source = new ArrayList<String>();
-        source.add("cayenne-TestProject.xml");
-        source.add("testProjectMap1.map.xml");
-        source.add("testProjectMap2.map.xml");
-
-        ArrayList<File> file = new ArrayList<File>();
-
-        for (String name : source) {
-            URL xmlUrl = getClass().getClassLoader().getResource(sourceUrl + name);
-            File target = new File(testFolder, name);
-            ResourceUtil.copyResourceToFile(xmlUrl, target);
-            file.add(target);
-        }
-
-        Injector injector = DIBootstrap.createInjector(testModule);
-        ProjectUpgrader_V7 upgrader = new ProjectUpgrader_V7();
-        injector.injectMembers(upgrader);
-
-        Resource resource = new URLResource(file.get(0).toURL());
-        assertNotNull(resource);
-        UpgradeHandler handler = upgrader.getUpgradeHandler(resource);
-        assertNotNull(handler);
-
-        Resource upgraded = handler.performUpgrade();
-        assertNotNull(upgraded);
-        assertNotSame(resource, upgraded);
-
-        assertPerformUpgrade6Cayenne(file.get(0));
-        assertObjAttributeMap1(file.get(1));
-        assertObjAttributeMap2(file.get(2));
-    }
-
-    private void assertObjAttributeMap1(File file) throws Exception {
-        Document document = toDOMTree(file);
-
-        XPath xpath = XPathFactory.newInstance().newXPath();
-        assertEquals("7", xpath.evaluate("/data-map/@project-version", document));
-
-        String xpathValue = "/data-map/obj-entity[@name='GreatArtist']/obj-attribute";
-        XPathExpression expr = xpath.compile(xpathValue);
-        Node node = (Node) expr.evaluate(document, XPathConstants.NODE);
-
-        assertEquals("attribute2", xpath.evaluate("@name", node));
-    }
-
-    private void assertObjAttributeMap2(File file) throws Exception {
-        Document document = toDOMTree(file);
+		assertPerformUpgrade6Cayenne(files.get(0));
+		assertPerformUpgrade6Map1(files.get(1));
+		assertPerformUpgradeMap2(files.get(2));
+	}
+
+	private void assertPerformUpgrade6Map1(File file) throws Exception {
+		Document document = toDOMTree(file);
+
+		XPath xpath = XPathFactory.newInstance().newXPath();
+		assertEquals("7", xpath.evaluate("/data-map/@project-version", document));
+
+		NodeList maps = (NodeList) xpath.evaluate("/data-map/obj-entity/entity-listener", document,
+				XPathConstants.NODESET);
+		assertNotNull(maps);
+		assertEquals(0, maps.getLength());
+	}
+
+	private void assertPerformUpgrade6Cayenne(File file) throws Exception {
+		Document document = toDOMTree(file);
+
+		XPath xpath = XPathFactory.newInstance().newXPath();
+		assertEquals("7", xpath.evaluate("/domain/@project-version", document));
+	}
+
+	private void assertPerformUpgradeMap2(File file) throws Exception {
+		Document document = toDOMTree(file);
+
+		XPath xpath = XPathFactory.newInstance().newXPath();
+		assertEquals("7", xpath.evaluate("/data-map/@project-version", document));
+	}
+
+	@Test
+	public void testObjAttributeDelete() throws Exception {
+
+		File testFolder = setupTestDirectory("testObjAttribute");
+		String sourceUrl = getClass().getPackage().getName().replace('.', '/') + "/6a/delete_shadow_attributes/";
+
+		Module testModule = new Module() {
+
+			public void configure(Binder binder) {
+				binder.bind(ProjectSaver.class).to(FileProjectSaver.class);
+				binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
+				binder.bind(ClassLoaderManager.class).to(DefaultClassLoaderManager.class);
+				binder.bind(DataMapLoader.class).to(XMLDataMapLoader.class);
+				binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
+			}
+		};
+
+		ArrayList<String> source = new ArrayList<String>();
+		source.add("cayenne-TestProject.xml");
+		source.add("testProjectMap1.map.xml");
+		source.add("testProjectMap2.map.xml");
+
+		ArrayList<File> file = new ArrayList<File>();
+
+		for (String name : source) {
+			URL xmlUrl = getClass().getClassLoader().getResource(sourceUrl + name);
+			File target = new File(testFolder, name);
+			ResourceUtil.copyResourceToFile(xmlUrl, target);
+			file.add(target);
+		}
+
+		Injector injector = DIBootstrap.createInjector(testModule);
+		ProjectUpgrader_V7 upgrader = new ProjectUpgrader_V7();
+		injector.injectMembers(upgrader);
+
+		Resource resource = new URLResource(file.get(0).toURL());
+		assertNotNull(resource);
+		UpgradeHandler handler = upgrader.getUpgradeHandler(resource);
+		assertNotNull(handler);
+
+		Resource upgraded = handler.performUpgrade();
+		assertNotNull(upgraded);
+		assertNotSame(resource, upgraded);
+
+		assertPerformUpgrade6Cayenne(file.get(0));
+		assertObjAttributeMap1(file.get(1));
+		assertObjAttributeMap2(file.get(2));
+	}
+
+	private void assertObjAttributeMap1(File file) throws Exception {
+		Document document = toDOMTree(file);
+
+		XPath xpath = XPathFactory.newInstance().newXPath();
+		assertEquals("7", xpath.evaluate("/data-map/@project-version", document));
+
+		String xpathValue = "/data-map/obj-entity[@name='GreatArtist']/obj-attribute";
+		XPathExpression expr = xpath.compile(xpathValue);
+		Node node = (Node) expr.evaluate(document, XPathConstants.NODE);
+
+		assertEquals("attribute2", xpath.evaluate("@name", node));
+	}
+
+	private void assertObjAttributeMap2(File file) throws Exception {
+		Document document = toDOMTree(file);
 
-        XPath xpath = XPathFactory.newInstance().newXPath();
-        assertEquals("7", xpath.evaluate("/data-map/@project-version", document));
+		XPath xpath = XPathFactory.newInstance().newXPath();
+		assertEquals("7", xpath.evaluate("/data-map/@project-version", document));
 
-        String xpath_1 = "/data-map/obj-entity[@name='House']/obj-attribute/@name";
-        String xpath_2 = "/data-map/obj-entity[@name='Penthouse']/obj-attribute/@name";
-        XPathExpression expr = xpath.compile(xpath_1);
-        String houseAttr = (String) expr.evaluate(document, XPathConstants.STRING);
-        expr = xpath.compile(xpath_2);
-        String penthouseAttr = (String) expr.evaluate(document, XPathConstants.STRING);
-
-        assertEquals("attribute2", houseAttr);
-        assertEquals("attribute3", penthouseAttr);
-    }
+		String xpath_1 = "/data-map/obj-entity[@name='House']/obj-attribute/@name";
+		String xpath_2 = "/data-map/obj-entity[@name='Penthouse']/obj-attribute/@name";
+		XPathExpression expr = xpath.compile(xpath_1);
+		String houseAttr = (String) expr.evaluate(document, XPathConstants.STRING);
+		expr = xpath.compile(xpath_2);
+		String penthouseAttr = (String) expr.evaluate(document, XPathConstants.STRING);
+
+		assertEquals("attribute2", houseAttr);
+		assertEquals("attribute3", penthouseAttr);
+	}
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/84a83fe1/cayenne-server/pom.xml
----------------------------------------------------------------------
diff --git a/cayenne-server/pom.xml b/cayenne-server/pom.xml
index d00cd8c..311f8f3 100644
--- a/cayenne-server/pom.xml
+++ b/cayenne-server/pom.xml
@@ -92,18 +92,6 @@
 			<optional>true</optional>
 		</dependency>
 		<dependency>
-			<groupId>commons-dbcp</groupId>
-			<artifactId>commons-dbcp</artifactId>
-			<scope>provided</scope>
-			<optional>true</optional>
-		</dependency>
-		<dependency>
-			<groupId>commons-pool</groupId>
-			<artifactId>commons-pool</artifactId>
-			<scope>provided</scope>
-			<optional>true</optional>
-		</dependency>
-		<dependency>
 			<groupId>org.apache.geronimo.specs</groupId>
 			<artifactId>geronimo-jms_1.1_spec</artifactId>
 			<scope>provided</scope>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/84a83fe1/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DBCPDataSourceFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DBCPDataSourceFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DBCPDataSourceFactory.java
deleted file mode 100644
index 8224856..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DBCPDataSourceFactory.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-package org.apache.cayenne.configuration.server;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-import java.util.Map.Entry;
-
-import javax.sql.DataSource;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.configuration.DataNodeDescriptor;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.resource.Resource;
-import org.apache.cayenne.resource.ResourceLocator;
-import org.apache.commons.dbcp.BasicDataSourceFactory;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * A {@link DataSourceFactory} based on DBCP connection pool library.
- * 
- * @since 3.1
- */
-public class DBCPDataSourceFactory implements DataSourceFactory {
-
-    private static final String DBCP_PROPERTIES = "dbcp.properties";
-
-    private static final Log logger = LogFactory.getLog(DBCPDataSourceFactory.class);
-
-    @Inject
-    protected ResourceLocator resourceLocator;
-
-    @Override
-    public DataSource getDataSource(DataNodeDescriptor nodeDescriptor) throws Exception {
-
-        String location = nodeDescriptor.getParameters();
-        if (location == null) {
-            logger.debug("No explicit DBCP config location, will use default location: "
-                    + DBCP_PROPERTIES);
-            location = DBCP_PROPERTIES;
-        }
-
-        Resource baseConfiguration = nodeDescriptor.getConfigurationSource();
-        if (baseConfiguration == null) {
-            throw new CayenneRuntimeException(
-                    "Null 'configurationSource' for nodeDescriptor '%s'",
-                    nodeDescriptor.getName());
-        }
-
-        Resource dbcpConfiguration = baseConfiguration.getRelativeResource(location);
-        if (dbcpConfiguration == null) {
-            throw new CayenneRuntimeException(
-                    "Missing DBCP configuration '%s' for nodeDescriptor '%s'",
-                    location,
-                    nodeDescriptor.getName());
-        }
-
-        Properties properties = getProperties(dbcpConfiguration);
-        if (logger.isDebugEnabled()) {
-            logger.debug("DBCP Properties: " + properties);
-        }
-
-        properties = filteredDeprecatedProperties(properties);
-        return BasicDataSourceFactory.createDataSource(properties);
-    }
-
-    /**
-     * Converts old-style cayene.dbcp.xyz properties to just cayenne.dbcp.
-     */
-    private Properties filteredDeprecatedProperties(Properties unfiltered) {
-        Properties properties = new Properties();
-
-        final String deprecatedPrefix = "cayenne.dbcp.";
-
-        for (Entry<Object, Object> entry : unfiltered.entrySet()) {
-            Object key = entry.getKey();
-            if (key instanceof String && key.toString().startsWith(deprecatedPrefix)) {
-
-                String oldKey = key.toString();
-                key = oldKey.substring(deprecatedPrefix.length());
-                logger.info("Deprecated use of 'cayenne.dbcp.' prefix in '"
-                        + oldKey
-                        + "', converting to "
-                        + key);
-            }
-
-            properties.put(key, entry.getValue());
-        }
-
-        return properties;
-    }
-
-    private Properties getProperties(Resource dbcpConfiguration) throws IOException {
-        Properties properties = new Properties();
-        InputStream in = dbcpConfiguration.getURL().openStream();
-        try {
-            properties.load(in);
-        }
-        finally {
-            try {
-                in.close();
-            }
-            catch (IOException e) {
-            }
-        }
-
-        return properties;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/84a83fe1/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DBCPDataSourceFactoryTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DBCPDataSourceFactoryTest.java b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DBCPDataSourceFactoryTest.java
deleted file mode 100644
index 0ed02b5..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DBCPDataSourceFactoryTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-package org.apache.cayenne.configuration.server;
-
-import org.apache.cayenne.configuration.DataNodeDescriptor;
-import org.apache.cayenne.resource.URLResource;
-import org.apache.commons.dbcp.BasicDataSource;
-import org.junit.Test;
-
-import javax.sql.DataSource;
-import java.io.IOException;
-import java.net.URL;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-public class DBCPDataSourceFactoryTest {
-
-    @Test
-    public void testGetDataSource() throws Exception {
-
-        String baseUrl = getClass().getPackage().getName().replace('.', '/');
-        URL url = getClass().getClassLoader().getResource(baseUrl + "/");
-        assertNotNull(url);
-
-        DataNodeDescriptor nodeDescriptor = new DataNodeDescriptor();
-        nodeDescriptor.setConfigurationSource(new URLResource(url));
-        nodeDescriptor.setParameters("testDBCP.properties");
-
-        DBCPDataSourceFactory factory = new DBCPDataSourceFactory();
-        DataSource dataSource = factory.getDataSource(nodeDescriptor);
-        assertNotNull(dataSource);
-
-        assertTrue(dataSource instanceof BasicDataSource);
-        BasicDataSource basicDataSource = (BasicDataSource) dataSource;
-        assertEquals("com.example.jdbc.Driver", basicDataSource.getDriverClassName());
-        assertEquals("jdbc:somedb://localhost/cayenne", basicDataSource.getUrl());
-        assertEquals("john", basicDataSource.getUsername());
-        assertEquals("secret", basicDataSource.getPassword());
-        assertEquals(20, basicDataSource.getMaxActive());
-        assertEquals(5, basicDataSource.getMinIdle());
-        assertEquals(8, basicDataSource.getMaxIdle());
-        assertEquals(10000, basicDataSource.getMaxWait());
-        assertEquals("select 1 from xyz;", basicDataSource.getValidationQuery());
-    }
-
-    @Test
-    public void testGetDataSource_LegacyConfig() throws Exception {
-
-        String baseUrl = getClass().getPackage().getName().replace('.', '/');
-        URL url = getClass().getClassLoader().getResource(baseUrl + "/");
-        assertNotNull(url);
-
-        DataNodeDescriptor nodeDescriptor = new DataNodeDescriptor();
-        nodeDescriptor.setConfigurationSource(new URLResource(url));
-        nodeDescriptor.setParameters("testDBCP_legacy.properties");
-
-        DBCPDataSourceFactory factory = new DBCPDataSourceFactory();
-        DataSource dataSource = factory.getDataSource(nodeDescriptor);
-        assertNotNull(dataSource);
-
-        assertTrue(dataSource instanceof BasicDataSource);
-        BasicDataSource basicDataSource = (BasicDataSource) dataSource;
-        assertEquals("com.example.jdbc.Driver", basicDataSource.getDriverClassName());
-        assertEquals("jdbc:somedb://localhost/cayenne", basicDataSource.getUrl());
-        assertEquals("john", basicDataSource.getUsername());
-        assertEquals("secret", basicDataSource.getPassword());
-        assertEquals(20, basicDataSource.getMaxActive());
-        assertEquals(5, basicDataSource.getMinIdle());
-        assertEquals(8, basicDataSource.getMaxIdle());
-        assertEquals(10000, basicDataSource.getMaxWait());
-        assertEquals("select 1 from xyz;", basicDataSource.getValidationQuery());
-    }
-
-    @Test
-    public void testGetDataSource_InvalidLocation() throws Exception {
-
-        String baseUrl = getClass().getPackage().getName().replace('.', '/');
-        URL url = getClass().getClassLoader().getResource(baseUrl + "/");
-        assertNotNull(url);
-
-        DataNodeDescriptor nodeDescriptor = new DataNodeDescriptor();
-        nodeDescriptor.setConfigurationSource(new URLResource(url));
-        nodeDescriptor.setParameters("testDBCP.properties.nosuchfile");
-
-        DBCPDataSourceFactory factory = new DBCPDataSourceFactory();
-
-        try {
-            factory.getDataSource(nodeDescriptor);
-            fail("didn't throw on abscent config file");
-        }
-        catch (IOException ex) {
-            // expected
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/84a83fe1/cayenne-tools/pom.xml
----------------------------------------------------------------------
diff --git a/cayenne-tools/pom.xml b/cayenne-tools/pom.xml
index dc133a8..a759107 100644
--- a/cayenne-tools/pom.xml
+++ b/cayenne-tools/pom.xml
@@ -78,18 +78,6 @@
 		</dependency>
 
 		<dependency>
-			<groupId>commons-dbcp</groupId>
-			<artifactId>commons-dbcp</artifactId>
-			<scope>compile</scope>
-		</dependency>
-
-		<dependency>
-			<groupId>commons-pool</groupId>
-			<artifactId>commons-pool</artifactId>
-			<scope>compile</scope>
-		</dependency>
-
-		<dependency>
 			<groupId>org.apache.velocity</groupId>
 			<artifactId>velocity</artifactId>
 		</dependency>		

http://git-wip-us.apache.org/repos/asf/cayenne/blob/84a83fe1/docs/doc/pom.xml
----------------------------------------------------------------------
diff --git a/docs/doc/pom.xml b/docs/doc/pom.xml
index c5619ec..4039cd4 100644
--- a/docs/doc/pom.xml
+++ b/docs/doc/pom.xml
@@ -68,18 +68,6 @@
 		</dependency>
 
 		<dependency>
-			<groupId>commons-dbcp</groupId>
-			<artifactId>commons-dbcp</artifactId>
-			<scope>compile</scope>
-		</dependency>
-
-		<dependency>
-			<groupId>commons-pool</groupId>
-			<artifactId>commons-pool</artifactId>
-			<scope>compile</scope>
-		</dependency>
-
-		<dependency>
 			<groupId>foundrylogic.vpp</groupId>
 			<artifactId>vpp</artifactId>
 		</dependency>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/84a83fe1/docs/doc/src/main/resources/UPGRADE.txt
----------------------------------------------------------------------
diff --git a/docs/doc/src/main/resources/UPGRADE.txt b/docs/doc/src/main/resources/UPGRADE.txt
index ea6f088..5e30bce 100644
--- a/docs/doc/src/main/resources/UPGRADE.txt
+++ b/docs/doc/src/main/resources/UPGRADE.txt
@@ -6,6 +6,9 @@ IMPORTANT: be sure to read all notes for the intermediate releases between your
 -------------------------------------------------------------------------------
 UPGRADING TO 4.0.M3
 
+* Per CAY-2026 minimal Java version is now 1.7. If you are still need Java 1.6, you can use Cayenne 3.1 or 4.0.M2 until your
+  application is able to upgrade. 
+
 * We no longer add @Deprecated annotation to generated String property names in entity superclasses.
   Instead String property names inclusion
   became optional, controlled with "createPropertyNames" flag in cgen ("false" by default). Also a similar option
@@ -21,8 +24,20 @@ UPGRADING TO 4.0.M3
   'orderBy' that would previously reset the corresponding option state now work as "append". Methods that would previously append to the
   option state were removed as redundant. Please revisit your code if you previously relied on the reset behavior.
 
-* Per CAY-2025 DBCP2DataSourceFactory does not support deprecated properties. So if you want to upgrade from commons-dbcp to commons-dbcp2,
-  you should replace all old-style properties with the newer ones.
+* If you are using DBCPDataSourceFactory, you will need to take a few steps to upgrade:
+
+  - Per CAY-2025 and CAY-2026, DBCPDataSourceFactory is now based on DBCP2 (which is required under Java 1.7 and newer).
+  - Check your DBCP properties file to ensure it uses property names supported by DBCP. 
+    (In the past Cayenne would require prefixing those properties with 'cayenne.dbcp.'. If you still have that prefix, remove it).
+  - To use DBCPDataSourceFactory, you will now have to explicitly include an extra Cayenne module, as it is no longer in cayenne-server. 
+    E.g. if you are using Maven:
+
+    <parent>
+      <groupId>org.apache.cayenne</groupId>
+      <artifactId>cayenne-dbcp2</artifactId>
+      <version>4.0.M3</version>
+    </parent>
+ 
 
 UPGRADING TO 4.0.M2
 


Mime
View raw message