This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit 1f90bd9711524559755f343314d4a3fd3362ea7c
Author: Andrus Adamchik <[email protected]>
AuthorDate: Tue Jul 21 11:42:13 2026 +0200

    CAY-2982 Modeler: when upgrading projects allow upgraders to send outcome 
messages
---
 RELEASE-NOTES.txt                                  |   1 +
 ...vice.java => CompatibilityProjectUpgrader.java} |  19 ++--
 .../compatibility/ProjectCompatibilityModule.java  |   4 +-
 .../CompatibilityDataChannelDescriptorLoader.java  |  22 ++--
 .../configuration/CompatibilityDataMapLoader.java  |  10 +-
 .../compatibility/CompatibilityTestModule.java     |   4 +-
 .../CompatibilityUpgradeServiceIT.java             |  12 +--
 .../org/apache/cayenne/project/ProjectModule.java  |   6 +-
 ...adeService.java => DefaultProjectUpgrader.java} | 118 ++++++++++++---------
 .../{UpgradeUnit.java => PostUpgradeState.java}    |  36 ++-----
 .../{UpgradeService.java => PreUpgradeState.java}  |  18 ++--
 .../{UpgradeService.java => ProjectUpgrader.java}  |   8 +-
 .../{UpgradeUnit.java => UpgradeContext.java}      |  32 ++++--
 .../cayenne/project/upgrade/UpgradeMetaData.java   |  66 ------------
 .../project/upgrade/handlers/UpgradeHandler.java   |  16 +--
 .../upgrade/handlers/UpgradeHandler_V10.java       |   6 +-
 .../upgrade/handlers/UpgradeHandler_V11.java       |  26 ++---
 .../upgrade/handlers/UpgradeHandler_V12.java       |  13 +--
 .../upgrade/handlers/UpgradeHandler_V7.java        |  18 ++--
 .../upgrade/handlers/UpgradeHandler_V8.java        |   6 +-
 .../upgrade/handlers/UpgradeHandler_V9.java        |   6 +-
 ...ceTest.java => DefaultProjectUpgraderTest.java} |  26 ++---
 .../upgrade/handlers/BaseUpgradeHandlerTest.java   |   7 +-
 .../upgrade/handlers/UpgradeHandler_V12Test.java   |  16 +--
 .../org/apache/cayenne/modeler/Application.java    |   6 +-
 .../modeler/ui/action/OpenProjectAction.java       |  32 ++++--
 26 files changed, 250 insertions(+), 284 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index dfdb33ca7..0361549fa 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -28,6 +28,7 @@ CAY-2975 Mnemonic table aliases in generated SQL
 CAY-2978 AI skill: "cayenne-model-naming"
 CAY-2979 AI skill: "cayenne-full-db-sync"
 CAY-2980 Improve model name generation
+CAY-2982 Modeler: when upgrading projects allow upgraders to send outcome 
messages
 
 Bug Fixes:
 
diff --git 
a/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/CompatibilityUpgradeService.java
 
b/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/CompatibilityProjectUpgrader.java
similarity index 77%
rename from 
cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/CompatibilityUpgradeService.java
rename to 
cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/CompatibilityProjectUpgrader.java
index d1ccb4ad7..0e5bc1781 100644
--- 
a/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/CompatibilityUpgradeService.java
+++ 
b/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/CompatibilityProjectUpgrader.java
@@ -21,8 +21,9 @@ package org.apache.cayenne.project.compatibility;
 
 import org.apache.cayenne.configuration.DataChannelDescriptor;
 import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.project.upgrade.DefaultUpgradeService;
-import org.apache.cayenne.project.upgrade.UpgradeUnit;
+import org.apache.cayenne.project.upgrade.DefaultProjectUpgrader;
+import org.apache.cayenne.project.upgrade.PostUpgradeState;
+import org.apache.cayenne.project.upgrade.UpgradeContext;
 import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler;
 import org.apache.cayenne.resource.Resource;
 import org.w3c.dom.Document;
@@ -32,31 +33,31 @@ import java.util.List;
 /**
  * @since 4.1
  */
