CAY-2335: New XML loading/saving mechanics with support of plugable handlers - ProjectExtension - new upgrade handlers
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/38553b16 Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/38553b16 Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/38553b16 Branch: refs/heads/master Commit: 38553b1603b9622a6eae691131a4106591649556 Parents: c58b6f4 Author: Nikita Timofeev <[email protected]> Authored: Tue Jul 25 12:39:56 2017 +0300 Committer: Nikita Timofeev <[email protected]> Committed: Tue Jul 25 12:39:56 2017 +0300 ---------------------------------------------------------------------- .../cayenne/project/CompoundSaverDelegate.java | 183 +++++++ .../cayenne/project/ConfigurationSaver.java | 12 +- .../cayenne/project/FileProjectSaver.java | 25 +- .../org/apache/cayenne/project/Project.java | 10 +- .../apache/cayenne/project/ProjectModule.java | 43 +- .../cayenne/project/SaveableNodesGetter.java | 11 +- .../project/extension/BaseSaverDelegate.java | 133 +++++ .../extension/ExtensionAwareHandlerFactory.java | 69 +++ .../project/extension/LoaderDelegate.java | 45 ++ .../project/extension/ProjectExtension.java | 49 ++ .../project/extension/SaverDelegate.java | 45 ++ .../project/upgrade/BaseUpgradeHandler.java | 218 -------- .../upgrade/DataSourceInfoLoader_3_0_0_1.java | 228 --------- .../project/upgrade/DefaultUpgradeService.java | 318 ++++++++++++ .../project/upgrade/ProjectUpgrader.java | 34 -- .../cayenne/project/upgrade/UpgradeHandler.java | 57 --- .../cayenne/project/upgrade/UpgradeService.java | 33 ++ .../cayenne/project/upgrade/UpgradeUnit.java | 54 ++ .../upgrade/handlers/UpgradeHandler.java | 58 +++ .../upgrade/handlers/UpgradeHandler_V10.java | 68 +++ .../upgrade/handlers/UpgradeHandler_V7.java | 109 ++++ .../upgrade/handlers/UpgradeHandler_V8.java | 99 ++++ .../upgrade/handlers/UpgradeHandler_V9.java | 81 +++ .../project/upgrade/v6/ProjectUpgrader_V6.java | 43 -- .../project/upgrade/v6/UpgradeHandler_V6.java | 118 ----- ...XMLDataChannelDescriptorLoader_V3_0_0_1.java | 299 ----------- .../v6/XMLDataSourceInfoLoader_V3_0_0_1.java | 300 ----------- .../project/upgrade/v7/UpgradeHandler_V7.java | 137 ----- .../project/upgrade/v8/UpgradeHandler_V8.java | 174 ------- .../project/upgrade/v9/UpgradeHandler_V9.java | 145 ------ .../project/DataChannelProjectLoaderTest.java | 19 +- .../project/DataChannelProjectSaverTest.java | 30 +- .../cayenne/project/FileProjectSaverTest.java | 4 +- .../upgrade/DefaultUpgradeServiceTest.java | 163 ++++++ .../handlers/BaseUpgradeHandlerTest.java | 71 +++ .../handlers/UpgradeHandler_V10Test.java | 66 +++ .../upgrade/handlers/UpgradeHandler_V7Test.java | 94 ++++ .../upgrade/handlers/UpgradeHandler_V8Test.java | 97 ++++ .../upgrade/handlers/UpgradeHandler_V9Test.java | 69 +++ .../upgrade/v7/ProjectUpgrader_V7Test.java | 499 ------------------- .../upgrade/v8/ProjectUpgrader_V8Test.java | 197 -------- .../upgrade/v9/ProjectUpgrader_V9Test.java | 249 --------- .../apache/cayenne/project/cayenne-PROJECT1.xml | 14 +- .../apache/cayenne/project/cayenne-PROJECT2.xml | 16 +- .../cayenne/project/testProjectMap1_1.map.xml | 10 +- .../cayenne/project/testProjectMap1_2.map.xml | 10 +- .../cayenne/project/testProjectMap2_1.map.xml | 10 +- .../cayenne/project/testProjectMap2_2.map.xml | 10 +- .../upgrade/handlers/cayenne-project-v10.xml | 3 + .../upgrade/handlers/cayenne-project-v11.xml | 3 + .../handlers/cayenne-project-v3.2.1.0.xml | 3 + .../upgrade/handlers/cayenne-project-v5.xml | 3 + .../upgrade/handlers/cayenne-project-v6.xml | 17 + .../upgrade/handlers/cayenne-project-v7.xml | 15 + .../upgrade/handlers/cayenne-project-v8.xml | 15 + .../upgrade/handlers/cayenne-project-v9.xml | 15 + .../upgrade/handlers/test-map-v6.map.xml | 21 + .../upgrade/handlers/test-map-v7.map.xml | 31 ++ .../upgrade/handlers/test-map-v8.map.xml | 13 + .../upgrade/handlers/test-map-v9.map.xml | 12 + 60 files changed, 2194 insertions(+), 2783 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/CompoundSaverDelegate.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/CompoundSaverDelegate.java b/cayenne-project/src/main/java/org/apache/cayenne/project/CompoundSaverDelegate.java new file mode 100644 index 0000000..5ea7a29 --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/CompoundSaverDelegate.java @@ -0,0 +1,183 @@ +/***************************************************************** + * 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.project; + +import java.util.Collection; + +import org.apache.cayenne.configuration.DataChannelDescriptor; +import org.apache.cayenne.configuration.DataNodeDescriptor; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.DbRelationship; +import org.apache.cayenne.map.Embeddable; +import org.apache.cayenne.map.EmbeddableAttribute; +import org.apache.cayenne.map.ObjAttribute; +import org.apache.cayenne.map.ObjEntity; +import org.apache.cayenne.map.ObjRelationship; +import org.apache.cayenne.map.Procedure; +import org.apache.cayenne.map.ProcedureParameter; +import org.apache.cayenne.map.QueryDescriptor; +import org.apache.cayenne.project.extension.SaverDelegate; +import org.apache.cayenne.util.XMLEncoder; + +/** + * @since 4.1 + */ +class CompoundSaverDelegate implements SaverDelegate { + + Collection<SaverDelegate> delegates; + + CompoundSaverDelegate(Collection<SaverDelegate> delegates) { + this.delegates = delegates; + setParentDelegate(this); + } + + @Override + public Void visitDataChannelDescriptor(DataChannelDescriptor channelDescriptor) { + for(SaverDelegate delegate : delegates) { + delegate.visitDataChannelDescriptor(channelDescriptor); + } + return null; + } + + @Override + public Void visitDataNodeDescriptor(DataNodeDescriptor nodeDescriptor) { + for(SaverDelegate delegate : delegates) { + delegate.visitDataNodeDescriptor(nodeDescriptor); + } + return null; + } + + @Override + public Void visitDataMap(DataMap dataMap) { + for(SaverDelegate delegate : delegates) { + delegate.visitDataMap(dataMap); + } + return null; + } + + @Override + public Void visitObjEntity(ObjEntity entity) { + for(SaverDelegate delegate : delegates) { + delegate.visitObjEntity(entity); + } + return null; + } + + @Override + public Void visitDbEntity(DbEntity entity) { + for(SaverDelegate delegate : delegates) { + delegate.visitDbEntity(entity); + } + return null; + } + + @Override + public Void visitEmbeddable(Embeddable embeddable) { + for(SaverDelegate delegate : delegates) { + delegate.visitEmbeddable(embeddable); + } + return null; + } + + @Override + public Void visitEmbeddableAttribute(EmbeddableAttribute attribute) { + for(SaverDelegate delegate : delegates) { + delegate.visitEmbeddableAttribute(attribute); + } + return null; + } + + @Override + public Void visitObjAttribute(ObjAttribute attribute) { + for(SaverDelegate delegate : delegates) { + delegate.visitObjAttribute(attribute); + } + return null; + } + + @Override + public Void visitDbAttribute(DbAttribute attribute) { + for(SaverDelegate delegate : delegates) { + delegate.visitDbAttribute(attribute); + } + return null; + } + + @Override + public Void visitObjRelationship(ObjRelationship relationship) { + for(SaverDelegate delegate : delegates) { + delegate.visitObjRelationship(relationship); + } + return null; + } + + @Override + public Void visitDbRelationship(DbRelationship relationship) { + for(SaverDelegate delegate : delegates) { + delegate.visitDbRelationship(relationship); + } + return null; + } + + @Override + public Void visitProcedure(Procedure procedure) { + for(SaverDelegate delegate : delegates) { + delegate.visitProcedure(procedure); + } + return null; + } + + @Override + public Void visitProcedureParameter(ProcedureParameter parameter) { + for(SaverDelegate delegate : delegates) { + delegate.visitProcedureParameter(parameter); + } + return null; + } + + @Override + public Void visitQuery(QueryDescriptor query) { + for(SaverDelegate delegate : delegates) { + delegate.visitQuery(query); + } + return null; + } + + @Override + public void setXMLEncoder(XMLEncoder encoder) { + for(SaverDelegate delegate : delegates) { + delegate.setXMLEncoder(encoder); + } + } + + @Override + public void setParentDelegate(SaverDelegate parentDelegate) { + for(SaverDelegate delegate : delegates) { + delegate.setParentDelegate(parentDelegate); + } + } + + @Override + public SaverDelegate getParentDelegate() { + return null; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/ConfigurationSaver.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/ConfigurationSaver.java b/cayenne-project/src/main/java/org/apache/cayenne/project/ConfigurationSaver.java index 9ed8a88..1aab516 100644 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/ConfigurationSaver.java +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/ConfigurationSaver.java @@ -19,10 +19,12 @@ package org.apache.cayenne.project; import java.io.PrintWriter; +import java.util.Collection; import org.apache.cayenne.configuration.BaseConfigurationNodeVisitor; import org.apache.cayenne.configuration.DataChannelDescriptor; import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.project.extension.SaverDelegate; import org.apache.cayenne.util.XMLEncoder; /** @@ -32,17 +34,20 @@ class ConfigurationSaver extends BaseConfigurationNodeVisitor<Void> { private PrintWriter printWriter; private String version; + private SaverDelegate delegate; - ConfigurationSaver(PrintWriter printWriter, String version) { + ConfigurationSaver(PrintWriter printWriter, String version, SaverDelegate delegate) { this.printWriter = printWriter; this.version = version; + this.delegate = delegate; } @Override public Void visitDataChannelDescriptor(DataChannelDescriptor node) { XMLEncoder encoder = new XMLEncoder(printWriter, "\t", version); printXMLHeader(encoder); - node.encodeAsXML(encoder); + delegate.setXMLEncoder(encoder); + node.encodeAsXML(encoder, delegate); return null; } @@ -50,7 +55,8 @@ class ConfigurationSaver extends BaseConfigurationNodeVisitor<Void> { public Void visitDataMap(DataMap node) { XMLEncoder encoder = new XMLEncoder(printWriter, "\t", version); printXMLHeader(encoder); - node.encodeAsXML(encoder); + delegate.setXMLEncoder(encoder); + node.encodeAsXML(encoder, delegate); return null; } http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/FileProjectSaver.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/FileProjectSaver.java b/cayenne-project/src/main/java/org/apache/cayenne/project/FileProjectSaver.java index c37d763..fe01162 100644 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/FileProjectSaver.java +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/FileProjectSaver.java @@ -23,6 +23,8 @@ import org.apache.cayenne.configuration.ConfigurationNameMapper; import org.apache.cayenne.configuration.ConfigurationNode; import org.apache.cayenne.configuration.ConfigurationNodeVisitor; import org.apache.cayenne.di.Inject; +import org.apache.cayenne.project.extension.ProjectExtension; +import org.apache.cayenne.project.extension.SaverDelegate; import org.apache.cayenne.resource.Resource; import org.apache.cayenne.resource.URLResource; import org.apache.cayenne.util.Util; @@ -38,6 +40,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; +import java.util.List; /** * A ProjectSaver saving project configuration to the file system. @@ -53,16 +56,24 @@ public class FileProjectSaver implements ProjectSaver { protected ConfigurationNodeVisitor<Collection<ConfigurationNode>> saveableNodesGetter; protected String fileEncoding; - public FileProjectSaver() { + protected Collection<SaverDelegate> saverDelegates; + + public FileProjectSaver(@Inject List<ProjectExtension> extensions) { resourceGetter = new ConfigurationSourceGetter(); saveableNodesGetter = new SaveableNodesGetter(); // this is not configurable yet... probably doesn't have to be fileEncoding = "UTF-8"; + + saverDelegates = new ArrayList<>(extensions.size()); + for(ProjectExtension extension : extensions) { + SaverDelegate delegate = extension.createSaverDelegate(); + saverDelegates.add(delegate); + } } public String getSupportedVersion() { - return "9"; + return String.valueOf(Project.VERSION); } public void save(Project project) { @@ -169,7 +180,7 @@ public class FileProjectSaver implements ProjectSaver { for (SaveUnit unit : units) { String name = unit.targetFile.getName(); - if (name == null || name.length() < 3) { + if (name.length() < 3) { name = "cayenne-project"; } @@ -185,8 +196,8 @@ public class FileProjectSaver implements ProjectSaver { unit.targetTempFile.delete(); } - try (PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream( - unit.targetTempFile), fileEncoding));) { + try (PrintWriter printWriter = new PrintWriter(new OutputStreamWriter( + new FileOutputStream(unit.targetTempFile), fileEncoding))) { saveToTempFile(unit, printWriter); } catch (UnsupportedEncodingException e) { throw new CayenneRuntimeException("Unsupported encoding '%s' (%s)", e, fileEncoding, e.getMessage()); @@ -198,7 +209,9 @@ public class FileProjectSaver implements ProjectSaver { } void saveToTempFile(SaveUnit unit, PrintWriter printWriter) { - unit.node.acceptVisitor(new ConfigurationSaver(printWriter, getSupportedVersion())); + unit.node.acceptVisitor( + new ConfigurationSaver(printWriter, getSupportedVersion(), new CompoundSaverDelegate(saverDelegates)) + ); } void saveCommit(Collection<SaveUnit> units) { http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/Project.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/Project.java b/cayenne-project/src/main/java/org/apache/cayenne/project/Project.java index ad0458b..a1ebd70 100644 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/Project.java +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/Project.java @@ -36,6 +36,14 @@ import org.apache.cayenne.resource.Resource; */ public class Project { + /** + * Current version of Cayenne project. + * Used by different parsers and savers of project's XML files. + * + * @since 4.1 + */ + static public final int VERSION = 10; + protected boolean modified; protected ConfigurationTree<?> configurationTree; @@ -45,7 +53,7 @@ public class Project { public Project(ConfigurationTree<?> configurationTree) { this.configurationTree = configurationTree; this.configurationSourceGetter = new ConfigurationSourceGetter(); - this.unusedResources = new HashSet<URL>(); + this.unusedResources = new HashSet<>(); } public ConfigurationTree<?> getConfigurationTree() { http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/ProjectModule.java ---------------------------------------------------------------------- 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 a1eeb98..8f5d011 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 @@ -19,26 +19,55 @@ package org.apache.cayenne.project; import org.apache.cayenne.di.Binder; +import org.apache.cayenne.di.ListBuilder; import org.apache.cayenne.di.Module; -import org.apache.cayenne.project.upgrade.ProjectUpgrader; -import org.apache.cayenne.project.upgrade.v9.ProjectUpgrader_V9; +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.handlers.UpgradeHandler; +import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler_V10; +import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler_V7; +import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler_V8; +import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler_V9; import org.apache.cayenne.project.validation.DefaultProjectValidator; import org.apache.cayenne.project.validation.ProjectValidator; /** - * A dependency injection (DI) module contributing configuration related to Cayenne mapping project manipulation to a - * DI container. + * A dependency injection (DI) module contributing configuration related + * to Cayenne mapping project manipulation to a DI container. * * @since 4.0 */ public class ProjectModule implements Module { + /** + * @since 4.1 + */ + public static ListBuilder<ProjectExtension> contributeExtension(Binder binder) { + return binder.bindList(ProjectExtension.class); + } + + /** + * @since 4.1 + */ + public static ListBuilder<UpgradeHandler> contributeUpgradeHandler(Binder binder) { + return binder.bindList(UpgradeHandler.class); + } + public void configure(Binder binder) { binder.bind(ProjectLoader.class).to(DataChannelProjectLoader.class); binder.bind(ProjectSaver.class).to(FileProjectSaver.class); - binder.bind(ProjectUpgrader.class).to(ProjectUpgrader_V9.class); binder.bind(ProjectValidator.class).to(DefaultProjectValidator.class); - binder.bind(ConfigurationNodeParentGetter.class).to( - DefaultConfigurationNodeParentGetter.class); + binder.bind(ConfigurationNodeParentGetter.class).to(DefaultConfigurationNodeParentGetter.class); + + binder.bind(UpgradeService.class).to(DefaultUpgradeService.class); + // Note: order is important + contributeUpgradeHandler(binder) + .add(UpgradeHandler_V7.class) + .add(UpgradeHandler_V8.class) + .add(UpgradeHandler_V9.class) + .add(UpgradeHandler_V10.class); + + contributeExtension(binder); } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/SaveableNodesGetter.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/SaveableNodesGetter.java b/cayenne-project/src/main/java/org/apache/cayenne/project/SaveableNodesGetter.java index ca74cc2..8da76e6 100644 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/SaveableNodesGetter.java +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/SaveableNodesGetter.java @@ -30,19 +30,14 @@ import java.util.Collections; /** * @since 3.1 */ -class SaveableNodesGetter extends - BaseConfigurationNodeVisitor<Collection<ConfigurationNode>> { +class SaveableNodesGetter extends BaseConfigurationNodeVisitor<Collection<ConfigurationNode>> { @Override - public Collection<ConfigurationNode> visitDataChannelDescriptor( - DataChannelDescriptor descriptor) { + public Collection<ConfigurationNode> visitDataChannelDescriptor(DataChannelDescriptor descriptor) { Collection<ConfigurationNode> nodes = new ArrayList<>(); nodes.add(descriptor); - - for (DataMap map : descriptor.getDataMaps()) { - nodes.add(map); - } + nodes.addAll(descriptor.getDataMaps()); return nodes; } http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/extension/BaseSaverDelegate.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/extension/BaseSaverDelegate.java b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/BaseSaverDelegate.java new file mode 100644 index 0000000..08565b2 --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/BaseSaverDelegate.java @@ -0,0 +1,133 @@ +/***************************************************************** + * 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.project.extension; + +import org.apache.cayenne.configuration.DataChannelDescriptor; +import org.apache.cayenne.configuration.DataNodeDescriptor; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.DbRelationship; +import org.apache.cayenne.map.Embeddable; +import org.apache.cayenne.map.EmbeddableAttribute; +import org.apache.cayenne.map.ObjAttribute; +import org.apache.cayenne.map.ObjEntity; +import org.apache.cayenne.map.ObjRelationship; +import org.apache.cayenne.map.Procedure; +import org.apache.cayenne.map.ProcedureParameter; +import org.apache.cayenne.map.QueryDescriptor; +import org.apache.cayenne.util.XMLEncoder; + +/** + * Base saver delegate that handles common setters/getters, as well as provides empty stub for all methods. + * + * @since 4.1 + */ +public class BaseSaverDelegate implements SaverDelegate { + + protected XMLEncoder encoder; + + protected SaverDelegate parentDelegate; + + @Override + public Void visitDataChannelDescriptor(DataChannelDescriptor channelDescriptor) { + return null; + } + + @Override + public Void visitDataNodeDescriptor(DataNodeDescriptor nodeDescriptor) { + return null; + } + + @Override + public Void visitDataMap(DataMap dataMap) { + return null; + } + + @Override + public Void visitObjEntity(ObjEntity entity) { + return null; + } + + @Override + public Void visitDbEntity(DbEntity entity) { + return null; + } + + @Override + public Void visitEmbeddable(Embeddable embeddable) { + return null; + } + + @Override + public Void visitEmbeddableAttribute(EmbeddableAttribute attribute) { + return null; + } + + @Override + public Void visitObjAttribute(ObjAttribute attribute) { + return null; + } + + @Override + public Void visitDbAttribute(DbAttribute attribute) { + return null; + } + + @Override + public Void visitObjRelationship(ObjRelationship relationship) { + return null; + } + + @Override + public Void visitDbRelationship(DbRelationship relationship) { + return null; + } + + @Override + public Void visitProcedure(Procedure procedure) { + return null; + } + + @Override + public Void visitProcedureParameter(ProcedureParameter parameter) { + return null; + } + + @Override + public Void visitQuery(QueryDescriptor query) { + return null; + } + + @Override + public void setXMLEncoder(XMLEncoder encoder) { + this.encoder = encoder; + } + + @Override + public void setParentDelegate(SaverDelegate parentDelegate) { + this.parentDelegate = parentDelegate; + } + + @Override + public SaverDelegate getParentDelegate() { + return parentDelegate; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/extension/ExtensionAwareHandlerFactory.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/extension/ExtensionAwareHandlerFactory.java b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/ExtensionAwareHandlerFactory.java new file mode 100644 index 0000000..fc7e35d --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/ExtensionAwareHandlerFactory.java @@ -0,0 +1,69 @@ +/***************************************************************** + * 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.project.extension; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.cayenne.CayenneRuntimeException; +import org.apache.cayenne.configuration.xml.DefaultHandlerFactory; +import org.apache.cayenne.configuration.xml.NamespaceAwareNestedTagHandler; +import org.apache.cayenne.di.Inject; + +/** + * Project parser handlers factory that will use third-party extensions + * to provide handlers for unknown tags. + * + * @see ProjectExtension + * @see DefaultHandlerFactory + * + * @since 4.1 + */ +public class ExtensionAwareHandlerFactory extends DefaultHandlerFactory { + + Map<String, LoaderDelegate> loaderDelegates = new ConcurrentHashMap<>(); + + public ExtensionAwareHandlerFactory(@Inject List<ProjectExtension> extensions) { + for(ProjectExtension extension : extensions) { + LoaderDelegate delegate = extension.createLoaderDelegate(); + LoaderDelegate old = loaderDelegates.put(delegate.getTargetNamespace(), delegate); + if(old != null) { + throw new CayenneRuntimeException("Found two loader delegates for namespace %s", + delegate.getTargetNamespace()); + } + } + } + + @Override + public NamespaceAwareNestedTagHandler createHandler(String namespace, String localName, + NamespaceAwareNestedTagHandler parent) { + + LoaderDelegate delegate = loaderDelegates.get(namespace); + if(delegate != null) { + NamespaceAwareNestedTagHandler handler = delegate.createHandler(parent, localName); + if(handler != null) { + return handler; + } + } + + return super.createHandler(namespace, localName, parent); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/extension/LoaderDelegate.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/extension/LoaderDelegate.java b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/LoaderDelegate.java new file mode 100644 index 0000000..938e7c0 --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/LoaderDelegate.java @@ -0,0 +1,45 @@ +/***************************************************************** + * 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.project.extension; + +import org.apache.cayenne.configuration.xml.NamespaceAwareNestedTagHandler; + +/** + * Delegate that handles loading process for extension specific parts of XML document. + * + * @since 4.1 + */ +public interface LoaderDelegate { + + /** + * @return target namespace that this extension is using + */ + String getTargetNamespace(); + + /** + * Create handler that will handle parsing process further. + * + * @param parent parent handler + * @param tag current tag that in question + * @return new handler that will process tag or null if there is no interest in tag + */ + NamespaceAwareNestedTagHandler createHandler(NamespaceAwareNestedTagHandler parent, String tag); + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/extension/ProjectExtension.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/extension/ProjectExtension.java b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/ProjectExtension.java new file mode 100644 index 0000000..1bfa33e --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/ProjectExtension.java @@ -0,0 +1,49 @@ +/***************************************************************** + * 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.project.extension; + +/** + * <p>DataMap XML file extension mechanics.</p> + * <p> + * Can be used to enhance datamap.map.xml files with additional (really random) information. + * By default extensions not used by {@link org.apache.cayenne.configuration.server.ServerRuntime} or + * ClientRuntime so they can safely store big chunks of data. + * </p> + * <p> + * Extensions can be contributed by {@link org.apache.cayenne.project.ProjectModule#contributeExtension(org.apache.cayenne.di.Binder)}. + * {@link org.apache.cayenne.project.ProjectModule} currently used by Modeler and cli tools, e.g. cdbimport and cgen. + * </p> + * + * @see org.apache.cayenne.project.extension.info.InfoExtension as reference implementation + * @since 4.1 + */ +public interface ProjectExtension { + + /** + * @return delegate that handle loading phase of XML processing + */ + LoaderDelegate createLoaderDelegate(); + + /** + * @return delegate that handle saving phase of XML processing + */ + SaverDelegate createSaverDelegate(); + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/extension/SaverDelegate.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/extension/SaverDelegate.java b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/SaverDelegate.java new file mode 100644 index 0000000..4ed5c92 --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/SaverDelegate.java @@ -0,0 +1,45 @@ +/***************************************************************** + * 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.project.extension; + +import org.apache.cayenne.configuration.ConfigurationNodeVisitor; +import org.apache.cayenne.util.XMLEncoder; + +/** + * Delegate that handles saving XML of extension. + * {@link BaseSaverDelegate} should be used as a base class for custom delegates. + * + * @since 4.1 + */ +public interface SaverDelegate extends ConfigurationNodeVisitor<Void> { + + /** + * @param encoder provided by caller + */ + void setXMLEncoder(XMLEncoder encoder); + + /** + * @param parentDelegate parent delegate, provided by caller + */ + void setParentDelegate(SaverDelegate parentDelegate); + + SaverDelegate getParentDelegate(); + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/BaseUpgradeHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/BaseUpgradeHandler.java b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/BaseUpgradeHandler.java deleted file mode 100644 index 89a7b82..0000000 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/BaseUpgradeHandler.java +++ /dev/null @@ -1,218 +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.project.upgrade; - -import org.apache.cayenne.ConfigurationException; -import org.apache.cayenne.configuration.DataChannelDescriptor; -import org.apache.cayenne.map.DataMap; -import org.apache.cayenne.map.EntityResolver; -import org.apache.cayenne.resource.Resource; -import org.apache.cayenne.util.Util; -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.DefaultHandler; - -import java.io.InputStream; -import java.net.URL; - -/** - * A common superclass of UpgradeHandlers. - * - * @since 3.1 - */ -// there's no guarantee this will survive the further version upgrades, but for -// now all -// the code here seems like version-agnostic -public abstract class BaseUpgradeHandler implements UpgradeHandler { - - static final String UNKNOWN_VERSION = "0"; - static final String MIN_SUPPORTED_VERSION = "3.0.0.1"; - - protected Resource projectSource; - protected UpgradeMetaData metaData; - - public BaseUpgradeHandler(Resource projectSource) { - - if (projectSource == null) { - throw new NullPointerException("Null project source"); - } - - this.projectSource = projectSource; - } - - /** - * Creates a single common EntityResolver for all project DataMaps, setting - * it as a namespace for all of them. This is needed for resolving cross-map - * relationships. - */ - protected void attachToNamespace(DataChannelDescriptor channelDescriptor) { - EntityResolver entityResolver = new EntityResolver(channelDescriptor.getDataMaps()); - - for (DataMap map : entityResolver.getDataMaps()) { - map.setNamespace(entityResolver); - } - } - - @Override - public Resource getProjectSource() { - return projectSource; - } - - @Override - public UpgradeMetaData getUpgradeMetaData() { - // no attempts at thread-safety... shouldn't be needed for upgrades - if (metaData == null) { - metaData = loadMetaData(); - } - - return metaData; - } - - @Override - public Resource performUpgrade() throws ConfigurationException { - UpgradeMetaData metaData = getUpgradeMetaData(); - switch (metaData.getUpgradeType()) { - case DOWNGRADE_NEEDED: - throw new ConfigurationException("Downgrade can not be performed"); - case INTERMEDIATE_UPGRADE_NEEDED: - throw new ConfigurationException("Upgrade can not be performed - intermediate version upgrade needed"); - case UPGRADE_NEEDED: - return doPerformUpgrade(metaData); - default: - return getProjectSource(); - } - } - - /** - * Does the actual project upgrade, assuming the caller already verified - * that the upgrade is possible. - * - * @param metaData - * object describing the type of upgrade - */ - protected abstract Resource doPerformUpgrade(UpgradeMetaData metaData) throws ConfigurationException; - - protected abstract String getToVersion(); - - /** - * Creates a metadata object describing the type of upgrade needed. - */ - protected UpgradeMetaData loadMetaData() { - String version = loadProjectVersion(); - - UpgradeMetaData metadata = new UpgradeMetaData(); - metadata.setSupportedVersion(getToVersion()); - metadata.setProjectVersion(version); - - int c1 = compareVersions(version, MIN_SUPPORTED_VERSION); - int c2 = compareVersions(getToVersion(), version); - - if (c1 < 0) { - metadata.setIntermediateUpgradeVersion(MIN_SUPPORTED_VERSION); - metadata.setUpgradeType(UpgradeType.INTERMEDIATE_UPGRADE_NEEDED); - } else if (c2 < 0) { - metadata.setUpgradeType(UpgradeType.DOWNGRADE_NEEDED); - } else if (c2 == 0) { - metadata.setUpgradeType(UpgradeType.UPGRADE_NOT_NEEDED); - } else { - metadata.setUpgradeType(UpgradeType.UPGRADE_NEEDED); - } - - return metadata; - } - - /** - * A default method for quick extraction of the project version from an XML - * file. - */ - protected String loadProjectVersion() { - - RootTagHandler rootHandler = new RootTagHandler(); - URL url = projectSource.getURL(); - - try (InputStream in = url.openStream();) { - - XMLReader parser = Util.createXmlReader(); - - parser.setContentHandler(rootHandler); - parser.setErrorHandler(rootHandler); - parser.parse(new InputSource(in)); - } catch (SAXException e) { - // expected ... handler will terminate as soon as it finds a root - // tag. - } catch (Exception e) { - throw new ConfigurationException("Error reading configuration from %s", e, url); - } - - return rootHandler.projectVersion != null ? rootHandler.projectVersion : UNKNOWN_VERSION; - } - - /** - * Compares two String versions. - */ - protected int compareVersions(String v1, String v2) { - - if (v1.equals(v2)) { - return 0; - } - - double v1Double = decodeVersion(v1); - double v2Double = decodeVersion(v2); - return v1Double < v2Double ? -1 : 1; - } - - protected double decodeVersion(String version) { - if (version == null || version.trim().length() == 0) { - return 0; - } - - // leave the first dot, and treat remaining as a fraction - // remove all non digit chars - StringBuilder buffer = new StringBuilder(version.length()); - boolean dotProcessed = false; - for (int i = 0; i < version.length(); i++) { - char nextChar = version.charAt(i); - if (nextChar == '.' && !dotProcessed) { - dotProcessed = true; - buffer.append('.'); - } else if (Character.isDigit(nextChar)) { - buffer.append(nextChar); - } - } - - return Double.parseDouble(buffer.toString()); - } - - class RootTagHandler extends DefaultHandler { - - private String projectVersion; - - @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - - this.projectVersion = attributes.getValue("", "project-version"); - - // bail right away - we are not interested in reading this to the - // end - throw new SAXException("finished"); - } - } -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DataSourceInfoLoader_3_0_0_1.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DataSourceInfoLoader_3_0_0_1.java b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DataSourceInfoLoader_3_0_0_1.java deleted file mode 100644 index dc52a50..0000000 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DataSourceInfoLoader_3_0_0_1.java +++ /dev/null @@ -1,228 +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.project.upgrade; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.MalformedURLException; -import java.net.URL; - -import org.apache.cayenne.ConfigurationException; -import org.apache.cayenne.configuration.PasswordEncoding; -import org.apache.cayenne.configuration.SAXNestedTagHandler; -import org.apache.cayenne.conn.DataSourceInfo; -import org.apache.cayenne.resource.Resource; -import org.apache.cayenne.util.Util; -import org.xml.sax.Attributes; -import org.xml.sax.ContentHandler; -import org.xml.sax.InputSource; -import org.xml.sax.XMLReader; - -/** - * A loader of XML for the {@link DataSourceInfo} object. The loader is - * compatible with project version 3.0.0.1 and earlier. - * - * @since 3.1 - */ -// TODO: andrus 12.13.2009 - unused yet.. will be used in upgrade manager -class DataSourceInfoLoader_3_0_0_1 { - - public DataSourceInfo load(Resource configurationResource) throws Exception { - - if (configurationResource == null) { - throw new NullPointerException("Null configurationResource"); - } - - DataSourceInfo dataSourceDescriptor = new DataSourceInfo(); - - XMLReader parser = Util.createXmlReader(); - - DriverHandler handler = new DriverHandler(dataSourceDescriptor, parser); - parser.setContentHandler(handler); - parser.setErrorHandler(handler); - parser.parse(new InputSource(configurationResource.getURL().openStream())); - - return dataSourceDescriptor; - } - - private static String passwordFromURL(URL url) { - InputStream inputStream = null; - String password = null; - - try { - inputStream = url.openStream(); - password = passwordFromInputStream(inputStream); - } catch (IOException exception) { - // ignore - } - - return password; - } - - private static String passwordFromInputStream(InputStream inputStream) { - String password = null; - - try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));) { - - password = bufferedReader.readLine(); - } catch (IOException exception) { - // ignoring... - } finally { - - try { - inputStream.close(); - } catch (IOException exception) { - } - } - - return password; - } - - private class DriverHandler extends SAXNestedTagHandler { - - private DataSourceInfo dataSourceDescriptor; - - DriverHandler(DataSourceInfo dataSourceDescriptor, XMLReader parser) { - super(parser, null); - this.dataSourceDescriptor = dataSourceDescriptor; - } - - @Override - protected ContentHandler createChildTagHandler(String namespaceURI, String localName, String name, - Attributes attributes) { - - if (localName.equals("driver")) { - String className = attributes.getValue("", "class"); - dataSourceDescriptor.setJdbcDriver(className); - return new DriverChildrenHandler(parser, this); - } - - return super.createChildTagHandler(namespaceURI, localName, name, attributes); - } - } - - private class DriverChildrenHandler extends SAXNestedTagHandler { - - private DataSourceInfo dataSourceDescriptor; - - DriverChildrenHandler(XMLReader parser, DriverHandler parentHandler) { - super(parser, parentHandler); - this.dataSourceDescriptor = parentHandler.dataSourceDescriptor; - } - - @Override - protected ContentHandler createChildTagHandler(String namespaceURI, String localName, String name, - Attributes attributes) { - - if (localName.equals("login")) { - - String encoderClass = attributes.getValue("encoderClass"); - - String encoderKey = attributes.getValue("encoderKey"); - if (encoderKey == null) { - encoderKey = attributes.getValue("encoderSalt"); - } - - String password = attributes.getValue("password"); - String passwordLocation = attributes.getValue("passwordLocation"); - String passwordSource = attributes.getValue("passwordSource"); - if (passwordSource == null) { - passwordSource = DataSourceInfo.PASSWORD_LOCATION_MODEL; - } - - String username = attributes.getValue("userName"); - - dataSourceDescriptor.setPasswordEncoderClass(encoderClass); - dataSourceDescriptor.setPasswordEncoderKey(encoderKey); - dataSourceDescriptor.setPasswordLocation(passwordLocation); - dataSourceDescriptor.setPasswordSource(passwordSource); - dataSourceDescriptor.setUserName(username); - - // Replace {} in passwordSource with encoderSalt -- useful for - // EXECUTABLE - // & URL options - if (encoderKey != null) { - passwordSource = passwordSource.replaceAll("\\{\\}", encoderKey); - } - - PasswordEncoding passwordEncoder = dataSourceDescriptor.getPasswordEncoder(); - - if (passwordLocation != null) { - if (passwordLocation.equals(DataSourceInfo.PASSWORD_LOCATION_CLASSPATH)) { - - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - URL url = classLoader.getResource(username); - if (url != null) { - password = passwordFromURL(url); - } else { - // ignoring.. - } - } else if (passwordLocation.equals(DataSourceInfo.PASSWORD_LOCATION_URL)) { - try { - password = passwordFromURL(new URL(passwordSource)); - } catch (MalformedURLException exception) { - // ignoring... - } - } else if (passwordLocation.equals(DataSourceInfo.PASSWORD_LOCATION_EXECUTABLE)) { - if (passwordSource != null) { - try { - Process process = Runtime.getRuntime().exec(passwordSource); - password = passwordFromInputStream(process.getInputStream()); - process.waitFor(); - } catch (IOException exception) { - // ignoring... - } catch (InterruptedException exception) { - // ignoring... - } - } - } - } - - if (password != null && passwordEncoder != null) { - dataSourceDescriptor.setPassword(passwordEncoder.decodePassword(password, encoderKey)); - } - } else if (localName.equals("url")) { - dataSourceDescriptor.setDataSourceUrl(attributes.getValue("value")); - } else if (localName.equals("connectionPool")) { - String min = attributes.getValue("min"); - if (min != null) { - try { - dataSourceDescriptor.setMinConnections(Integer.parseInt(min)); - } catch (NumberFormatException nfex) { - throw new ConfigurationException("Non-numeric 'min' attribute '%s'", nfex, min); - } - } - - String max = attributes.getValue("max"); - if (max != null) { - try { - dataSourceDescriptor.setMaxConnections(Integer.parseInt(max)); - } catch (NumberFormatException nfex) { - throw new ConfigurationException("Non-numeric 'max' attribute '%s'", nfex, max); - } - } - } - - return super.createChildTagHandler(namespaceURI, localName, name, attributes); - } - } - -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DefaultUpgradeService.java ---------------------------------------------------------------------- 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/DefaultUpgradeService.java new file mode 100644 index 0000000..aafb3d2 --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DefaultUpgradeService.java @@ -0,0 +1,318 @@ +/***************************************************************** + * 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.project.upgrade; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; + +import org.apache.cayenne.ConfigurationException; +import org.apache.cayenne.configuration.ConfigurationTree; +import org.apache.cayenne.configuration.DataChannelDescriptor; +import org.apache.cayenne.configuration.DataChannelDescriptorLoader; +import org.apache.cayenne.di.Inject; +import org.apache.cayenne.project.Project; +import org.apache.cayenne.project.ProjectSaver; +import org.apache.cayenne.project.upgrade.handlers.UpgradeHandler; +import org.apache.cayenne.resource.Resource; +import org.apache.cayenne.util.Util; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + +/** + * + * 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 + * + * 2. This cycle can be used by ServerRuntime 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 + * + * @since 4.1 + */ +public class DefaultUpgradeService implements UpgradeService { + + public static final String UNKNOWN_VERSION = "0"; + public static final String MIN_SUPPORTED_VERSION = "6"; + + TreeMap<String, UpgradeHandler> handlers = new TreeMap<>(VersionComparator.INSTANCE); + + @Inject + private ProjectSaver projectSaver; + + @Inject + private DataChannelDescriptorLoader loader; + + public DefaultUpgradeService(@Inject List<UpgradeHandler> handlerList) { + for(UpgradeHandler handler : handlerList) { + handlers.put(handler.getVersion(), handler); + } + } + + @Override + public UpgradeMetaData getUpgradeType(Resource resource) { + UpgradeMetaData metaData = new UpgradeMetaData(); + + String version = loadProjectVersion(resource); + metaData.setProjectVersion(version); + metaData.setSupportedVersion(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; + } + + int c2 = VersionComparator.INSTANCE.compare(String.valueOf(Project.VERSION), version); + if (c2 < 0) { + metaData.setUpgradeType(UpgradeType.DOWNGRADE_NEEDED); + } else if (c2 == 0) { + metaData.setUpgradeType(UpgradeType.UPGRADE_NOT_NEEDED); + } else { + metaData.setUpgradeType(UpgradeType.UPGRADE_NEEDED); + } + return metaData; + } + + 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)) { + found = true; + continue; + } + if(!found) { + continue; + } + + handlerList.add(entry.getValue()); + } + + return handlerList; + } + + @Override + public Resource upgradeProject(Resource resource) { + List<UpgradeHandler> handlerList = getHandlersForVersion(loadProjectVersion(resource)); + + resource = upgradeDOM(resource, handlerList); + upgradeModel(resource, handlerList); + + return resource; + } + + Resource upgradeDOM(Resource resource, List<UpgradeHandler> handlerList) { + // Load DOM for all resources + Document projectDocument = readDocument(resource); + UpgradeUnit projectUnit = new UpgradeUnit(resource, projectDocument); + + List<Resource> dataMapResources = getAdditionalDatamapResources(projectUnit); + List<UpgradeUnit> upgradeUnits = new ArrayList<>(dataMapResources.size()); + for (Resource dataMapResource : dataMapResources) { + upgradeUnits.add(new UpgradeUnit(dataMapResource, readDocument(dataMapResource))); + } + + // Update DOM + for(UpgradeHandler handler : handlerList) { + handler.processProjectDom(projectUnit); + for(UpgradeUnit dataMapUnit : upgradeUnits) { + handler.processDataMapDom(dataMapUnit); + } + } + + // Save modified DOM back to original files + saveDocument(projectUnit); + for(UpgradeUnit dataMapUnit : upgradeUnits) { + saveDocument(dataMapUnit); + } + + return projectUnit.getResource(); + } + + void upgradeModel(Resource resource, List<UpgradeHandler> handlerList) { + // Load Model back from the update XML + ConfigurationTree<DataChannelDescriptor> configurationTree = loader.load(resource); + + // Update model level if needed + for(UpgradeHandler handler : handlerList) { + handler.processModel(configurationTree.getRootNode()); + } + + // Save project once again via project saver, this will normalize XML to minimize final diff + Project project = new Project(configurationTree); + projectSaver.save(project); + } + + List<Resource> getAdditionalDatamapResources(UpgradeUnit upgradeUnit) { + List<Resource> resources = new ArrayList<>(); + try { + XPath xpath = XPathFactory.newInstance().newXPath(); + NodeList nodes = (NodeList) xpath.evaluate("/domain/map/@name", upgradeUnit.getDocument(), XPathConstants.NODESET); + for (int i = 0; i < nodes.getLength(); i++) { + Node mapNode = nodes.item(i); + // in version 3.0.0.1 and earlier map tag had attribute location, + // but it was always equal to data map name + ".map.xml" + Resource mapResource = upgradeUnit.getResource().getRelativeResource(mapNode.getNodeValue() + ".map.xml"); + resources.add(mapResource); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + return resources; + } + + protected void saveDocument(UpgradeUnit upgradeUnit) { + try { + Source input = new DOMSource(upgradeUnit.getDocument()); + Result output = new StreamResult(Util.toFile(upgradeUnit.getResource().getURL())); + + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + transformer.transform(input, output); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + protected Document readDocument(Resource resource) { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(false); + try { + DocumentBuilder domBuilder = documentBuilderFactory.newDocumentBuilder(); + try (InputStream inputStream = resource.getURL().openStream()) { + return domBuilder.parse(inputStream); + } catch (IOException | SAXException e) { + throw new ConfigurationException("Error loading configuration from %s", e, resource); + } + } catch (ParserConfigurationException e) { + throw new ConfigurationException(e); + } + } + + /** + * A default method for quick extraction of the project version from an XML + * file. + */ + protected String loadProjectVersion(Resource resource) { + + RootTagHandler rootHandler = new RootTagHandler(); + URL url = resource.getURL(); + try (InputStream in = url.openStream()) { + XMLReader parser = Util.createXmlReader(); + parser.setContentHandler(rootHandler); + parser.setErrorHandler(rootHandler); + parser.parse(new InputSource(in)); + } catch (SAXException e) { + // expected... handler will terminate as soon as it finds a root tag. + } catch (Exception e) { + throw new ConfigurationException("Error reading configuration from %s", e, url); + } + + return rootHandler.projectVersion != null ? rootHandler.projectVersion : UNKNOWN_VERSION; + } + + protected static double decodeVersion(String version) { + if (version == null || version.trim().length() == 0) { + return 0; + } + + // leave the first dot, and treat remaining as a fraction + // remove all non digit chars + StringBuilder buffer = new StringBuilder(version.length()); + boolean dotProcessed = false; + for (int i = 0; i < version.length(); i++) { + char nextChar = version.charAt(i); + if (nextChar == '.' && !dotProcessed) { + dotProcessed = true; + buffer.append('.'); + } else if (Character.isDigit(nextChar)) { + buffer.append(nextChar); + } + } + + return Double.parseDouble(buffer.toString()); + } + + private static class VersionComparator implements Comparator<String> { + + private static final VersionComparator INSTANCE = new VersionComparator(); + + @Override + public int compare(String o1, String o2) { + if (o1.equals(o2)) { + return 0; + } + double v1Double = decodeVersion(o1); + double v2Double = decodeVersion(o2); + return v1Double < v2Double ? -1 : 1; + } + } + + class RootTagHandler extends DefaultHandler { + + private String projectVersion; + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + + this.projectVersion = attributes.getValue("", "project-version"); + + // bail right away - we are not interested in reading this to the end + throw new SAXException("finished"); + } + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/ProjectUpgrader.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/ProjectUpgrader.java b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/ProjectUpgrader.java deleted file mode 100644 index 8eac85f..0000000 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/ProjectUpgrader.java +++ /dev/null @@ -1,34 +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.project.upgrade; - -import org.apache.cayenne.resource.Resource; - -/** - * Defines API of an upgrade handler for Cayenne projects. - * - * @since 3.1 - */ -public interface ProjectUpgrader { - - /** - * Returns an upgrade handler to process upgrades of a given project. - */ - UpgradeHandler getUpgradeHandler(Resource projectSource); -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeHandler.java b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeHandler.java deleted file mode 100644 index e307b90..0000000 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeHandler.java +++ /dev/null @@ -1,57 +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.project.upgrade; - -import org.apache.cayenne.ConfigurationException; -import org.apache.cayenne.resource.Resource; - -/** - * A stateful helper object for analyzing the projects and performing upgrades. - * - * @since 3.1 - */ -public interface UpgradeHandler { - - /** - * Returns the original configuration source for the project before the upgrade. - */ - Resource getProjectSource(); - - /** - * Returns a metadata object containing information about the upgrade to be performed. - * Users should call this method before invoking {@link #performUpgrade()}, to make - * sure upgrade is needed and possible. Tools (like CayenneModeler) may use this - * object to build user-friendly messages asking for user input on the upgrade. - */ - UpgradeMetaData getUpgradeMetaData(); - - /** - * Performs an in-place project configuration upgrade, throwing a - * {@link ConfigurationException} if the upgrade fails. Before doing the upgrade, - * check the handler {@link UpgradeMetaData}. Upgrades will succeed only for projects - * that have {@link UpgradeType#UPGRADE_NEEDED} or - * {@link UpgradeType#UPGRADE_NOT_NEEDED} statuses. In the later case of course, - * upgrade will simply be skipped. - * - * @return a configuration Resource for the upgraded project. Depending on the upgrade - * type, it may be the same resource as the original configuration, or a - * totally different resource. - */ - Resource performUpgrade() throws ConfigurationException; -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeService.java ---------------------------------------------------------------------- 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/UpgradeService.java new file mode 100644 index 0000000..a9cb480 --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeService.java @@ -0,0 +1,33 @@ +/***************************************************************** + * 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.project.upgrade; + +import org.apache.cayenne.resource.Resource; + +/** + * @since 4.1 + */ +public interface UpgradeService { + + UpgradeMetaData getUpgradeType(Resource resource); + + Resource upgradeProject(Resource resource); + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeUnit.java ---------------------------------------------------------------------- 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/UpgradeUnit.java new file mode 100644 index 0000000..3fb0b95 --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/UpgradeUnit.java @@ -0,0 +1,54 @@ +/***************************************************************** + * 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.project.upgrade; + +import org.apache.cayenne.resource.Resource; +import org.w3c.dom.Document; + +/** + * @since 4.1 + */ +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 void setResource(Resource resource) { + this.resource = resource; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler.java ---------------------------------------------------------------------- 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 new file mode 100644 index 0000000..535ec8c --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler.java @@ -0,0 +1,58 @@ +/***************************************************************** + * 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.project.upgrade.handlers; + +import org.apache.cayenne.configuration.DataChannelDescriptor; +import org.apache.cayenne.project.upgrade.UpgradeUnit; + +/** + * Interface that upgrade handlers should implement. + * Implementation also should be injected into DI stack in right order. + * + * @since 4.1 + */ +public interface UpgradeHandler { + + /** + * @return target version for this handler + */ + String getVersion(); + + /** + * Process DOM for the project root file (e.g. cayenne-project.xml) + */ + void processProjectDom(UpgradeUnit upgradeUnit); + + /** + * Process DOM for the data map file (e.g. datamap.map.xml) + */ + void processDataMapDom(UpgradeUnit upgradeUnit); + + /** + * This method should be avoided as much as possible, as + * using this method will make upgrade process not future proof and + * will require refactoring if model should change. + */ + void processModel(DataChannelDescriptor dataChannelDescriptor); + // should be this really, but no Java 8 yet: + //default void processModel(DataChannelDescriptor dataChannelDescriptor) {} + + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V10.java ---------------------------------------------------------------------- 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 new file mode 100644 index 0000000..44b55b6 --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V10.java @@ -0,0 +1,68 @@ +/***************************************************************** + * 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.project.upgrade.handlers; + +import org.apache.cayenne.configuration.DataChannelDescriptor; +import org.apache.cayenne.project.upgrade.UpgradeUnit; +import org.w3c.dom.Element; + +/** + * Upgrade handler for the project version "10" introduced by 4.1.M1 release. + * Changes highlight: + * - strict schema for domain (e.g. main project document) + * - new schema for data map allowing usage of additional elements (e.g. XML extensions) + * + * @since 4.1 + */ +public class UpgradeHandler_V10 implements UpgradeHandler { + + @Override + public String getVersion() { + return "10"; + } + + @Override + public void processProjectDom(UpgradeUnit upgradeUnit) { + Element domain = upgradeUnit.getDocument().getDocumentElement(); + // introduce xml namespace and schema for domain + domain.setAttribute("xmlns","http://cayenne.apache.org/schema/10/domain"); + domain.setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance"); + domain.setAttribute("xsi:schemaLocation", "http://cayenne.apache.org/schema/10/domain " + + "http://cayenne.apache.org/schema/10/domain.xsd"); + // update version + domain.setAttribute("project-version", getVersion()); + } + + @Override + public void processDataMapDom(UpgradeUnit upgradeUnit) { + Element dataMap = upgradeUnit.getDocument().getDocumentElement(); + // update schema + dataMap.setAttribute("xmlns","http://cayenne.apache.org/schema/10/modelMap"); + dataMap.setAttribute("xsi:schemaLocation", "http://cayenne.apache.org/schema/10/modelMap " + + "http://cayenne.apache.org/schema/10/modelMap.xsd"); + // update version + dataMap.setAttribute("project-version", getVersion()); + } + + @Override + public void processModel(DataChannelDescriptor dataChannelDescriptor) { + // noop + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/38553b16/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V7.java ---------------------------------------------------------------------- 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 new file mode 100644 index 0000000..174e660 --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V7.java @@ -0,0 +1,109 @@ +/***************************************************************** + * 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.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.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * @since 4.1 + */ +public class UpgradeHandler_V7 implements UpgradeHandler { + + @Override + public String getVersion() { + return "7"; + } + + @Override + public void processProjectDom(UpgradeUnit upgradeUnit) { + Element domain = upgradeUnit.getDocument().getDocumentElement(); + domain.setAttribute("project-version", getVersion()); + + XPath xpath = XPathFactory.newInstance().newXPath(); + Node node; + try { + node = (Node) xpath.evaluate("/domain/property[@name='cayenne.DataDomain.usingExternalTransactions']", + upgradeUnit.getDocument(), XPathConstants.NODE); + }catch (Exception ex) { + return; + } + + if(node != null) { + domain.removeChild(node); + } + } + + @Override + public void processDataMapDom(UpgradeUnit upgradeUnit) { + Element dataMap = upgradeUnit.getDocument().getDocumentElement(); + dataMap.setAttribute("xmlns","http://cayenne.apache.org/schema/7/modelMap"); + dataMap.setAttribute("xsi:schemaLocation", "http://cayenne.apache.org/schema/7/modelMap " + + "http://cayenne.apache.org/schema/7/modelMap.xsd"); + dataMap.setAttribute("project-version", getVersion()); + } + + @Override + public void processModel(DataChannelDescriptor dataChannelDescriptor) { + for (DataMap dataMap : dataChannelDescriptor.getDataMaps()) { + // if objEntity has super entity, then checks it for duplicated attributes + for (ObjEntity objEntity : dataMap.getObjEntities()) { + ObjEntity superEntity = objEntity.getSuperEntity(); + if (superEntity != null) { + removeShadowAttributes(objEntity, superEntity); + } + } + } + } + + /** + * Remove attributes from objEntity, if superEntity has attributes with same names. + */ + private void removeShadowAttributes(ObjEntity objEntity, ObjEntity superEntity) { + + List<String> delList = new ArrayList<>(); + + // if subAttr and superAttr have same names, adds subAttr to delList + for (ObjAttribute subAttr : objEntity.getDeclaredAttributes()) { + for (ObjAttribute superAttr : superEntity.getAttributes()) { + if (subAttr.getName().equals(superAttr.getName())) { + delList.add(subAttr.getName()); + } + } + } + + if (!delList.isEmpty()) { + for (String i : delList) { + objEntity.removeAttribute(i); + } + } + } +}