-public class CompatibilityUpgradeService extends DefaultUpgradeService {
+public class CompatibilityProjectUpgrader extends DefaultProjectUpgrader {
 
     @Inject
     DocumentProvider documentProvider;
 
-    public CompatibilityUpgradeService(@Inject List<UpgradeHandler> 
handlerList) {
+    public CompatibilityProjectUpgrader(@Inject List<UpgradeHandler> 
handlerList) {
         super(handlerList);
     }
 
     @Override
-    public Resource upgradeProject(Resource resource) {
+    public PostUpgradeState upgrade(Resource resource) {
         List<UpgradeHandler> handlerList = 
getHandlersForVersion(loadProjectVersion(resource));
-        List<UpgradeUnit> upgradeUnits = upgradeDOM(resource, handlerList);
+        List<UpgradeContext> upgradeUnits = upgradeDOM(resource, handlerList);
 
-        for(UpgradeUnit unit : upgradeUnits) {
+        for(UpgradeContext unit : upgradeUnits) {
             documentProvider.putDocument(unit.getResource().getURL(), 
unit.getDocument());
         }
 
-        return resource;
+        return new PostUpgradeState(resource, 
collectPostUpgradeMessages(upgradeUnits));
     }
 
     public Resource upgradeDataMap(Resource resource) {
         List<UpgradeHandler> handlerList = 
getHandlersForVersion(loadProjectVersion(resource));
         Document document =  readDocument(resource.getURL());
-        UpgradeUnit upgradeUnit = new UpgradeUnit(resource, document);
+        UpgradeContext upgradeUnit = new UpgradeContext(resource, document);
         for(UpgradeHandler handler : handlerList) {
             handler.processDataMapDom(upgradeUnit);
         }
diff --git 
a/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/ProjectCompatibilityModule.java
 
b/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/ProjectCompatibilityModule.java
index 582b7abfa..637418d36 100644
--- 
a/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/ProjectCompatibilityModule.java
+++ 
b/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/ProjectCompatibilityModule.java
@@ -26,7 +26,7 @@ import 
org.apache.cayenne.project.compatibility.configuration.CompatibilityDataM
 import org.apache.cayenne.di.Binder;
 import org.apache.cayenne.di.Module;
 import org.apache.cayenne.project.ProjectModule;
-import org.apache.cayenne.project.upgrade.UpgradeService;
+import org.apache.cayenne.project.upgrade.ProjectUpgrader;
 import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler_V10;
 import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler_V11;
 import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler_V12;
@@ -44,7 +44,7 @@ public class ProjectCompatibilityModule implements Module {
         
binder.bind(DataChannelDescriptorLoader.class).to(CompatibilityDataChannelDescriptorLoader.class);
         binder.bind(DataMapLoader.class).to(CompatibilityDataMapLoader.class);
 
-        
binder.bind(UpgradeService.class).to(CompatibilityUpgradeService.class);
+        
binder.bind(ProjectUpgrader.class).to(CompatibilityProjectUpgrader.class);
         binder.bind(DocumentProvider.class).to(DefaultDocumentProvider.class);
 
         ProjectModule.extend(binder)
diff --git 
a/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/configuration/CompatibilityDataChannelDescriptorLoader.java
 
b/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/configuration/CompatibilityDataChannelDescriptorLoader.java
index 85b48a79b..5dd1feffe 100644
--- 
a/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/configuration/CompatibilityDataChannelDescriptorLoader.java
+++ 
b/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/configuration/CompatibilityDataChannelDescriptorLoader.java
@@ -35,10 +35,10 @@ import org.apache.cayenne.configuration.xml.LoaderContext;
 import org.apache.cayenne.configuration.xml.XMLDataChannelDescriptorLoader;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.di.Provider;
-import org.apache.cayenne.project.compatibility.CompatibilityUpgradeService;
+import org.apache.cayenne.project.compatibility.CompatibilityProjectUpgrader;
 import org.apache.cayenne.project.compatibility.DocumentProvider;
-import org.apache.cayenne.project.upgrade.UpgradeMetaData;
-import org.apache.cayenne.project.upgrade.UpgradeService;
+import org.apache.cayenne.project.upgrade.PreUpgradeState;
+import org.apache.cayenne.project.upgrade.ProjectUpgrader;
 import org.apache.cayenne.project.upgrade.UpgradeType;
 import org.apache.cayenne.resource.Resource;
 import org.apache.cayenne.util.Util;
@@ -57,7 +57,7 @@ public class CompatibilityDataChannelDescriptorLoader extends 
XMLDataChannelDesc
     private static final Logger LOGGER = 
LoggerFactory.getLogger(XMLDataChannelDescriptorLoader.class);
 
     @Inject
-    Provider<UpgradeService> upgradeServiceProvider;
+    Provider<ProjectUpgrader> upgradeServiceProvider;
 
     @Inject
     DocumentProvider documentProvider;
@@ -68,30 +68,30 @@ public class CompatibilityDataChannelDescriptorLoader 
extends XMLDataChannelDesc
             throw new NullPointerException("Null configurationResource");
         }
 
-        if(!(upgradeServiceProvider.get() instanceof 
CompatibilityUpgradeService)) {
+        if(!(upgradeServiceProvider.get() instanceof 
CompatibilityProjectUpgrader)) {
             throw new ConfigurationException("CompatibilityUpgradeService 
expected");
         }
 
-        CompatibilityUpgradeService upgradeService = 
(CompatibilityUpgradeService)upgradeServiceProvider.get();
+        CompatibilityProjectUpgrader upgradeService = 
(CompatibilityProjectUpgrader)upgradeServiceProvider.get();
 
-        UpgradeMetaData metaData = 
upgradeService.getUpgradeType(configurationResource);
-        if(metaData.getUpgradeType() == UpgradeType.UPGRADE_NOT_NEEDED) {
+        PreUpgradeState metaData = 
upgradeService.checkUpgradeNeeded(configurationResource);
+        if(metaData.requiredUpgrade() == UpgradeType.UPGRADE_NOT_NEEDED) {
             return super.load(configurationResource);
         }
 
-        if(metaData.getUpgradeType() == UpgradeType.DOWNGRADE_NEEDED) {
+        if(metaData.requiredUpgrade() == UpgradeType.DOWNGRADE_NEEDED) {
             throw new ConfigurationException("Unable to load configuration 
from %s: " +
                     "It was created using a newer version of the Modeler", 
configurationResource.getURL());
         }
 
-        if(metaData.getUpgradeType() == 
UpgradeType.INTERMEDIATE_UPGRADE_NEEDED) {
+        if(metaData.requiredUpgrade() == 
UpgradeType.INTERMEDIATE_UPGRADE_NEEDED) {
             throw new ConfigurationException("Unable to load configuration 
from %s: " +
                     "Open the project in the older Modeler to do an 
intermediate upgrade.", configurationResource.getURL());
         }
 
         URL configurationURL = configurationResource.getURL();
 
-        upgradeService.upgradeProject(configurationResource);
+        upgradeService.upgrade(configurationResource);
         Document projectDocument = 
documentProvider.getDocument(configurationURL);
         if(projectDocument == null) {
             throw new ConfigurationException("Unable to upgrade " + 
configurationURL);
diff --git 
a/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/configuration/CompatibilityDataMapLoader.java
 
b/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/configuration/CompatibilityDataMapLoader.java
index e7ccf5732..d2a736451 100644
--- 
a/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/configuration/CompatibilityDataMapLoader.java
+++ 
b/cayenne-project-compatibility/src/main/java/org/apache/cayenne/project/compatibility/configuration/CompatibilityDataMapLoader.java
@@ -34,9 +34,9 @@ import org.apache.cayenne.configuration.xml.XMLDataMapLoader;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.di.Provider;
 import org.apache.cayenne.map.DataMap;
-import org.apache.cayenne.project.compatibility.CompatibilityUpgradeService;
+import org.apache.cayenne.project.compatibility.CompatibilityProjectUpgrader;
 import org.apache.cayenne.project.compatibility.DocumentProvider;
-import org.apache.cayenne.project.upgrade.UpgradeService;
+import org.apache.cayenne.project.upgrade.ProjectUpgrader;
 import org.apache.cayenne.resource.Resource;
 import org.apache.cayenne.util.Util;
 import org.w3c.dom.Document;
@@ -49,7 +49,7 @@ import org.xml.sax.XMLReader;
 public class CompatibilityDataMapLoader extends XMLDataMapLoader {
 
     @Inject
-    Provider<UpgradeService> upgradeServiceProvider;
+    Provider<ProjectUpgrader> upgradeServiceProvider;
 
     @Inject
     DocumentProvider documentProvider;
@@ -59,11 +59,11 @@ public class CompatibilityDataMapLoader extends 
XMLDataMapLoader {
         Document document = 
documentProvider.getDocument(configurationResource.getURL());
         // no document yet in provider, maybe DataMap is directly loaded
         if(document == null) {
-            if(!(upgradeServiceProvider.get() instanceof 
CompatibilityUpgradeService)) {
+            if(!(upgradeServiceProvider.get() instanceof 
CompatibilityProjectUpgrader)) {
                 throw new ConfigurationException("CompatibilityUpgradeService 
expected");
             }
             // try to upgrade datamap directly
-            CompatibilityUpgradeService upgradeService = 
(CompatibilityUpgradeService)upgradeServiceProvider.get();
+            CompatibilityProjectUpgrader upgradeService = 
(CompatibilityProjectUpgrader)upgradeServiceProvider.get();
             upgradeService.upgradeDataMap(configurationResource);
             document = 
documentProvider.getDocument(configurationResource.getURL());
 
diff --git 
a/cayenne-project-compatibility/src/test/java/org/apache/cayenne/project/compatibility/CompatibilityTestModule.java
 
b/cayenne-project-compatibility/src/test/java/org/apache/cayenne/project/compatibility/CompatibilityTestModule.java
index a2b8cbf78..0836d57bd 100644
--- 
a/cayenne-project-compatibility/src/test/java/org/apache/cayenne/project/compatibility/CompatibilityTestModule.java
+++ 
b/cayenne-project-compatibility/src/test/java/org/apache/cayenne/project/compatibility/CompatibilityTestModule.java
@@ -31,7 +31,7 @@ import org.apache.cayenne.di.Module;
 import org.apache.cayenne.di.spi.DefaultAdhocObjectFactory;
 import org.apache.cayenne.di.spi.DefaultClassLoaderManager;
 import org.apache.cayenne.project.ProjectSaver;
-import org.apache.cayenne.project.upgrade.UpgradeService;
+import org.apache.cayenne.project.upgrade.ProjectUpgrader;
 import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler;
 import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler_V10;
 import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler_V11;
@@ -46,7 +46,7 @@ public class CompatibilityTestModule implements Module {
 
     @Override
     public void configure(Binder binder) {
-        
binder.bind(UpgradeService.class).to(CompatibilityUpgradeService.class);
+        
binder.bind(ProjectUpgrader.class).to(CompatibilityProjectUpgrader.class);
         binder.bind(DocumentProvider.class).to(DefaultDocumentProvider.class);
 
         binder.bind(HandlerFactory.class).to(DefaultHandlerFactory.class);
diff --git 
a/cayenne-project-compatibility/src/test/java/org/apache/cayenne/project/compatibility/CompatibilityUpgradeServiceIT.java
 
b/cayenne-project-compatibility/src/test/java/org/apache/cayenne/project/compatibility/CompatibilityUpgradeServiceIT.java
index d62ed1634..553407870 100644
--- 
a/cayenne-project-compatibility/src/test/java/org/apache/cayenne/project/compatibility/CompatibilityUpgradeServiceIT.java
+++ 
b/cayenne-project-compatibility/src/test/java/org/apache/cayenne/project/compatibility/CompatibilityUpgradeServiceIT.java
@@ -23,7 +23,7 @@ import java.net.URL;
 
 import org.apache.cayenne.di.DIBootstrap;
 import org.apache.cayenne.di.Injector;
-import org.apache.cayenne.project.upgrade.UpgradeService;
+import org.apache.cayenne.project.upgrade.ProjectUpgrader;
 import org.apache.cayenne.resource.Resource;
 import org.apache.cayenne.resource.URLResource;
 import org.junit.jupiter.api.Test;
@@ -37,14 +37,14 @@ public class CompatibilityUpgradeServiceIT {
     public void upgradeFullProjectDom() {
         Injector injector = getInjector();
 
-        CompatibilityUpgradeService upgradeService = 
(CompatibilityUpgradeService)injector
-                .getInstance(UpgradeService.class);
+        CompatibilityProjectUpgrader upgradeService = 
(CompatibilityProjectUpgrader)injector
+                .getInstance(ProjectUpgrader.class);
 
         DocumentProvider documentProvider = 
injector.getInstance(DocumentProvider.class);
 
         URL resourceUrl = getClass().getResource("cayenne-project-v6.xml");
         Resource resource = new URLResource(resourceUrl);
-        upgradeService.upgradeProject(resource);
+        upgradeService.upgrade(resource);
 
         Document domainDocument = documentProvider.getDocument(resourceUrl);
 
@@ -64,8 +64,8 @@ public class CompatibilityUpgradeServiceIT {
     public void upgradeStandAloneDataMapDom() {
         Injector injector = getInjector();
 
-        CompatibilityUpgradeService upgradeService = 
(CompatibilityUpgradeService)injector
-                .getInstance(UpgradeService.class);
+        CompatibilityProjectUpgrader upgradeService = 
(CompatibilityProjectUpgrader)injector
+                .getInstance(ProjectUpgrader.class);
 
         DocumentProvider documentProvider = 
injector.getInstance(DocumentProvider.class);
 
diff --git 
a/cayenne-project/src/main/java/org/apache/cayenne/project/ProjectModule.java 
b/cayenne-project/src/main/java/org/apache/cayenne/project/ProjectModule.java
index 97a5afb8e..0eb00a0cf 100644
--- 
a/cayenne-project/src/main/java/org/apache/cayenne/project/ProjectModule.java
+++ 
b/cayenne-project/src/main/java/org/apache/cayenne/project/ProjectModule.java
@@ -24,8 +24,8 @@ import org.apache.cayenne.di.Binder;
 import org.apache.cayenne.di.ListBuilder;
 import org.apache.cayenne.di.Module;
 import org.apache.cayenne.project.extension.ProjectExtension;
-import org.apache.cayenne.project.upgrade.DefaultUpgradeService;
-import org.apache.cayenne.project.upgrade.UpgradeService;
+import org.apache.cayenne.project.upgrade.DefaultProjectUpgrader;
+import org.apache.cayenne.project.upgrade.ProjectUpgrader;
 import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler;
 import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler_V10;
 import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler_V11;
@@ -76,7 +76,7 @@ public class ProjectModule implements Module {
         
binder.bind(ConfigurationNodeParentGetter.class).to(DefaultConfigurationNodeParentGetter.class);
         
binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
 
-        binder.bind(UpgradeService.class).to(DefaultUpgradeService.class);
+        binder.bind(ProjectUpgrader.class).to(DefaultProjectUpgrader.class);
 
         extend(binder)
                 .initAllExtensions()
diff --git 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DefaultUpgradeService.java
 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DefaultProjectUpgrader.java
similarity index 76%
rename from 
cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DefaultUpgradeService.java
rename to 
cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DefaultProjectUpgrader.java
index ecaa22571..5559f117c 100644
--- 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DefaultUpgradeService.java
+++ 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DefaultProjectUpgrader.java
@@ -60,8 +60,10 @@ import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Comparator;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.TreeMap;
 
 import static org.apache.cayenne.util.Util.isBlank;
@@ -70,27 +72,27 @@ import static org.apache.cayenne.util.Util.isBlank;
  *
  * Upgrade service sequence is following:
  * 1. This cycle should be done by Modeler and will result in a full project 
upgrade
- *
- *  - find all project and datamap resources
- *  - define set of upgrade handlers to process those resources
- *  - process DOM (project + N data maps)
- *  - save & load cycle to flush all DOM changes
- *  - process project model
- *  - save once again to cleanup and sort final XML
- *
+ * <p>
+ * - find all project and datamap resources
+ * - define set of upgrade handlers to process those resources
+ * - process DOM (project + N data maps)
+ * - save & load cycle to flush all DOM changes
+ * - process project model
+ * - save once again to cleanup and sort final XML
+ * <p>
  * 2. This cycle can be used by CayenneRuntime to optionally support old 
project versions
- *
- *  - find all project and datamap resources
- *  - define set of upgrade handlers to process those resources
- *  - process DOM (project + N data maps)
- *  - directly load model from DOM w/o saving
- *  - process project model
+ * <p>
+ * - find all project and datamap resources
+ * - define set of upgrade handlers to process those resources
+ * - process DOM (project + N data maps)
+ * - directly load model from DOM w/o saving
+ * - process project model
  *
  * @since 4.1
  */
-public class DefaultUpgradeService implements UpgradeService {
+public class DefaultProjectUpgrader implements ProjectUpgrader {
 
-    private static final Logger LOGGER = 
LoggerFactory.getLogger(DefaultUpgradeService.class);
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(DefaultProjectUpgrader.class);
 
     public static final String UNKNOWN_VERSION = "0";
     public static final String MIN_SUPPORTED_VERSION = "6";
@@ -103,48 +105,48 @@ public class DefaultUpgradeService implements 
UpgradeService {
     @Inject
     private DataChannelDescriptorLoader loader;
 
-    public DefaultUpgradeService(@Inject List<UpgradeHandler> handlerList) {
-        for(UpgradeHandler handler : handlerList) {
+    public DefaultProjectUpgrader(@Inject List<UpgradeHandler> handlerList) {
+        for (UpgradeHandler handler : handlerList) {
             handlers.put(handler.getVersion(), handler);
         }
     }
 
     @Override
-    public UpgradeMetaData getUpgradeType(Resource resource) {
-        UpgradeMetaData metaData = new UpgradeMetaData();
-
+    public PreUpgradeState checkUpgradeNeeded(Resource resource) {
         String version = loadProjectVersion(resource);
-        metaData.setProjectVersion(version);
-        metaData.setSupportedVersion(String.valueOf(Project.VERSION));
+        String supportedVersion = String.valueOf(Project.VERSION);
 
         int c1 = VersionComparator.INSTANCE.compare(version, 
MIN_SUPPORTED_VERSION);
         if (c1 < 0) {
-            metaData.setIntermediateUpgradeVersion(MIN_SUPPORTED_VERSION);
-            metaData.setUpgradeType(UpgradeType.INTERMEDIATE_UPGRADE_NEEDED);
-            return metaData;
+            return new PreUpgradeState(
+                    UpgradeType.INTERMEDIATE_UPGRADE_NEEDED,
+                    version,
+                    supportedVersion,
+                    MIN_SUPPORTED_VERSION);
         }
 
-        int c2 = 
VersionComparator.INSTANCE.compare(String.valueOf(Project.VERSION), version);
+        int c2 = VersionComparator.INSTANCE.compare(supportedVersion, version);
+        UpgradeType upgradeType;
         if (c2 < 0) {
-            metaData.setUpgradeType(UpgradeType.DOWNGRADE_NEEDED);
+            upgradeType = UpgradeType.DOWNGRADE_NEEDED;
         } else if (c2 == 0) {
-            metaData.setUpgradeType(UpgradeType.UPGRADE_NOT_NEEDED);
+            upgradeType = UpgradeType.UPGRADE_NOT_NEEDED;
         } else {
-            metaData.setUpgradeType(UpgradeType.UPGRADE_NEEDED);
+            upgradeType = UpgradeType.UPGRADE_NEEDED;
         }
-        return metaData;
+        return new PreUpgradeState(upgradeType, version, supportedVersion, 
null);
     }
 
     protected List<UpgradeHandler> getHandlersForVersion(String version) {
         boolean found = MIN_SUPPORTED_VERSION.equals(version);
         List<UpgradeHandler> handlerList = new ArrayList<>();
 
-        for(Map.Entry<String, UpgradeHandler> entry : handlers.entrySet()) {
-            if(entry.getKey().equals(version)) {
+        for (Map.Entry<String, UpgradeHandler> entry : handlers.entrySet()) {
+            if (entry.getKey().equals(version)) {
                 found = true;
                 continue;
             }
-            if(!found) {
+            if (!found) {
                 continue;
             }
 
@@ -155,39 +157,51 @@ public class DefaultUpgradeService implements 
UpgradeService {
     }
 
     @Override
-    public Resource upgradeProject(Resource resource) {
+    public PostUpgradeState upgrade(Resource resource) {
         List<UpgradeHandler> handlerList = 
getHandlersForVersion(loadProjectVersion(resource));
 
-        List<UpgradeUnit> upgradeUnits = upgradeDOM(resource, handlerList);
+        List<UpgradeContext> upgradeUnits = upgradeDOM(resource, handlerList);
         saveDOM(upgradeUnits);
 
-        resource = upgradeUnits.get(0).getResource();
+        resource = upgradeUnits.getFirst().getResource();
 
         ConfigurationTree<DataChannelDescriptor> configurationTree = 
upgradeModel(resource, handlerList);
         saveModel(configurationTree);
 
-        return resource;
+        return new PostUpgradeState(resource, 
collectPostUpgradeMessages(upgradeUnits));
+    }
+
+    /**
+     * Collects user-facing messages recorded by upgrade handlers while 
processing the units, deduplicating repeats
+     * of the same message across units.
+     */
+    protected static List<String> 
collectPostUpgradeMessages(Collection<UpgradeContext> upgradeUnits) {
+        Set<String> messages = new LinkedHashSet<>();
+        for (UpgradeContext unit : upgradeUnits) {
+            messages.addAll(unit.getPostUpgradeMessages());
+        }
+        return new ArrayList<>(messages);
     }
 
-    protected List<UpgradeUnit> upgradeDOM(Resource resource, 
List<UpgradeHandler> handlerList) {
-        List<UpgradeUnit> allUnits = new ArrayList<>();
+    protected List<UpgradeContext> upgradeDOM(Resource resource, 
List<UpgradeHandler> handlerList) {
+        List<UpgradeContext> allUnits = new ArrayList<>();
 
         // Load DOM for all resources
         Document projectDocument = readDocument(resource.getURL());
-        UpgradeUnit projectUnit = new UpgradeUnit(resource, projectDocument);
+        UpgradeContext projectUnit = new UpgradeContext(resource, 
projectDocument);
         allUnits.add(projectUnit);
 
         List<Resource> dataMapResources = 
getAdditionalDatamapResources(projectUnit);
-        List<UpgradeUnit> dataMapUnits = new 
ArrayList<>(dataMapResources.size());
+        List<UpgradeContext> dataMapUnits = new 
ArrayList<>(dataMapResources.size());
         for (Resource dataMapResource : dataMapResources) {
-            dataMapUnits.add(new UpgradeUnit(dataMapResource, 
readDocument(dataMapResource.getURL())));
+            dataMapUnits.add(new UpgradeContext(dataMapResource, 
readDocument(dataMapResource.getURL())));
         }
         allUnits.addAll(dataMapUnits);
 
         // Update DOM
-        for(UpgradeHandler handler : handlerList) {
+        for (UpgradeHandler handler : handlerList) {
             handler.processProjectDom(projectUnit);
-            for(UpgradeUnit dataMapUnit : dataMapUnits) {
+            for (UpgradeContext dataMapUnit : dataMapUnits) {
                 handler.processDataMapDom(dataMapUnit);
             }
         }
@@ -195,8 +209,8 @@ public class DefaultUpgradeService implements 
UpgradeService {
         return allUnits;
     }
 
-    protected void saveDOM(Collection<UpgradeUnit> upgradeUnits) {
-        for(UpgradeUnit unit : upgradeUnits) {
+    protected void saveDOM(Collection<UpgradeContext> upgradeUnits) {
+        for (UpgradeContext unit : upgradeUnits) {
             saveDocument(unit);
         }
     }
@@ -206,7 +220,7 @@ public class DefaultUpgradeService implements 
UpgradeService {
         ConfigurationTree<DataChannelDescriptor> configurationTree = 
loadProject(resource);
 
         // Update model level if needed
-        for(UpgradeHandler handler : handlerList) {
+        for (UpgradeHandler handler : handlerList) {
             handler.processModel(configurationTree.getRootNode());
         }
 
@@ -219,7 +233,7 @@ public class DefaultUpgradeService implements 
UpgradeService {
 
         // link all datamaps, or else we will lose cross-datamaps relationships
         EntityResolver resolver = new EntityResolver();
-        for(DataMap dataMap : configurationTree.getRootNode().getDataMaps()) {
+        for (DataMap dataMap : configurationTree.getRootNode().getDataMaps()) {
             resolver.addDataMap(dataMap);
             dataMap.setNamespace(resolver);
         }
@@ -232,7 +246,7 @@ public class DefaultUpgradeService implements 
UpgradeService {
         projectSaver.save(project);
     }
 
-    List<Resource> getAdditionalDatamapResources(UpgradeUnit upgradeUnit) {
+    List<Resource> getAdditionalDatamapResources(UpgradeContext upgradeUnit) {
         List<Resource> resources = new ArrayList<>();
         try {
             XPath xpath = XPathFactory.newInstance().newXPath();
@@ -250,7 +264,7 @@ public class DefaultUpgradeService implements 
UpgradeService {
         return resources;
     }
 
-    protected void saveDocument(UpgradeUnit upgradeUnit) {
+    protected void saveDocument(UpgradeContext upgradeUnit) {
         try {
             Source input = new DOMSource(upgradeUnit.getDocument());
             Result output = new 
StreamResult(Util.toFile(upgradeUnit.getResource().getURL()));
@@ -348,7 +362,7 @@ public class DefaultUpgradeService implements 
UpgradeService {
         }
     }
 
-    class RootTagHandler extends DefaultHandler {
+    static class RootTagHandler extends DefaultHandler {
 
         private String projectVersion;
 
diff --git 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeUnit.java
 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/PostUpgradeState.java
similarity index 64%
copy from 
cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeUnit.java
copy to 
cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/PostUpgradeState.java
index 8803a2200..4aedeb027 100644
--- 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeUnit.java
+++ 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/PostUpgradeState.java
@@ -16,39 +16,21 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-
 package org.apache.cayenne.project.upgrade;
 
 import org.apache.cayenne.resource.Resource;
-import org.w3c.dom.Document;
+
+import java.util.List;
 
 /**
- * @since 4.1
+ * A result of a project upgrade: the resource of the upgraded project plus 
optional messages from individual upgrade
+ * handlers, describing manual steps the user must perform to complete the 
upgrade.
+ *
+ * @since 5.0
  */
-public class UpgradeUnit {
-
-    private Resource resource;
-
-    private Document document;
-
-    public UpgradeUnit(Resource resource, Document document) {
-        this.resource = resource;
-        this.document = document;
-    }
-
-    public Document getDocument() {
-        return document;
-    }
-
-    public Resource getResource() {
-        return resource;
-    }
-
-    public void setDocument(Document document) {
-        this.document = document;
-    }
+public record PostUpgradeState(Resource resource, List<String> messages) {
 
-    public void setResource(Resource resource) {
-        this.resource = resource;
+    public PostUpgradeState {
+        messages = List.copyOf(messages);
     }
 }
diff --git 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeService.java
 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/PreUpgradeState.java
similarity index 76%
copy from 
cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeService.java
copy to 
cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/PreUpgradeState.java
index edeb0df12..4ae52d50b 100644
--- 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeService.java
+++ 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/PreUpgradeState.java
@@ -16,18 +16,16 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-
 package org.apache.cayenne.project.upgrade;
 
-import org.apache.cayenne.resource.Resource;
-
 /**
- * @since 4.1
+ * An object providing upgrade information about a specific project in the 
context of enclosing Cayenne runtime.
+ *
+ * @since 3.1
  */
-public interface UpgradeService {
-
-    UpgradeMetaData getUpgradeType(Resource resource);
-
-    Resource upgradeProject(Resource resource);
-
+public record PreUpgradeState(
+        UpgradeType requiredUpgrade,
+        String projectVersion,
+        String supportedVersion,
+        String intermediateUpgradeVersion) {
 }
diff --git 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeService.java
 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/ProjectUpgrader.java
similarity index 87%
rename from 
cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeService.java
rename to 
cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/ProjectUpgrader.java
index edeb0df12..fd75206c9 100644
--- 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeService.java
+++ 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/ProjectUpgrader.java
@@ -22,12 +22,12 @@ package org.apache.cayenne.project.upgrade;
 import org.apache.cayenne.resource.Resource;
 
 /**
- * @since 4.1
+ * @since 5.0
  */
-public interface UpgradeService {
+public interface ProjectUpgrader {
 
-    UpgradeMetaData getUpgradeType(Resource resource);
+    PreUpgradeState checkUpgradeNeeded(Resource resource);
 
-    Resource upgradeProject(Resource resource);
+    PostUpgradeState upgrade(Resource resource);
 
 }
diff --git 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeUnit.java
 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeContext.java
similarity index 59%
rename from 
cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeUnit.java
rename to 
cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeContext.java
index 8803a2200..1d1acfbd5 100644
--- 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeUnit.java
+++ 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeContext.java
@@ -22,18 +22,22 @@ package org.apache.cayenne.project.upgrade;
 import org.apache.cayenne.resource.Resource;
 import org.w3c.dom.Document;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * @since 4.1
  */
-public class UpgradeUnit {
-
-    private Resource resource;
+public class UpgradeContext {
 
-    private Document document;
+    private final Resource resource;
+    private final Document document;
+    private final List<String> postUpgradeMessages;
 
-    public UpgradeUnit(Resource resource, Document document) {
+    public UpgradeContext(Resource resource, Document document) {
         this.resource = resource;
         this.document = document;
+        this.postUpgradeMessages = new ArrayList<>();
     }
 
     public Document getDocument() {
@@ -44,11 +48,21 @@ public class UpgradeUnit {
         return resource;
     }
 
-    public void setDocument(Document document) {
-        this.document = document;
+    /**
+     * Records a message shown to the user once the upgrade is done, 
describing manual steps required to complete
+     * the transition (e.g. regenerating classes or updating application 
code). Intended for upgrade handlers that
+     * detect a condition in this unit that they can't fix automatically.
+     *
+     * @since 5.0
+     */
+    public void addPostUpgradeMessage(String message) {
+        postUpgradeMessages.add(message);
     }
 
-    public void setResource(Resource resource) {
-        this.resource = resource;
+    /**
+     * @since 5.0
+     */
+    public List<String> getPostUpgradeMessages() {
+        return postUpgradeMessages;
     }
 }
diff --git 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeMetaData.java
 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeMetaData.java
deleted file mode 100644
index 1e5253855..000000000
--- 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeMetaData.java
+++ /dev/null
@@ -1,66 +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
- *
- *    https://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.project.upgrade;
-
-/**
- * An object providing upgrade information about a specific project in the 
context of
- * enclosing Cayenne runtime.
- * 
- * @since 3.1
- */
-public class UpgradeMetaData {
-
-    protected UpgradeType upgradeType;
-    protected String projectVersion;
-    protected String supportedVersion;
-    protected String intermediateUpgradeVersion;
-
-    public UpgradeType getUpgradeType() {
-        return upgradeType;
-    }
-
-    public void setUpgradeType(UpgradeType upgradeType) {
-        this.upgradeType = upgradeType;
-    }
-
-    public String getProjectVersion() {
-        return projectVersion;
-    }
-
-    public void setProjectVersion(String projectVersion) {
-        this.projectVersion = projectVersion;
-    }
-
-    public String getSupportedVersion() {
-        return supportedVersion;
-    }
-
-    public void setSupportedVersion(String supportedVersion) {
-        this.supportedVersion = supportedVersion;
-    }
-
-    public String getIntermediateUpgradeVersion() {
-        return intermediateUpgradeVersion;
-    }
-
-    public void setIntermediateUpgradeVersion(String 
intermediateUpgradeVersion) {
-        this.intermediateUpgradeVersion = intermediateUpgradeVersion;
-    }
-
-}
diff --git 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler.java
 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler.java
index 680a6a4de..7baf63737 100644
--- 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler.java
+++ 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler.java
@@ -20,7 +20,7 @@
 package org.apache.cayenne.project.upgrade.handlers;
 
 import org.apache.cayenne.configuration.DataChannelDescriptor;
-import org.apache.cayenne.project.upgrade.UpgradeUnit;
+import org.apache.cayenne.project.upgrade.UpgradeContext;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
@@ -73,12 +73,12 @@ public interface UpgradeHandler {
     /**
      * Process DOM for the project root file (e.g. cayenne-project.xml)
      */
-    void processProjectDom(UpgradeUnit upgradeUnit);
+    void processProjectDom(UpgradeContext upgradeUnit);
 
     /**
      * Process DOM for the data map file (e.g. datamap.map.xml)
      */
-    void processDataMapDom(UpgradeUnit upgradeUnit);
+    void processDataMapDom(UpgradeContext upgradeUnit);
 
     /**
      * This method should be avoided as much as possible, as
@@ -93,7 +93,7 @@ public interface UpgradeHandler {
      *
      * @param upgradeUnit for the datamap
      */
-    default void updateDomainSchemaAndVersion(UpgradeUnit upgradeUnit) {
+    default void updateDomainSchemaAndVersion(UpgradeContext upgradeUnit) {
         Element domain = upgradeUnit.getDocument().getDocumentElement();
         // update schema
         domain.setAttribute("xmlns", "http://cayenne.apache.org/schema/"; + 
getVersion() + "/domain");
@@ -109,7 +109,7 @@ public interface UpgradeHandler {
      *
      * @param upgradeUnit for the datamap
      */
-    default void updateDataMapSchemaAndVersion(UpgradeUnit upgradeUnit) {
+    default void updateDataMapSchemaAndVersion(UpgradeContext upgradeUnit) {
         Element dataMap = upgradeUnit.getDocument().getDocumentElement();
         // update schema
         dataMap.setAttribute("xmlns", "http://cayenne.apache.org/schema/"; + 
getVersion() + "/modelMap");
@@ -125,7 +125,7 @@ public interface UpgradeHandler {
      * @param upgradeUnit a unit to work with
      * @param extension   name of the extension (cgen, dbImport, etc.)
      */
-    default void updateExtensionSchema(UpgradeUnit upgradeUnit, String 
extension) {
+    default void updateExtensionSchema(UpgradeContext upgradeUnit, String 
extension) {
         XPath xpath = XPathFactory.newInstance().newXPath();
         NodeList nodes;
         try {
@@ -147,7 +147,7 @@ public interface UpgradeHandler {
      * @param extension   name of the extension (e.g. validation)
      * @since 5.0-M2
      */
-    default void updateDomainExtensionSchema(UpgradeUnit upgradeUnit, String 
extension) {
+    default void updateDomainExtensionSchema(UpgradeContext upgradeUnit, 
String extension) {
         XPath xpath = XPathFactory.newInstance().newXPath();
         NodeList nodes;
         try {
@@ -169,7 +169,7 @@ public interface UpgradeHandler {
      * @param upgradeUnit a unit to work with
      * @since 5.0
      */
-    default void updateInfoSchema(UpgradeUnit upgradeUnit) {
+    default void updateInfoSchema(UpgradeContext upgradeUnit) {
         XPath xpath = XPathFactory.newInstance().newXPath();
         NodeList nodes;
         try {
diff --git 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V10.java
 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V10.java
index ba01d8b2b..32aea9bef 100644
--- 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V10.java
+++ 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V10.java
@@ -19,7 +19,7 @@
 
 package org.apache.cayenne.project.upgrade.handlers;
 
-import org.apache.cayenne.project.upgrade.UpgradeUnit;
+import org.apache.cayenne.project.upgrade.UpgradeContext;
 
 /**
  * Upgrade handler for the project version "10" introduced by 4.1.M1 release.
@@ -37,13 +37,13 @@ public class UpgradeHandler_V10 implements UpgradeHandler {
     }
 
     @Override
-    public void processProjectDom(UpgradeUnit upgradeUnit) {
+    public void processProjectDom(UpgradeContext upgradeUnit) {
         // introduce xml namespace and schema for domain
         updateDomainSchemaAndVersion(upgradeUnit);
     }
 
     @Override
-    public void processDataMapDom(UpgradeUnit upgradeUnit) {
+    public void processDataMapDom(UpgradeContext upgradeUnit) {
         updateDataMapSchemaAndVersion(upgradeUnit);
     }
 }
diff --git 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11.java
 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11.java
index 752fe2f63..a32736fa1 100644
--- 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11.java
+++ 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11.java
@@ -19,7 +19,7 @@
 
 package org.apache.cayenne.project.upgrade.handlers;
 
-import org.apache.cayenne.project.upgrade.UpgradeUnit;
+import org.apache.cayenne.project.upgrade.UpgradeContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Element;
@@ -68,13 +68,13 @@ public class UpgradeHandler_V11 implements UpgradeHandler {
     }
 
     @Override
-    public void processProjectDom(UpgradeUnit upgradeUnit) {
+    public void processProjectDom(UpgradeContext upgradeUnit) {
         updateDomainSchemaAndVersion(upgradeUnit);
         updateDataNodeConnectionPool(upgradeUnit);
     }
 
     @Override
-    public void processDataMapDom(UpgradeUnit upgradeUnit) {
+    public void processDataMapDom(UpgradeContext upgradeUnit) {
         updateDataMapSchemaAndVersion(upgradeUnit);
         updateExtensionSchema(upgradeUnit, CGEN);
         updateExtensionSchema(upgradeUnit, DB_IMPORT);
@@ -88,7 +88,7 @@ public class UpgradeHandler_V11 implements UpgradeHandler {
         updateDbImportConfig(upgradeUnit);
     }
 
-    private void dropROPProperties(UpgradeUnit upgradeUnit) {
+    private void dropROPProperties(UpgradeContext upgradeUnit) {
         Element dataMap = upgradeUnit.getDocument().getDocumentElement();
         NodeList propertyNodes;
         try {
@@ -112,7 +112,7 @@ public class UpgradeHandler_V11 implements UpgradeHandler {
         }
     }
 
-    private void dropObjEntityClientInfo(UpgradeUnit upgradeUnit) {
+    private void dropObjEntityClientInfo(UpgradeContext upgradeUnit) {
         NodeList objEntityNodes;
         try {
             XPath xpath = XPathFactory.newInstance().newXPath();
@@ -129,7 +129,7 @@ public class UpgradeHandler_V11 implements UpgradeHandler {
         }
     }
 
-    private void upgradeGenericObjEntity(UpgradeUnit upgradeUnit) {
+    private void upgradeGenericObjEntity(UpgradeContext upgradeUnit) {
         NodeList objEntityNodes;
         try {
             XPath xpath = XPathFactory.newInstance().newXPath();
@@ -147,7 +147,7 @@ public class UpgradeHandler_V11 implements UpgradeHandler {
         }
     }
 
-    private void updateDbImportConfig(UpgradeUnit upgradeUnit) {
+    private void updateDbImportConfig(UpgradeContext upgradeUnit) {
         XPath xpath = XPathFactory.newInstance().newXPath();
         NodeList nodes;
         try {
@@ -162,13 +162,13 @@ public class UpgradeHandler_V11 implements UpgradeHandler 
{
         }
     }
 
-    private void updateCgenConfig(UpgradeUnit upgradeUnit) {
+    private void updateCgenConfig(UpgradeContext upgradeUnit) {
         renameQueryTemplates(upgradeUnit);
         dropCgenClientConfig(upgradeUnit);
         updateTemplates(upgradeUnit);
     }
 
-    private void updateDataNodeConnectionPool(UpgradeUnit upgradeUnit) {
+    private void updateDataNodeConnectionPool(UpgradeContext upgradeUnit) {
         XPath xpath = XPathFactory.newInstance().newXPath();
         NodeList nodes;
         try {
@@ -187,7 +187,7 @@ public class UpgradeHandler_V11 implements UpgradeHandler {
         }
     }
 
-    private void renameQueryTemplates(UpgradeUnit upgradeUnit) {
+    private void renameQueryTemplates(UpgradeContext upgradeUnit) {
         XPath xpath = XPathFactory.newInstance().newXPath();
         NodeList queryTemplates;
         NodeList querySuperTemplates;
@@ -211,7 +211,7 @@ public class UpgradeHandler_V11 implements UpgradeHandler {
         }
     }
 
-    private void dropCgenClientConfig(UpgradeUnit upgradeUnit) {
+    private void dropCgenClientConfig(UpgradeContext upgradeUnit) {
         XPath xpath = XPathFactory.newInstance().newXPath();
         NodeList nodes;
         try {
@@ -233,7 +233,7 @@ public class UpgradeHandler_V11 implements UpgradeHandler {
      *
      * @param upgradeUnit - unit to upgrade
      */
-    private void updateTemplates(UpgradeUnit upgradeUnit) {
+    private void updateTemplates(UpgradeContext upgradeUnit) {
         updateTemplate(upgradeUnit, "template");
         updateTemplate(upgradeUnit, "superTemplate");
         updateTemplate(upgradeUnit, "embeddableTemplate");
@@ -242,7 +242,7 @@ public class UpgradeHandler_V11 implements UpgradeHandler {
         updateTemplate(upgradeUnit, "dataMapSuperTemplate");
     }
 
-    private void updateTemplate(UpgradeUnit upgradeUnit, String nodeName) {
+    private void updateTemplate(UpgradeContext upgradeUnit, String nodeName) {
         XPath xpath = XPathFactory.newInstance().newXPath();
         NodeList templates;
         try {
diff --git 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V12.java
 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V12.java
index d5c56f183..cfd0e9075 100644
--- 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V12.java
+++ 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V12.java
@@ -19,7 +19,7 @@
 
 package org.apache.cayenne.project.upgrade.handlers;
 
-import org.apache.cayenne.project.upgrade.UpgradeUnit;
+import org.apache.cayenne.project.upgrade.UpgradeContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Element;
@@ -51,21 +51,21 @@ public class UpgradeHandler_V12 implements UpgradeHandler {
     }
 
     @Override
-    public void processProjectDom(UpgradeUnit upgradeUnit) {
+    public void processProjectDom(UpgradeContext upgradeUnit) {
         updateDomainSchemaAndVersion(upgradeUnit);
         removeGraphIncludes(upgradeUnit);
         updateDomainExtensionSchema(upgradeUnit, VALIDATION);
     }
 
     @Override
-    public void processDataMapDom(UpgradeUnit upgradeUnit) {
+    public void processDataMapDom(UpgradeContext upgradeUnit) {
         updateDataMapSchemaAndVersion(upgradeUnit);
         updateExtensionSchema(upgradeUnit, CGEN);
         updateExtensionSchema(upgradeUnit, DB_IMPORT);
         updateInfoSchema(upgradeUnit);
     }
 
-    private void removeGraphIncludes(UpgradeUnit upgradeUnit) {
+    private void removeGraphIncludes(UpgradeContext upgradeUnit) {
         XPath xpath = XPathFactory.newInstance().newXPath();
         NodeList nodes;
         try {
@@ -79,9 +79,10 @@ public class UpgradeHandler_V12 implements UpgradeHandler {
         for (int j = 0; j < nodes.getLength(); j++) {
             Element element = (Element) nodes.item(j);
             String href = element.getAttribute("href");
-            if (href != null && href.endsWith(GRAPH_SUFFIX)) {
+            if (href.endsWith(GRAPH_SUFFIX)) {
                 deleteGraphFile(upgradeUnit, href);
                 toRemove.add(element);
+                upgradeUnit.addPostUpgradeMessage("The 'graph' diagram layout 
is no longer supported and was deleted from the project");
             }
         }
         for (Element element : toRemove) {
@@ -89,7 +90,7 @@ public class UpgradeHandler_V12 implements UpgradeHandler {
         }
     }
 
-    private void deleteGraphFile(UpgradeUnit upgradeUnit, String href) {
+    private void deleteGraphFile(UpgradeContext upgradeUnit, String href) {
         try {
             File projectFile = new 
File(upgradeUnit.getResource().getURL().toURI());
             File graphFile = new File(projectFile.getParentFile(), href);
diff --git 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V7.java
 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V7.java
index 217645818..9a41e7e0b 100644
--- 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V7.java
+++ 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V7.java
@@ -19,20 +19,20 @@
 
 package org.apache.cayenne.project.upgrade.handlers;
 
-import java.util.ArrayList;
-import java.util.List;
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathFactory;
-
 import org.apache.cayenne.configuration.DataChannelDescriptor;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.ObjAttribute;
 import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.project.upgrade.UpgradeUnit;
+import org.apache.cayenne.project.upgrade.UpgradeContext;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * @since 4.1
  */
@@ -44,7 +44,7 @@ public class UpgradeHandler_V7 implements UpgradeHandler {
     }
 
     @Override
-    public void processProjectDom(UpgradeUnit upgradeUnit) {
+    public void processProjectDom(UpgradeContext upgradeUnit) {
         Element domain = upgradeUnit.getDocument().getDocumentElement();
         domain.setAttribute("project-version", getVersion());
 
@@ -63,7 +63,7 @@ public class UpgradeHandler_V7 implements UpgradeHandler {
     }
 
     @Override
-    public void processDataMapDom(UpgradeUnit upgradeUnit) {
+    public void processDataMapDom(UpgradeContext upgradeUnit) {
         updateDataMapSchemaAndVersion(upgradeUnit);
     }
 
diff --git 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V8.java
 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V8.java
index 5ce9328f9..74ea62bf7 100644
--- 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V8.java
+++ 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V8.java
@@ -25,7 +25,7 @@ import javax.xml.xpath.XPathFactory;
 
 import org.apache.cayenne.ConfigurationException;
 import org.apache.cayenne.map.QueryDescriptor;
-import org.apache.cayenne.project.upgrade.UpgradeUnit;
+import org.apache.cayenne.project.upgrade.UpgradeContext;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
@@ -40,13 +40,13 @@ public class UpgradeHandler_V8 implements UpgradeHandler {
     }
 
     @Override
-    public void processProjectDom(UpgradeUnit upgradeUnit) {
+    public void processProjectDom(UpgradeContext upgradeUnit) {
         Element domain = upgradeUnit.getDocument().getDocumentElement();
         domain.setAttribute("project-version", getVersion());
     }
 
     @Override
-    public void processDataMapDom(UpgradeUnit upgradeUnit) {
+    public void processDataMapDom(UpgradeContext upgradeUnit) {
         updateDataMapSchemaAndVersion(upgradeUnit);
 
         XPath xpath = XPathFactory.newInstance().newXPath();
diff --git 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V9.java
 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V9.java
index b6836e6d5..499cc7fea 100644
--- 
a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V9.java
+++ 
b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V9.java
@@ -24,7 +24,7 @@ import javax.xml.xpath.XPath;
 import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathFactory;
 
-import org.apache.cayenne.project.upgrade.UpgradeUnit;
+import org.apache.cayenne.project.upgrade.UpgradeContext;
 import org.apache.cayenne.util.Util;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -45,13 +45,13 @@ public class UpgradeHandler_V9 implements UpgradeHandler {
     }
 
     @Override
-    public void processProjectDom(UpgradeUnit upgradeUnit) {
+    public void processProjectDom(UpgradeContext upgradeUnit) {
         Element domain = upgradeUnit.getDocument().getDocumentElement();
         domain.setAttribute("project-version", getVersion());
     }
 
     @Override
-    public void processDataMapDom(UpgradeUnit upgradeUnit) {
+    public void processDataMapDom(UpgradeContext upgradeUnit) {
         Document document = upgradeUnit.getDocument();
         Element dataMap = document.getDocumentElement();
         updateDataMapSchemaAndVersion(upgradeUnit);
diff --git 
a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/DefaultUpgradeServiceTest.java
 
b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/DefaultProjectUpgraderTest.java
similarity index 86%
rename from 
cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/DefaultUpgradeServiceTest.java
rename to 
cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/DefaultProjectUpgraderTest.java
index 8a006c96c..62d9a02f4 100644
--- 
a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/DefaultUpgradeServiceTest.java
+++ 
b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/DefaultProjectUpgraderTest.java
@@ -43,16 +43,16 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.*;
 
-public class DefaultUpgradeServiceTest {
+public class DefaultProjectUpgraderTest {
 
-    DefaultUpgradeService upgradeService;
+    DefaultProjectUpgrader upgradeService;
 
     List<UpgradeHandler> handlers;
 
     @BeforeEach
     public void createService() {
         createHandlers();
-        upgradeService = new DefaultUpgradeService(handlers);
+        upgradeService = new DefaultProjectUpgrader(handlers);
     }
 
     @ParameterizedTest
@@ -64,9 +64,9 @@ public class DefaultUpgradeServiceTest {
         "12, UPGRADE_NOT_NEEDED",
         "13, DOWNGRADE_NEEDED"
     })
-    public void getUpgradeType(String version, UpgradeType expectedType) {
-        UpgradeMetaData metaData = 
upgradeService.getUpgradeType(getResourceForVersion(version));
-        assertEquals(expectedType, metaData.getUpgradeType());
+    public void checkUpgradeNeeded(String version, UpgradeType expectedType) {
+        PreUpgradeState metaData = 
upgradeService.checkUpgradeNeeded(getResourceForVersion(version));
+        assertEquals(expectedType, metaData.requiredUpgrade());
     }
 
     @Test
@@ -87,7 +87,7 @@ public class DefaultUpgradeServiceTest {
         URL url = 
Objects.requireNonNull(getClass().getResource("../cayenne-PROJECT1.xml"));
         Resource resource = new URLResource(url);
         Document document = readDocument(url);
-        UpgradeUnit unit = new UpgradeUnit(resource, document);
+        UpgradeContext unit = new UpgradeContext(resource, document);
         List<Resource> resources = 
upgradeService.getAdditionalDatamapResources(unit);
 
         assertEquals(2, resources.size());
@@ -107,7 +107,7 @@ public class DefaultUpgradeServiceTest {
         "10,        10.0"
     })
     public void decodeVersion(String version, double expected) {
-        assertEquals(expected, DefaultUpgradeService.decodeVersion(version), 
0.000001);
+        assertEquals(expected, DefaultProjectUpgrader.decodeVersion(version), 
0.000001);
     }
 
     @Test
@@ -115,10 +115,10 @@ public class DefaultUpgradeServiceTest {
         Resource resource = new 
URLResource(getClass().getResource("../cayenne-PROJECT1.xml"));
 
         // Mock service so it will use actual reading but skip actual saving 
part
-        upgradeService = mock(DefaultUpgradeService.class);
+        upgradeService = mock(DefaultProjectUpgrader.class);
         when(upgradeService.upgradeDOM(any(Resource.class), 
ArgumentMatchers.anyList()))
                 .thenCallRealMethod();
-        
when(upgradeService.getAdditionalDatamapResources(any(UpgradeUnit.class)))
+        
when(upgradeService.getAdditionalDatamapResources(any(UpgradeContext.class)))
                 .thenCallRealMethod();
 
         upgradeService.upgradeDOM(resource, handlers);
@@ -127,16 +127,16 @@ public class DefaultUpgradeServiceTest {
 //        verify(upgradeService, 
times(3)).saveDocument(any(UpgradeUnit.class));
         for(UpgradeHandler handler : handlers) {
             verify(handler).getVersion();
-            verify(handler).processProjectDom(any(UpgradeUnit.class));
+            verify(handler).processProjectDom(any(UpgradeContext.class));
             // two data maps
-            verify(handler, 
times(2)).processDataMapDom(any(UpgradeUnit.class));
+            verify(handler, 
times(2)).processDataMapDom(any(UpgradeContext.class));
             verifyNoMoreInteractions(handler);
         }
     }
 
     @Test
     public void readDocument() {
-        Document document = 
DefaultUpgradeService.readDocument(getClass().getResource("../cayenne-PROJECT1.xml"));
+        Document document = 
DefaultProjectUpgrader.readDocument(getClass().getResource("../cayenne-PROJECT1.xml"));
         assertEquals("12", 
document.getDocumentElement().getAttribute("project-version"));
     }
 
diff --git 
a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/BaseUpgradeHandlerTest.java
 
b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/BaseUpgradeHandlerTest.java
index 7b548a3a7..f330496dc 100644
--- 
a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/BaseUpgradeHandlerTest.java
+++ 
b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/BaseUpgradeHandlerTest.java
@@ -20,11 +20,10 @@
 package org.apache.cayenne.project.upgrade.handlers;
 
 import java.io.InputStreamReader;
-import java.io.StringReader;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 
-import org.apache.cayenne.project.upgrade.UpgradeUnit;
+import org.apache.cayenne.project.upgrade.UpgradeContext;
 import org.apache.cayenne.resource.URLResource;
 import org.junit.jupiter.api.BeforeEach;
 import org.w3c.dom.Document;
@@ -42,14 +41,14 @@ abstract class BaseUpgradeHandlerTest {
     abstract UpgradeHandler newHandler();
 
     Document processProjectDom(String xmlResourceName) throws Exception {
-        UpgradeUnit unit = new UpgradeUnit(new 
URLResource(getClass().getResource(xmlResourceName)),
+        UpgradeContext unit = new UpgradeContext(new 
URLResource(getClass().getResource(xmlResourceName)),
                 documentFromResource(xmlResourceName));
         handler.processProjectDom(unit);
         return unit.getDocument();
     }
 
     Document processDataMapDom(String xmlResourceName) throws Exception {
-        UpgradeUnit unit = new UpgradeUnit(new 
URLResource(getClass().getResource(xmlResourceName)),
+        UpgradeContext unit = new UpgradeContext(new 
URLResource(getClass().getResource(xmlResourceName)),
                 documentFromResource(xmlResourceName));
         handler.processDataMapDom(unit);
         return unit.getDocument();
diff --git 
a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V12Test.java
 
b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V12Test.java
index a2394069e..14c7ce002 100644
--- 
a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V12Test.java
+++ 
b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V12Test.java
@@ -20,7 +20,7 @@
 package org.apache.cayenne.project.upgrade.handlers;
 
 import org.apache.cayenne.configuration.DataChannelDescriptor;
-import org.apache.cayenne.project.upgrade.UpgradeUnit;
+import org.apache.cayenne.project.upgrade.UpgradeContext;
 import org.apache.cayenne.resource.URLResource;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.io.TempDir;
@@ -57,7 +57,8 @@ public class UpgradeHandler_V12Test extends 
BaseUpgradeHandlerTest {
         File graphFile = copyResourceToTemp("../v12/project1.graph.xml", 
"project1.graph.xml");
         assertTrue(graphFile.exists(), "precondition: graph file exists");
 
-        Document document = processProjectDomFromFile(projectFile);
+        UpgradeContext unit = processProjectDomFromFile(projectFile);
+        Document document = unit.getDocument();
 
         Element root = document.getDocumentElement();
         assertEquals("12", root.getAttribute("project-version"));
@@ -75,6 +76,9 @@ public class UpgradeHandler_V12Test extends 
BaseUpgradeHandlerTest {
                 ((Element) validation.item(0)).getAttribute("xmlns"));
 
         assertFalse(graphFile.exists(), "graph file must be deleted");
+
+        assertEquals(1, unit.getPostUpgradeMessages().size());
+        assertEquals("The 'graph' diagram layout is no longer supported and 
was deleted from the project", unit.getPostUpgradeMessages().getFirst());
     }
 
     @Test
@@ -82,7 +86,7 @@ public class UpgradeHandler_V12Test extends 
BaseUpgradeHandlerTest {
         File projectFile = copyResourceToTemp("../v12/cayenne-project1.xml", 
"cayenne-project.xml");
 
         // graph file intentionally absent — upgrade must complete without 
exception
-        Document document = processProjectDomFromFile(projectFile);
+        Document document = 
processProjectDomFromFile(projectFile).getDocument();
 
         Element root = document.getDocumentElement();
         assertEquals("12", root.getAttribute("project-version"));
@@ -142,14 +146,14 @@ public class UpgradeHandler_V12Test extends 
BaseUpgradeHandlerTest {
         return target;
     }
 
-    private Document processProjectDomFromFile(File file) throws Exception {
+    private UpgradeContext processProjectDomFromFile(File file) throws 
Exception {
         DocumentBuilder db = 
DocumentBuilderFactory.newInstance().newDocumentBuilder();
         Document doc;
         try (InputStream in = Files.newInputStream(file.toPath())) {
             doc = db.parse(in);
         }
-        UpgradeUnit unit = new UpgradeUnit(new 
URLResource(file.toURI().toURL()), doc);
+        UpgradeContext unit = new UpgradeContext(new 
URLResource(file.toURI().toURL()), doc);
         handler.processProjectDom(unit);
-        return doc;
+        return unit;
     }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Application.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Application.java
index 0498d786b..0fa9e2073 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Application.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Application.java
@@ -50,7 +50,7 @@ import 
org.apache.cayenne.project.ConfigurationNodeParentGetter;
 import org.apache.cayenne.project.ProjectLoader;
 import org.apache.cayenne.project.ProjectModule;
 import org.apache.cayenne.project.ProjectSaver;
-import org.apache.cayenne.project.upgrade.UpgradeService;
+import org.apache.cayenne.project.upgrade.ProjectUpgrader;
 import org.apache.cayenne.project.validation.ProjectValidator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -140,8 +140,8 @@ public class Application {
         return injector.getInstance(DataMapLoader.class);
     }
 
-    public UpgradeService getUpgradeService() {
-        return injector.getInstance(UpgradeService.class);
+    public ProjectUpgrader getUpgradeService() {
+        return injector.getInstance(ProjectUpgrader.class);
     }
 
     public CMFileChooser getFileChooser(Component parent, String title) {
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/OpenProjectAction.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/OpenProjectAction.java
index 4df09b64f..e4ad6f95b 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/OpenProjectAction.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/OpenProjectAction.java
@@ -26,8 +26,9 @@ import 
org.apache.cayenne.modeler.toolkit.filechooser.FileFilters;
 import org.apache.cayenne.modeler.ui.MainFrame;
 import org.apache.cayenne.modeler.ui.errors.ErrorDialog;
 import org.apache.cayenne.project.Project;
-import org.apache.cayenne.project.upgrade.UpgradeMetaData;
-import org.apache.cayenne.project.upgrade.UpgradeService;
+import org.apache.cayenne.project.upgrade.PostUpgradeState;
+import org.apache.cayenne.project.upgrade.PreUpgradeState;
+import org.apache.cayenne.project.upgrade.ProjectUpgrader;
 import org.apache.cayenne.resource.Resource;
 import org.apache.cayenne.resource.URLResource;
 import org.slf4j.Logger;
@@ -42,6 +43,7 @@ import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
 import java.io.File;
 import java.net.URL;
+import java.util.List;
 import java.util.Map;
 
 public class OpenProjectAction extends AppAction {
@@ -137,11 +139,13 @@ public class OpenProjectAction extends AppAction {
             URL url = file.toURI().toURL();
             Resource rootSource = new URLResource(url);
 
-            UpgradeService upgradeService = app.getUpgradeService();
-            UpgradeMetaData metaData = 
upgradeService.getUpgradeType(rootSource);
-            switch (metaData.getUpgradeType()) {
+            List<String> upgradeMessages = List.of();
+
+            ProjectUpgrader projectUpgrader = app.getUpgradeService();
+            PreUpgradeState metaData = 
projectUpgrader.checkUpgradeNeeded(rootSource);
+            switch (metaData.requiredUpgrade()) {
                 case INTERMEDIATE_UPGRADE_NEEDED:
-                    String modelerVersion = 
PROJECT_TO_MODELER_VERSION.get(metaData.getProjectVersion());
+                    String modelerVersion = 
PROJECT_TO_MODELER_VERSION.get(metaData.projectVersion());
                     if (modelerVersion == null) {
                         modelerVersion = "";
                     }
@@ -161,7 +165,9 @@ public class OpenProjectAction extends AppAction {
 
                 case UPGRADE_NEEDED:
                     if (processUpgrades()) {
-                        rootSource = upgradeService.upgradeProject(rootSource);
+                        PostUpgradeState postUpgrade = 
projectUpgrader.upgrade(rootSource);
+                        rootSource = postUpgrade.resource();
+                        upgradeMessages = postUpgrade.messages();
                     } else {
                         CloseProjectAction.closeProject(app, false);
                         return;
@@ -171,6 +177,10 @@ public class OpenProjectAction extends AppAction {
 
             openProjectResource(rootSource, controller, mcpHandshakeNonce);
 
+            if (!upgradeMessages.isEmpty()) {
+                showPostUpgradeMessages(upgradeMessages);
+            }
+
 
         } catch (Exception ex) {
             LOGGER.warn("Error loading project file.", ex);
@@ -184,6 +194,14 @@ public class OpenProjectAction extends AppAction {
         return project;
     }
 
+    private void showPostUpgradeMessages(List<String> messages) {
+        JOptionPane.showMessageDialog(
+                app.getFrame(),
+                "The project was upgraded, but some manual steps are 
required:\n\n" + String.join("\n\n", messages),
+                "Manual Steps Required",
+                JOptionPane.INFORMATION_MESSAGE);
+    }
+
     private boolean processUpgrades() {
         // need an upgrade
         int returnCode = JOptionPane.showConfirmDialog(

Reply via email to