CAY-2116 Split schema synchronization code in a separate module * more refactoring
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/ad944755 Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/ad944755 Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/ad944755 Branch: refs/heads/master Commit: ad9447556dd5e12b5e7f94a517bab1df7f50a5d3 Parents: 2df9f66 Author: Andrus Adamchik <[email protected]> Authored: Fri Sep 30 20:45:47 2016 +0300 Committer: Andrus Adamchik <[email protected]> Committed: Fri Sep 30 20:58:07 2016 +0300 ---------------------------------------------------------------------- .../dbsync/merge/CreateTableToModel.java | 24 +- .../dbsync/merge/EntityMergeSupport.java | 8 +- .../dbsync/naming/DuplicateNameResolver.java | 68 ++++++ .../cayenne/dbsync/naming/NameChecker.java | 36 +++ .../cayenne/dbsync/naming/NameCheckers.java | 223 +++++++++++++++++++ .../cayenne/dbsync/reverse/db/DbLoader.java | 8 +- .../reverse/db/ManyToManyCandidateEntity.java | 6 +- .../naming/DefaultObjectNameGenerator.java | 11 +- .../naming/LegacyObjectNameGenerator.java | 16 +- .../dbsync/reverse/naming/NameConverter.java | 154 ------------- .../cayenne/dbsync/naming/NameCheckersTest.java | 204 +++++++++++++++++ .../reverse/naming/NameConverterTest.java | 115 ---------- .../java/org/apache/cayenne/map/ObjEntity.java | 2 +- .../apache/cayenne/map/naming/NameChecker.java | 36 --- .../apache/cayenne/map/naming/NameCheckers.java | 221 ------------------ .../cayenne/map/naming/UniqueNameGenerator.java | 91 -------- .../main/java/org/apache/cayenne/util/Util.java | 126 +++++++++-- .../cayenne/map/naming/NameCheckersTest.java | 204 ----------------- .../java/org/apache/cayenne/util/UtilTest.java | 38 ++++ .../cayenne/gen/ClientDataMapArtifact.java | 3 +- .../org/apache/cayenne/gen/DataMapArtifact.java | 4 +- .../org/apache/cayenne/gen/DataMapUtils.java | 30 +-- .../org/apache/cayenne/gen/StringUtils.java | 23 +- .../org/apache/cayenne/gen/StringUtilsTest.java | 49 ++++ .../modeler/action/CreateAttributeAction.java | 10 +- .../action/CreateCallbackMethodAction.java | 15 +- .../modeler/action/CreateDataMapAction.java | 6 +- .../modeler/action/CreateDbEntityAction.java | 6 +- .../modeler/action/CreateEmbeddableAction.java | 6 +- .../modeler/action/CreateNodeAction.java | 6 +- .../modeler/action/CreateObjEntityAction.java | 12 +- .../modeler/action/CreateProcedureAction.java | 6 +- .../action/CreateProcedureParameterAction.java | 6 +- .../action/CreateRelationshipAction.java | 8 +- .../modeler/action/ImportDataMapAction.java | 8 +- .../modeler/action/ImportEOModelAction.java | 6 +- .../modeler/action/NewProjectAction.java | 6 +- .../cayenne/modeler/action/PasteAction.java | 40 ++-- .../action/ReverseEngineeringAction.java | 8 +- .../dialog/ResolveDbRelationshipDialog.java | 8 +- .../modeler/dialog/db/DbLoaderHelper.java | 10 +- .../cayenne/modeler/dialog/query/QueryType.java | 6 +- .../cayenne/modeler/editor/CallbackType.java | 32 +-- modeler/cayenne-wocompat/pom.xml | 6 + .../cayenne/wocompat/EOModelProcessor.java | 39 ++-- 45 files changed, 933 insertions(+), 1017 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/CreateTableToModel.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/CreateTableToModel.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/CreateTableToModel.java index 0997e9b..436a1f5 100644 --- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/CreateTableToModel.java +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/CreateTableToModel.java @@ -19,21 +19,22 @@ package org.apache.cayenne.dbsync.merge; import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.dbsync.naming.DuplicateNameResolver; +import org.apache.cayenne.dbsync.naming.NameCheckers; +import org.apache.cayenne.dbsync.reverse.naming.DefaultObjectNameGenerator; import org.apache.cayenne.map.DataMap; import org.apache.cayenne.map.DbEntity; import org.apache.cayenne.map.ObjEntity; -import org.apache.cayenne.dbsync.reverse.naming.NameConverter; /** * A {@link MergerToken} to add a {@link DbEntity} to a {@link DataMap} - * */ public class CreateTableToModel extends AbstractToModelToken.Entity { /** * className if {@link ObjEntity} should be generated with a - * special class name. - * Setting this to <code>null</code>, because by default class name should be generated + * special class name. + * Setting this to <code>null</code>, because by default class name should be generated */ private String objEntityClassName = null; //CayenneDataObject.class.getName(); @@ -53,11 +54,18 @@ public class CreateTableToModel extends AbstractToModelToken.Entity { } public void execute(MergerContext mergerContext) { + DbEntity dbEntity = getEntity(); + DataMap map = mergerContext.getDataMap(); - map.addDbEntity(getEntity()); + map.addDbEntity(dbEntity); // create a ObjEntity - String objEntityName = NameConverter.underscoredToJava(getEntity().getName(), true); + + // TODO: proper name generator must be injected + + String objEntityName = new DefaultObjectNameGenerator().createObjEntityName(dbEntity); + objEntityName = DuplicateNameResolver.resolve(NameCheckers.objEntity, dbEntity.getDataMap(), objEntityName); + // this loop will terminate even if no valid name is found // to prevent loader from looping forever (though such case is very unlikely) String baseName = objEntityName; @@ -77,12 +85,12 @@ public class CreateTableToModel extends AbstractToModelToken.Entity { objEntity.setClassName(className); objEntity.setSuperClassName(map.getDefaultSuperclass()); - + if (map.isClientSupported()) { objEntity.setClientClassName(map.getNameWithDefaultClientPackage(objEntity.getName())); objEntity.setClientSuperClassName(map.getDefaultClientSuperclass()); } - + map.addObjEntity(objEntity); // presumably there are no other ObjEntities pointing to this DbEntity, so syncing just this one... http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EntityMergeSupport.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EntityMergeSupport.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EntityMergeSupport.java index 7db68af..e055883 100644 --- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EntityMergeSupport.java +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EntityMergeSupport.java @@ -29,9 +29,9 @@ import org.apache.cayenne.map.Entity; import org.apache.cayenne.map.ObjAttribute; import org.apache.cayenne.map.ObjEntity; import org.apache.cayenne.map.ObjRelationship; -import org.apache.cayenne.map.naming.UniqueNameGenerator; +import org.apache.cayenne.dbsync.naming.DuplicateNameResolver; import org.apache.cayenne.dbsync.reverse.naming.LegacyObjectNameGenerator; -import org.apache.cayenne.map.naming.NameCheckers; +import org.apache.cayenne.dbsync.naming.NameCheckers; import org.apache.cayenne.dbsync.reverse.naming.ObjectNameGenerator; import org.apache.cayenne.util.DeleteRuleUpdater; import org.apache.cayenne.util.EntityMergeListener; @@ -205,7 +205,7 @@ public class EntityMergeSupport { private boolean createObjRelationship(ObjEntity entity, DbRelationship dr, String targetEntityName) { String relationshipName = nameGenerator.createObjRelationshipName(dr); - relationshipName = UniqueNameGenerator.generate(NameCheckers.objRelationship, entity, relationshipName); + relationshipName = DuplicateNameResolver.resolve(NameCheckers.objRelationship, entity, relationshipName); ObjRelationship or = new ObjRelationship(relationshipName); or.addDbRelationship(dr); @@ -279,7 +279,7 @@ public class EntityMergeSupport { } private void addMissingAttribute(ObjEntity entity, DbAttribute da) { - String attrName = UniqueNameGenerator.generate(NameCheckers.objAttribute, entity, + String attrName = DuplicateNameResolver.resolve(NameCheckers.objAttribute, entity, nameGenerator.createObjAttributeName(da)); String type = TypesMapping.getJavaBySqlType(da.getType()); http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/naming/DuplicateNameResolver.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/naming/DuplicateNameResolver.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/naming/DuplicateNameResolver.java new file mode 100644 index 0000000..3f55d8f --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/naming/DuplicateNameResolver.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.dbsync.naming; + +import org.apache.cayenne.map.DataMap; + +/** + * A generator of unique names for the various model objects. + * + * @since 4.0 + */ +public class DuplicateNameResolver { + + private static final String DEFAULT_PATTERN = "%s%d"; + + public static String resolve(NameChecker checker) { + return resolve(checker, DEFAULT_PATTERN, null, null); + } + + public static String resolve(NameChecker checker, Object context) { + return resolve(checker, DEFAULT_PATTERN, context, null); + } + + public static String resolve(NameChecker checker, Object context, String baseName) { + return resolve(checker, DEFAULT_PATTERN, context, baseName); + } + + public static String resolve(NameChecker nameChecker, String pattern, Object context, String baseName) { + + if (baseName == null) { + baseName = nameChecker.baseName(); + } + + String resolved = doResolve(nameChecker, pattern, context, baseName); + + // TODO ugly hack with cast... something more OO is in order + return (nameChecker == NameCheckers.embeddable) + ? ((DataMap) context).getNameWithDefaultPackage(resolved) : resolved; + } + + + private static String doResolve(NameChecker nameChecker, String pattern, Object namingContext, String baseName) { + int c = 1; + String name = baseName; + while (nameChecker.isNameInUse(namingContext, name)) { + name = String.format(pattern, baseName, c++); + } + + return name; + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/naming/NameChecker.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/naming/NameChecker.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/naming/NameChecker.java new file mode 100644 index 0000000..ade1ec5 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/naming/NameChecker.java @@ -0,0 +1,36 @@ +/***************************************************************** + * 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.dbsync.naming; + +/** + * @since 4.0 + */ +public interface NameChecker { + + /** + * Returns a base default name, like "UntitledEntity", etc. + */ + String baseName(); + + /** + * Checks if the name is already taken by another sibling in the same + * context. + */ + boolean isNameInUse(Object namingContext, String name); +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/naming/NameCheckers.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/naming/NameCheckers.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/naming/NameCheckers.java new file mode 100644 index 0000000..fca1734 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/naming/NameCheckers.java @@ -0,0 +1,223 @@ +/***************************************************************** + * 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.dbsync.naming; + +import org.apache.cayenne.access.DataDomain; +import org.apache.cayenne.configuration.DataChannelDescriptor; +import org.apache.cayenne.configuration.DataNodeDescriptor; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.Embeddable; +import org.apache.cayenne.map.Entity; +import org.apache.cayenne.map.ObjEntity; +import org.apache.cayenne.map.Procedure; +import org.apache.cayenne.map.ProcedureParameter; +import org.apache.commons.lang.StringUtils; + +/** + * A set of default {@link NameChecker} objects for the known model objects. + * + * @since 4.0 + */ +public enum NameCheckers implements NameChecker { + + dataChannelDescriptor("project") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + return false; + } + }, + + dataMap("datamap") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + // null context is a situation when DataMap is a + // top level object of the project + if (namingContext == null) { + return false; + } + + if (namingContext instanceof DataDomain) { + DataDomain domain = (DataDomain) namingContext; + return domain.getDataMap(name) != null; + } + + if (namingContext instanceof DataChannelDescriptor) { + DataChannelDescriptor domain = (DataChannelDescriptor) namingContext; + return domain.getDataMap(name) != null; + } + return false; + } + }, + + reverseEngineering("reverseEngineering") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + if (namingContext == null) { + return false; + } + + for (DataMap dataMap : ((DataChannelDescriptor) namingContext).getDataMaps()) { + if (dataMap != null && dataMap.getReverseEngineering() != null && + dataMap.getReverseEngineering().getName() != null && dataMap.getReverseEngineering().getName().equals(name)) { + return true; + } + } + return false; + } + }, + + objEntity("ObjEntity") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + DataMap map = (DataMap) namingContext; + return map.getObjEntity(name) != null; + } + }, + + embeddable("Embeddable") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + DataMap map = (DataMap) namingContext; + return map.getEmbeddable(map.getNameWithDefaultPackage(name)) != null; + } + }, + + embeddableAttribute("untitledAttr") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + Embeddable emb = (Embeddable) namingContext; + return emb.getAttribute(name) != null; + } + }, + + dbEntity("db_entity") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + DataMap map = (DataMap) namingContext; + return map.getDbEntity(name) != null; + } + }, + + procedureParameter("UntitledProcedureParameter") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + + // it doesn't matter if we create a parameter with + // a duplicate name.. parameters are positional anyway.. + // still try to use unique names for visual consistency + Procedure procedure = (Procedure) namingContext; + for (final ProcedureParameter parameter : procedure + .getCallParameters()) { + if (name.equals(parameter.getName())) { + return true; + } + } + + return false; + } + }, + + procedure("procedure") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + DataMap map = (DataMap) namingContext; + return map.getProcedure(name) != null; + } + }, + + query("query") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + DataMap map = (DataMap) namingContext; + return map.getQueryDescriptor(name) != null; + } + }, + + objAttribute("untitledAttr") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + return objRelationship.isNameInUse(namingContext, name); + } + }, + + dbAttribute("untitledAttr") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + Entity ent = (Entity) namingContext; + return ent.getAttribute(name) != null + || ent.getRelationship(name) != null; + } + }, + + dataNodeDescriptor("datanode") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + DataChannelDescriptor domain = (DataChannelDescriptor) namingContext; + for (DataNodeDescriptor dataNodeDescriptor : domain + .getNodeDescriptors()) { + if (dataNodeDescriptor.getName().equals(name)) { + return true; + } + } + return false; + } + }, + + objRelationship("untitledRel") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + ObjEntity ent = (ObjEntity) namingContext; + return dbAttribute.isNameInUse(namingContext, name) + || ent.getCallbackMethods().contains( + "get" + StringUtils.capitalize(name)); + } + }, + + dbRelationship("untitledRel") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + return dbAttribute.isNameInUse(namingContext, name); + } + }, + + objCallbackMethod("ObjCallbackMethod") { + @Override + public boolean isNameInUse(Object namingContext, String name) { + ObjEntity ent = (ObjEntity) namingContext; + + return name.startsWith("get") + && dbAttribute.isNameInUse(namingContext, + StringUtils.uncapitalize(name.substring(3))) + || ent.getCallbackMethods().contains(name); + } + }; + + private final String baseName; + + NameCheckers(String baseName) { + this.baseName = baseName; + } + + @Override + public String baseName() { + return baseName; + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoader.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoader.java index 5f233cd..44b9fb3 100644 --- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoader.java +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoader.java @@ -34,9 +34,9 @@ import org.apache.cayenne.map.DbRelationshipDetected; import org.apache.cayenne.map.ObjEntity; import org.apache.cayenne.map.Procedure; import org.apache.cayenne.map.ProcedureParameter; -import org.apache.cayenne.map.naming.UniqueNameGenerator; +import org.apache.cayenne.dbsync.naming.DuplicateNameResolver; import org.apache.cayenne.dbsync.reverse.naming.LegacyObjectNameGenerator; -import org.apache.cayenne.map.naming.NameCheckers; +import org.apache.cayenne.dbsync.naming.NameCheckers; import org.apache.cayenne.dbsync.reverse.naming.ObjectNameGenerator; import org.apache.cayenne.util.EqualsBuilder; import org.apache.commons.logging.Log; @@ -133,7 +133,7 @@ public class DbLoader { continue; } - String objEntityName = UniqueNameGenerator.generate(NameCheckers.objEntity, map, + String objEntityName = DuplicateNameResolver.resolve(NameCheckers.objEntity, map, nameGenerator.createObjEntityName(dbEntity)); ObjEntity objEntity = new ObjEntity(objEntityName); @@ -439,7 +439,7 @@ public class DbLoader { private String generateName(DbEntity entity, ExportedKey key, boolean toMany) { String forwardPreferredName = nameGenerator.createDbRelationshipName(key, toMany); - return UniqueNameGenerator.generate(NameCheckers.dbRelationship, entity, forwardPreferredName); + return DuplicateNameResolver.resolve(NameCheckers.dbRelationship, entity, forwardPreferredName); } private void fireObjEntitiesAddedEvents(Collection<ObjEntity> loadedObjEntities) { http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/ManyToManyCandidateEntity.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/ManyToManyCandidateEntity.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/ManyToManyCandidateEntity.java index 06c7d82..85af6a4 100644 --- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/ManyToManyCandidateEntity.java +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/ManyToManyCandidateEntity.java @@ -21,8 +21,8 @@ package org.apache.cayenne.dbsync.reverse.db; import org.apache.cayenne.map.DbRelationship; import org.apache.cayenne.map.ObjEntity; import org.apache.cayenne.map.ObjRelationship; -import org.apache.cayenne.map.naming.UniqueNameGenerator; -import org.apache.cayenne.map.naming.NameCheckers; +import org.apache.cayenne.dbsync.naming.DuplicateNameResolver; +import org.apache.cayenne.dbsync.naming.NameCheckers; import org.apache.cayenne.dbsync.reverse.naming.ObjectNameGenerator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -113,7 +113,7 @@ class ManyToManyCandidateEntity { (short) 1); ObjRelationship newRelationship = new ObjRelationship(); - newRelationship.setName(UniqueNameGenerator.generate(NameCheckers.objRelationship, srcEntity, + newRelationship.setName(DuplicateNameResolver.resolve(NameCheckers.objRelationship, srcEntity, nameGenerator.createDbRelationshipName(key, true))); newRelationship.setSourceEntity(srcEntity); http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/naming/DefaultObjectNameGenerator.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/naming/DefaultObjectNameGenerator.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/naming/DefaultObjectNameGenerator.java index d299338..a2d2264 100644 --- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/naming/DefaultObjectNameGenerator.java +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/naming/DefaultObjectNameGenerator.java @@ -18,10 +18,11 @@ ****************************************************************/ package org.apache.cayenne.dbsync.reverse.naming; +import org.apache.cayenne.dbsync.reverse.db.ExportedKey; import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.map.DbEntity; import org.apache.cayenne.map.DbRelationship; -import org.apache.cayenne.dbsync.reverse.db.ExportedKey; +import org.apache.cayenne.util.Util; import org.jvnet.inflector.Noun; import java.util.Locale; @@ -73,21 +74,21 @@ public class DefaultObjectNameGenerator implements ObjectNameGenerator { } } - return NameConverter.underscoredToJava(name, false); + return Util.underscoredToJava(name, false); } @Override public String createObjEntityName(DbEntity dbEntity) { - return NameConverter.underscoredToJava(dbEntity.getName(), true); + return Util.underscoredToJava(dbEntity.getName(), true); } @Override public String createObjAttributeName(DbAttribute attr) { - return NameConverter.underscoredToJava(attr.getName(), false); + return Util.underscoredToJava(attr.getName(), false); } @Override public String createObjRelationshipName(DbRelationship dbRel) { - return NameConverter.underscoredToJava(dbRel.getName(), false); + return Util.underscoredToJava(dbRel.getName(), false); } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/naming/LegacyObjectNameGenerator.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/naming/LegacyObjectNameGenerator.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/naming/LegacyObjectNameGenerator.java index 16f7f7a..1c52a6e 100644 --- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/naming/LegacyObjectNameGenerator.java +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/naming/LegacyObjectNameGenerator.java @@ -18,35 +18,37 @@ ****************************************************************/ package org.apache.cayenne.dbsync.reverse.naming; +import org.apache.cayenne.dbsync.reverse.db.ExportedKey; import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.map.DbEntity; import org.apache.cayenne.map.DbRelationship; -import org.apache.cayenne.dbsync.reverse.db.ExportedKey; +import org.apache.cayenne.util.Util; /** * BasicNamingStrategy is an naming strategy that creates names in Cayenne's * old-fashioned manner, i.e. the same way Cayenne did before 3.0 - * + * * @since 4.0 */ public class LegacyObjectNameGenerator implements ObjectNameGenerator { + public String createDbRelationshipName( ExportedKey key, boolean toMany) { - + String uglyName = (toMany) ? key.getFKTableName() + "_ARRAY" : "to_" + key.getPKTableName(); - return NameConverter.underscoredToJava(uglyName, false); + return Util.underscoredToJava(uglyName, false); } public String createObjEntityName(DbEntity dbEntity) { - return NameConverter.underscoredToJava(dbEntity.getName(), true); + return Util.underscoredToJava(dbEntity.getName(), true); } public String createObjAttributeName(DbAttribute attr) { - return NameConverter.underscoredToJava(attr.getName(), false); + return Util.underscoredToJava(attr.getName(), false); } public String createObjRelationshipName(DbRelationship dbRel) { - return NameConverter.underscoredToJava(dbRel.getName(), false); + return Util.underscoredToJava(dbRel.getName(), false); } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/naming/NameConverter.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/naming/NameConverter.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/naming/NameConverter.java deleted file mode 100644 index 63c4dcb..0000000 --- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/naming/NameConverter.java +++ /dev/null @@ -1,154 +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.dbsync.reverse.naming; - -import java.util.HashMap; -import java.util.Map; -import java.util.StringTokenizer; - -/** - * Utility class to convert from different naming styles to Java convention. For example - * names like "ABCD_EFG" can be converted to "abcdEfg". - */ -// TODO: deprecate -public class NameConverter { - - private static final Map<String, String> SPECIAL_CHAR_TO_JAVA_MAPPING = new HashMap<>(); - - static { - SPECIAL_CHAR_TO_JAVA_MAPPING.put("#", "pound"); - } - - /** - * Converts a String name to a String following java convention for the static final - * variables. E.g. "abcXyz" will be converted to "ABC_XYZ". - */ - // TODO: move to the only user.... - public static String javaToUnderscored(String name) { - if (name == null) { - return null; - } - - // clear of non-java chars. While the method name implies that a passed identifier - // is pure Java, it is used to build pk columns names and such, so extra safety - // check is a good idea - name = specialCharsToJava(name); - - char charArray[] = name.toCharArray(); - StringBuilder buffer = new StringBuilder(); - - for (int i = 0; i < charArray.length; i++) { - if ((Character.isUpperCase(charArray[i])) && (i != 0)) { - - char prevChar = charArray[i - 1]; - if ((Character.isLowerCase(prevChar))) { - buffer.append("_"); - } - } - - buffer.append(Character.toUpperCase(charArray[i])); - } - - return buffer.toString(); - } - - /** - * Converts names like "ABCD_EFG_123" to Java-style names like "abcdEfg123". If - * <code>capitalize</code> is true, returned name is capitalized (for instance if - * this is a class name). - * - * @since 1.2 - */ - // TODO: migrate users to ObjectNameGenerator - public static String underscoredToJava(String name, boolean capitalize) { - StringTokenizer st = new StringTokenizer(name, "_"); - StringBuilder buf = new StringBuilder(); - - boolean first = true; - while (st.hasMoreTokens()) { - String token = st.nextToken(); - - // clear of non-java chars - token = specialCharsToJava(token); - - int len = token.length(); - if (len == 0) { - continue; - } - - // sniff mixed case vs. single case styles - boolean hasLowerCase = false; - boolean hasUpperCase = false; - for (int i = 0; i < len && !(hasUpperCase && hasLowerCase); i++) { - if (Character.isUpperCase(token.charAt(i))) { - hasUpperCase = true; - } else if (Character.isLowerCase(token.charAt(i))) { - hasLowerCase = true; - } - } - - // if mixed case, preserve it, if all upper, convert to lower - if (hasUpperCase && !hasLowerCase) { - token = token.toLowerCase(); - } - - if (first) { - // apply explicit capitalization rules, if this is the first token - first = false; - if (capitalize) { - buf.append(Character.toUpperCase(token.charAt(0))); - } else { - buf.append(Character.toLowerCase(token.charAt(0))); - } - } else { - buf.append(Character.toUpperCase(token.charAt(0))); - } - - if (len > 1) { - buf.append(token.substring(1, len)); - } - } - return buf.toString(); - } - - /** - * Replaces special chars with human-readable and Java-id-compatible symbols. - */ - static String specialCharsToJava(String string) { - int len = string.length(); - if (len == 0) { - return string; - } - - StringBuilder buffer = new StringBuilder(len); - for (int i = 0; i < len; i++) { - - char c = string.charAt(i); - if (Character.isJavaIdentifierPart(c)) { - buffer.append(c); - } else { - Object word = SPECIAL_CHAR_TO_JAVA_MAPPING.get(String.valueOf(c)); - buffer.append(word != null ? word : "_"); - } - } - - return buffer.toString(); - } -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/naming/NameCheckersTest.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/naming/NameCheckersTest.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/naming/NameCheckersTest.java new file mode 100644 index 0000000..8131160 --- /dev/null +++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/naming/NameCheckersTest.java @@ -0,0 +1,204 @@ +/***************************************************************** + * 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.dbsync.naming; + +import org.apache.cayenne.access.DataDomain; +import org.apache.cayenne.configuration.DataChannelDescriptor; +import org.apache.cayenne.configuration.DataNodeDescriptor; +import org.apache.cayenne.map.DataMap; +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.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class NameCheckersTest { + + @Test + public void testObjEntityAttributes() throws Exception { + NameCheckers maker = NameCheckers.objAttribute; + ObjEntity namingContainer = new ObjEntity(); + + String baseName = maker.baseName(); + String name = DuplicateNameResolver.resolve(maker, namingContainer); + assertEquals(baseName, name); + namingContainer.addAttribute(new ObjAttribute(name)); + + name = DuplicateNameResolver.resolve(maker, namingContainer); + assertEquals(baseName + "1", name); + namingContainer.addAttribute(new ObjAttribute(name)); + + name = DuplicateNameResolver.resolve(maker, namingContainer); + assertEquals(baseName + "2", name); + namingContainer.addAttribute(new ObjAttribute(name)); + + name = DuplicateNameResolver.resolve(maker, namingContainer); + assertEquals(baseName + "3", name); + namingContainer.addAttribute(new ObjAttribute(name)); + + maker = NameCheckers.objRelationship; + baseName = maker.baseName(); + name = DuplicateNameResolver.resolve(maker, namingContainer); + assertEquals(baseName, name); + namingContainer.addRelationship(new ObjRelationship(name)); + + name = DuplicateNameResolver.resolve(maker, namingContainer); + assertEquals(baseName + "1", name); + namingContainer.addRelationship(new ObjRelationship(name)); + + maker = NameCheckers.objCallbackMethod; + baseName = maker.baseName(); + name = DuplicateNameResolver.resolve(maker, namingContainer); + assertEquals(baseName, name); + namingContainer.addRelationship(new ObjRelationship(name)); + } + + @Test + public void testEntity () { + DataMap map = new DataMap(); + + map.addDbEntity(new DbEntity("name")); + checkNameAndOther(map, NameCheckers.dbEntity, "name"); + + map.addObjEntity(new ObjEntity("name")); + checkNameAndOther(map, NameCheckers.objEntity, "name"); + + map.addProcedure(new Procedure("name")); + checkNameAndOther(map, NameCheckers.procedure, "name"); + + QueryDescriptor query = QueryDescriptor.selectQueryDescriptor(); + query.setName("name"); + map.addQueryDescriptor(query); + checkNameAndOther(map, NameCheckers.query, "name"); + } + + @Test + public void testProject() throws Exception { + assertFalse(NameCheckers.dataChannelDescriptor.isNameInUse(null, null)); + } + + @Test + public void testDbEntity() throws Exception { + DbEntity dbEntity = new DbEntity(); + + dbEntity.addRelationship(new DbRelationship("name")); + checkNameAndOther(dbEntity, NameCheckers.dbRelationship, "name"); + } + + @Test + public void testProcedureAttr() throws Exception { + Procedure procedure = new Procedure(); + + procedure.addCallParameter(new ProcedureParameter("name")); + checkNameAndOther(procedure, NameCheckers.procedureParameter, "name"); + } + + @Test + public void testEmbeddableAttr() throws Exception { + Embeddable embeddable = new Embeddable(); + + embeddable.addAttribute(new EmbeddableAttribute("name")); + checkNameAndOther(embeddable, NameCheckers.embeddableAttribute, "name"); + } + + @Test + public void testDatanode() throws Exception { + DataChannelDescriptor descriptor = new DataChannelDescriptor(); + + descriptor.getDataMaps().add(new DataMap("name")); + checkNameAndOther(descriptor, NameCheckers.dataMap, "name"); + + descriptor.getNodeDescriptors().add(new DataNodeDescriptor("name")); + checkNameAndOther(descriptor, NameCheckers.dataNodeDescriptor, "name"); + } + + @Test + public void testDataMap() throws Exception { + DataDomain dataDomain = new DataDomain("name"); + + dataDomain.addDataMap(new DataMap("name")); + checkNameAndOther(dataDomain, NameCheckers.dataMap, "name"); + + assertFalse(NameCheckers.dataMap.isNameInUse(null, "name")); + assertFalse(NameCheckers.dataMap.isNameInUse(1, "name")); + } + + private void checkNameAndOther(Object namingContainer, NameCheckers maker, String newName) { + assertTrue(maker.isNameInUse(namingContainer, newName)); + assertEquals(newName + "1", DuplicateNameResolver.resolve(maker,namingContainer, newName)); + assertEquals("other" + newName, DuplicateNameResolver.resolve(maker,namingContainer, "other" + newName)); + } + + @Test + public void testOverlappingAttributeAndCallbackNames() throws Exception { + ObjEntity namingContainer = new ObjEntity(); + + namingContainer.addAttribute(new ObjAttribute("myName")); + assertEquals("getMyName1", DuplicateNameResolver.resolve(NameCheckers.objCallbackMethod, namingContainer, "getMyName")); + + namingContainer.getCallbackMap().getPostAdd().addCallbackMethod("getSecondName"); + assertEquals("SecondName1", DuplicateNameResolver.resolve(NameCheckers.objAttribute, namingContainer, "SecondName")); + assertEquals("secondName1", DuplicateNameResolver.resolve(NameCheckers.objAttribute, namingContainer, "secondName")); + assertEquals("SecondName1", DuplicateNameResolver.resolve(NameCheckers.objRelationship, namingContainer, "SecondName")); + assertEquals("secondName1", DuplicateNameResolver.resolve(NameCheckers.objRelationship, namingContainer, "secondName")); + } + + @Test + public void testAttributeDifferentInFirstLetterCases() throws Exception { + ObjEntity namingContainer = new ObjEntity(); + + namingContainer.addAttribute(new ObjAttribute("myName")); + Assert.assertTrue(NameCheckers.objAttribute.isNameInUse(namingContainer, "myName")); + Assert.assertFalse(NameCheckers.objAttribute.isNameInUse(namingContainer, "MyName")); + + namingContainer.getCallbackMap().getPostAdd().addCallbackMethod("getSecondName"); + assertEquals("SecondName1", DuplicateNameResolver.resolve(NameCheckers.objAttribute, namingContainer, "SecondName")); + assertEquals("secondName1", DuplicateNameResolver.resolve(NameCheckers.objAttribute, namingContainer, "secondName")); + } + + @Test + public void testEmbeddable() { + DataMap map = new DataMap(); + + map.addEmbeddable(new Embeddable("name")); + Assert.assertTrue(NameCheckers.embeddable.isNameInUse(map, "name")); + assertEquals("name1", DuplicateNameResolver.resolve(NameCheckers.embeddable, map, "name")); + Assert.assertFalse(NameCheckers.embeddable.isNameInUse(map, "other-name")); + + map.setDefaultPackage("package"); + Assert.assertFalse(NameCheckers.embeddable.isNameInUse(map, "name")); + assertEquals("package.name", DuplicateNameResolver.resolve(NameCheckers.embeddable, map, "name")); + map.addEmbeddable(new Embeddable("package.name")); + + Assert.assertTrue(NameCheckers.embeddable.isNameInUse(map, "name")); + assertEquals("package.name1", DuplicateNameResolver.resolve(NameCheckers.embeddable, map, "name")); + Assert.assertFalse(NameCheckers.embeddable.isNameInUse(map, "other-name")); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/naming/NameConverterTest.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/naming/NameConverterTest.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/naming/NameConverterTest.java deleted file mode 100644 index 1c52f6e..0000000 --- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/naming/NameConverterTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/***************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - ****************************************************************/ - -package org.apache.cayenne.dbsync.reverse.naming; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class NameConverterTest { - - @Test - public void testUnderscoredToJava1() throws Exception { - String expected = "ClassNameIdentifier"; - assertEquals(expected, NameConverter.underscoredToJava( - "_CLASS_NAME_IDENTIFIER_", - true)); - } - - @Test - public void testUnderscoredToJava2() throws Exception { - String expected = "propNameIdentifier123"; - assertEquals(expected, NameConverter.underscoredToJava( - "_prop_name_Identifier_123", - false)); - } - - @Test - public void testUnderscoredToJava3() throws Exception { - String expected = "lastName"; - assertEquals(expected, NameConverter.underscoredToJava("lastName", false)); - } - - @Test - public void testUnderscoredToJava4() throws Exception { - String expected = "lastName"; - assertEquals(expected, NameConverter.underscoredToJava("LastName", false)); - } - - @Test - public void testUnderscoredToJava5() throws Exception { - String expected = "LastName"; - assertEquals(expected, NameConverter.underscoredToJava("LastName", true)); - } - - @Test - public void testUnderscoredToJavaSpecialChars() throws Exception { - assertEquals("ABCpoundXyz", NameConverter.underscoredToJava("ABC#_XYZ", true)); - } - - @Test - public void testJavaToUnderscored1() throws Exception { - String expected = "LAST_NAME"; - assertEquals(expected, NameConverter.javaToUnderscored("LastName")); - } - - @Test - public void testJavaToUnderscored2() throws Exception { - String expected = "A_CLASS"; - assertEquals(expected, NameConverter.javaToUnderscored("aClass")); - } - - @Test - public void testJavaToUnderscored3() throws Exception { - String expected = "VAR_A"; - assertEquals(expected, NameConverter.javaToUnderscored("varA")); - } - - @Test - public void testJavaToUnderscored4() throws Exception { - String expected = "LAST_NAME"; - assertEquals(expected, NameConverter.javaToUnderscored("LAST_NAME")); - } - - @Test - public void testJavaToUnderscored5() throws Exception { - String expected = "ABC_A"; - assertEquals(expected, NameConverter.javaToUnderscored("abc_A")); - } - - @Test - public void testJavaToUnderscored6() throws Exception { - String expected = "A123"; - assertEquals(expected, NameConverter.javaToUnderscored("a123")); - } - - @Test - public void testJavaToUnderscored7() throws Exception { - String expected = "AB_CDEF"; - assertEquals(expected, NameConverter.javaToUnderscored("abCDEF")); - } - - @Test - public void testJavaToUnderscored8() throws Exception { - String expected = "AB_CE"; - assertEquals(expected, NameConverter.javaToUnderscored("abCe")); - } - -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-server/src/main/java/org/apache/cayenne/map/ObjEntity.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/ObjEntity.java b/cayenne-server/src/main/java/org/apache/cayenne/map/ObjEntity.java index de79a6a..81a66ee 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/map/ObjEntity.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/map/ObjEntity.java @@ -677,7 +677,7 @@ public class ObjEntity extends Entity implements ObjEntityListener, Configuratio // create synthetic attribute if (attribute == null) { - attribute = new SyntheticPKObjAttribute(pk.getName()); + attribute = new SyntheticPKObjAttribute(Util.underscoredToJava(pk.getName(), false)); attribute.setDbAttributePath(pk.getName()); attribute.setType(TypesMapping.getJavaBySqlType(pk.getType())); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-server/src/main/java/org/apache/cayenne/map/naming/NameChecker.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/naming/NameChecker.java b/cayenne-server/src/main/java/org/apache/cayenne/map/naming/NameChecker.java deleted file mode 100644 index 68fdfd3..0000000 --- a/cayenne-server/src/main/java/org/apache/cayenne/map/naming/NameChecker.java +++ /dev/null @@ -1,36 +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.map.naming; - -/** - * @since 4.0 - */ -public interface NameChecker { - - /** - * Returns a base default name, like "UntitledEntity", etc. - */ - String baseName(); - - /** - * Checks if the name is already taken by another sibling in the same - * context. - */ - boolean isNameInUse(Object namingContext, String name); -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-server/src/main/java/org/apache/cayenne/map/naming/NameCheckers.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/naming/NameCheckers.java b/cayenne-server/src/main/java/org/apache/cayenne/map/naming/NameCheckers.java deleted file mode 100644 index 67639d6..0000000 --- a/cayenne-server/src/main/java/org/apache/cayenne/map/naming/NameCheckers.java +++ /dev/null @@ -1,221 +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.map.naming; - -import org.apache.cayenne.access.DataDomain; -import org.apache.cayenne.configuration.DataChannelDescriptor; -import org.apache.cayenne.configuration.DataNodeDescriptor; -import org.apache.cayenne.map.DataMap; -import org.apache.cayenne.map.Embeddable; -import org.apache.cayenne.map.Entity; -import org.apache.cayenne.map.ObjEntity; -import org.apache.cayenne.map.Procedure; -import org.apache.cayenne.map.ProcedureParameter; -import org.apache.commons.lang.StringUtils; - -/** - * @since 4.0 - */ -public enum NameCheckers implements NameChecker { - - dataChannelDescriptor("project") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - return false; - } - }, - - dataMap("datamap") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - // null context is a situation when DataMap is a - // top level object of the project - if (namingContext == null) { - return false; - } - - if (namingContext instanceof DataDomain) { - DataDomain domain = (DataDomain) namingContext; - return domain.getDataMap(name) != null; - } - - if (namingContext instanceof DataChannelDescriptor) { - DataChannelDescriptor domain = (DataChannelDescriptor) namingContext; - return domain.getDataMap(name) != null; - } - return false; - } - }, - - reverseEngineering("reverseEngineering") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - if (namingContext == null) { - return false; - } - - for (DataMap dataMap : ((DataChannelDescriptor) namingContext).getDataMaps()) { - if (dataMap!= null && dataMap.getReverseEngineering() != null && - dataMap.getReverseEngineering().getName()!=null && dataMap.getReverseEngineering().getName().equals(name)) { - return true; - } - } - return false; - } - }, - - objEntity("ObjEntity") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - DataMap map = (DataMap) namingContext; - return map.getObjEntity(name) != null; - } - }, - - embeddable("Embeddable") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - DataMap map = (DataMap) namingContext; - return map.getEmbeddable(map.getNameWithDefaultPackage(name)) != null; - } - }, - - embeddableAttribute("untitledAttr") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - Embeddable emb = (Embeddable) namingContext; - return emb.getAttribute(name) != null; - } - }, - - dbEntity("db_entity") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - DataMap map = (DataMap) namingContext; - return map.getDbEntity(name) != null; - } - }, - - procedureParameter("UntitledProcedureParameter") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - - // it doesn't matter if we create a parameter with - // a duplicate name.. parameters are positional anyway.. - // still try to use unique names for visual consistency - Procedure procedure = (Procedure) namingContext; - for (final ProcedureParameter parameter : procedure - .getCallParameters()) { - if (name.equals(parameter.getName())) { - return true; - } - } - - return false; - } - }, - - procedure("procedure") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - DataMap map = (DataMap) namingContext; - return map.getProcedure(name) != null; - } - }, - - query("query") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - DataMap map = (DataMap) namingContext; - return map.getQueryDescriptor(name) != null; - } - }, - - objAttribute("untitledAttr") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - return objRelationship.isNameInUse(namingContext, name); - } - }, - - dbAttribute("untitledAttr") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - Entity ent = (Entity) namingContext; - return ent.getAttribute(name) != null - || ent.getRelationship(name) != null; - } - }, - - dataNodeDescriptor("datanode") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - DataChannelDescriptor domain = (DataChannelDescriptor) namingContext; - for (DataNodeDescriptor dataNodeDescriptor : domain - .getNodeDescriptors()) { - if (dataNodeDescriptor.getName().equals(name)) { - return true; - } - } - return false; - } - }, - - objRelationship("untitledRel") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - ObjEntity ent = (ObjEntity) namingContext; - return dbAttribute.isNameInUse(namingContext, name) - || ent.getCallbackMethods().contains( - "get" + StringUtils.capitalize(name)); - } - }, - - dbRelationship("untitledRel") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - return dbAttribute.isNameInUse(namingContext, name); - } - }, - - objCallbackMethod("ObjCallbackMethod") { - @Override - public boolean isNameInUse(Object namingContext, String name) { - ObjEntity ent = (ObjEntity) namingContext; - - return name.startsWith("get") - && dbAttribute.isNameInUse(namingContext, - StringUtils.uncapitalize(name.substring(3))) - || ent.getCallbackMethods().contains(name); - } - }; - - public final String baseName; - - NameCheckers(String baseName) { - this.baseName = baseName; - } - - @Override - public String baseName() { - return baseName; - } - -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-server/src/main/java/org/apache/cayenne/map/naming/UniqueNameGenerator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/naming/UniqueNameGenerator.java b/cayenne-server/src/main/java/org/apache/cayenne/map/naming/UniqueNameGenerator.java deleted file mode 100644 index 2fe6801..0000000 --- a/cayenne-server/src/main/java/org/apache/cayenne/map/naming/UniqueNameGenerator.java +++ /dev/null @@ -1,91 +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.map.naming; - -import org.apache.cayenne.map.DataMap; - -/** - * @since 4.0 - */ -public class UniqueNameGenerator { - - public static final String DEFAULT_PATTERN = "%s%d"; - - private final NameChecker nameChecker; - - private final String pattern; - - public UniqueNameGenerator(NameChecker nameChecker, String pattern) { - this.nameChecker = nameChecker; - this.pattern = pattern; - } - - public static String generate(NameChecker checker) { - return generate(checker, DEFAULT_PATTERN, null, null); - } - - public static String generate(NameChecker checker, Object context) { - return generate(checker, DEFAULT_PATTERN, context, null); - } - - public static String generate(NameChecker checker, Object context, String baseName) { - return generate(checker, DEFAULT_PATTERN, context, baseName); - } - - public static String generate(NameChecker checker, String pattern, Object context, String baseName) { - UniqueNameGenerator generator; - if (checker == NameCheckers.embeddable) { - generator = new UniqueNameGenerator(NameCheckers.embeddable, pattern) { - @Override - public String generate(Object namingContext, String nameBase) { - return ((DataMap) namingContext).getNameWithDefaultPackage(super.generate(namingContext, nameBase)); - } - }; - } else { - generator = new UniqueNameGenerator(checker, pattern); - } - - return generator.generate(context, baseName); - } - - /** - * Creates a unique name for the new object and constructs this object. - */ - String generate(Object namingContext) { - return generate(namingContext, nameChecker.baseName()); - } - - String generate(Object namingContext, String nameBase) { - return generate(pattern, namingContext, nameBase != null ? nameBase : nameChecker.baseName()); - } - - /** - * @since 1.0.5 - */ - private String generate(String pattern, Object namingContext, String nameBase) { - int c = 1; - String name = nameBase; - while (nameChecker.isNameInUse(namingContext, name)) { - name = String.format(pattern, nameBase, c++); - } - - return name; - } - -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-server/src/main/java/org/apache/cayenne/util/Util.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/util/Util.java b/cayenne-server/src/main/java/org/apache/cayenne/util/Util.java index e0f5571..14e5eab 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/util/Util.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/util/Util.java @@ -19,6 +19,23 @@ package org.apache.cayenne.util; +import org.apache.cayenne.Cayenne; +import org.apache.cayenne.PersistenceState; +import org.apache.cayenne.Persistent; +import org.apache.cayenne.di.AdhocObjectFactory; +import org.apache.cayenne.di.spi.DefaultAdhocObjectFactory; +import org.apache.cayenne.di.spi.DefaultClassLoaderManager; +import org.apache.cayenne.reflect.ArcProperty; +import org.apache.cayenne.reflect.AttributeProperty; +import org.apache.cayenne.reflect.PropertyVisitor; +import org.apache.cayenne.reflect.ToManyProperty; +import org.apache.cayenne.reflect.ToOneProperty; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -42,31 +59,19 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.StringTokenizer; import java.util.regex.Pattern; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.apache.cayenne.Cayenne; -import org.apache.cayenne.PersistenceState; -import org.apache.cayenne.Persistent; -import org.apache.cayenne.di.AdhocObjectFactory; -import org.apache.cayenne.di.spi.DefaultAdhocObjectFactory; -import org.apache.cayenne.di.spi.DefaultClassLoaderManager; -import org.apache.cayenne.reflect.ArcProperty; -import org.apache.cayenne.reflect.AttributeProperty; -import org.apache.cayenne.reflect.PropertyVisitor; -import org.apache.cayenne.reflect.ToManyProperty; -import org.apache.cayenne.reflect.ToOneProperty; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; - /** * Contains various unorganized static utility methods used across Cayenne. */ public class Util { + private static final Map<String, String> SPECIAL_CHAR_TO_JAVA_MAPPING = new HashMap<>(); + static { + SPECIAL_CHAR_TO_JAVA_MAPPING.put("#", "pound"); + } + @Deprecated private static DefaultAdhocObjectFactory objectFactory; @@ -508,6 +513,91 @@ public class Util { return objectFactory.getJavaClass(className); } + /** + * Converts names like "ABCD_EFG_123" to Java-style names like "abcdEfg123". If + * <code>capitalize</code> is true, returned name is capitalized (for instance if + * this is a class name). + * + * @since 4.0 + */ + // TODO: trace direct users and switch over to ObjectNameGenerator + public static String underscoredToJava(String name, boolean capitalize) { + StringTokenizer st = new StringTokenizer(name, "_"); + StringBuilder buf = new StringBuilder(); + + boolean first = true; + while (st.hasMoreTokens()) { + String token = st.nextToken(); + + // clear of non-java chars + token = specialCharsToJava(token); + + int len = token.length(); + if (len == 0) { + continue; + } + + // sniff mixed case vs. single case styles + boolean hasLowerCase = false; + boolean hasUpperCase = false; + for (int i = 0; i < len && !(hasUpperCase && hasLowerCase); i++) { + if (Character.isUpperCase(token.charAt(i))) { + hasUpperCase = true; + } else if (Character.isLowerCase(token.charAt(i))) { + hasLowerCase = true; + } + } + + // if mixed case, preserve it, if all upper, convert to lower + if (hasUpperCase && !hasLowerCase) { + token = token.toLowerCase(); + } + + if (first) { + // apply explicit capitalization rules, if this is the first token + first = false; + if (capitalize) { + buf.append(Character.toUpperCase(token.charAt(0))); + } else { + buf.append(Character.toLowerCase(token.charAt(0))); + } + } else { + buf.append(Character.toUpperCase(token.charAt(0))); + } + + if (len > 1) { + buf.append(token.substring(1, len)); + } + } + return buf.toString(); + } + + /** + * Replaces special chars with human-readable and Java-id-compatible symbols. + * + * @since 4.0 + */ + public static String specialCharsToJava(String string) { + int len = string.length(); + if (len == 0) { + return string; + } + + StringBuilder buffer = new StringBuilder(len); + for (int i = 0; i < len; i++) { + + char c = string.charAt(i); + if (Character.isJavaIdentifierPart(c)) { + buffer.append(c); + } else { + Object word = SPECIAL_CHAR_TO_JAVA_MAPPING.get(String.valueOf(c)); + buffer.append(word != null ? word : "_"); + } + } + + return buffer.toString(); + } + static void setReverse(final Persistent sourceObject, String propertyName, final Persistent targetObject) { ArcProperty property = (ArcProperty) Cayenne.getClassDescriptor(sourceObject).getProperty(propertyName); http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-server/src/test/java/org/apache/cayenne/map/naming/NameCheckersTest.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/map/naming/NameCheckersTest.java b/cayenne-server/src/test/java/org/apache/cayenne/map/naming/NameCheckersTest.java deleted file mode 100644 index e3e6628..0000000 --- a/cayenne-server/src/test/java/org/apache/cayenne/map/naming/NameCheckersTest.java +++ /dev/null @@ -1,204 +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.map.naming; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.apache.cayenne.access.DataDomain; -import org.apache.cayenne.configuration.DataChannelDescriptor; -import org.apache.cayenne.configuration.DataNodeDescriptor; -import org.apache.cayenne.map.DataMap; -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.junit.Assert; -import org.junit.Test; - -public class NameCheckersTest { - - @Test - public void testObjEntityAttributes() throws Exception { - NameCheckers maker = NameCheckers.objAttribute; - ObjEntity namingContainer = new ObjEntity(); - - String baseName = maker.baseName(); - String name = UniqueNameGenerator.generate(maker, namingContainer); - assertEquals(baseName, name); - namingContainer.addAttribute(new ObjAttribute(name)); - - name = UniqueNameGenerator.generate(maker, namingContainer); - assertEquals(baseName + "1", name); - namingContainer.addAttribute(new ObjAttribute(name)); - - name = UniqueNameGenerator.generate(maker, namingContainer); - assertEquals(baseName + "2", name); - namingContainer.addAttribute(new ObjAttribute(name)); - - name = UniqueNameGenerator.generate(maker, namingContainer); - assertEquals(baseName + "3", name); - namingContainer.addAttribute(new ObjAttribute(name)); - - maker = NameCheckers.objRelationship; - baseName = maker.baseName(); - name = UniqueNameGenerator.generate(maker, namingContainer); - assertEquals(baseName, name); - namingContainer.addRelationship(new ObjRelationship(name)); - - name = UniqueNameGenerator.generate(maker, namingContainer); - assertEquals(baseName + "1", name); - namingContainer.addRelationship(new ObjRelationship(name)); - - maker = NameCheckers.objCallbackMethod; - baseName = maker.baseName(); - name = UniqueNameGenerator.generate(maker, namingContainer); - assertEquals(baseName, name); - namingContainer.addRelationship(new ObjRelationship(name)); - } - - @Test - public void testEntity () { - DataMap map = new DataMap(); - - map.addDbEntity(new DbEntity("name")); - checkNameAndOther(map, NameCheckers.dbEntity, "name"); - - map.addObjEntity(new ObjEntity("name")); - checkNameAndOther(map, NameCheckers.objEntity, "name"); - - map.addProcedure(new Procedure("name")); - checkNameAndOther(map, NameCheckers.procedure, "name"); - - QueryDescriptor query = QueryDescriptor.selectQueryDescriptor(); - query.setName("name"); - map.addQueryDescriptor(query); - checkNameAndOther(map, NameCheckers.query, "name"); - } - - @Test - public void testProject() throws Exception { - assertFalse(NameCheckers.dataChannelDescriptor.isNameInUse(null, null)); - } - - @Test - public void testDbEntity() throws Exception { - DbEntity dbEntity = new DbEntity(); - - dbEntity.addRelationship(new DbRelationship("name")); - checkNameAndOther(dbEntity, NameCheckers.dbRelationship, "name"); - } - - @Test - public void testProcedureAttr() throws Exception { - Procedure procedure = new Procedure(); - - procedure.addCallParameter(new ProcedureParameter("name")); - checkNameAndOther(procedure, NameCheckers.procedureParameter, "name"); - } - - @Test - public void testEmbeddableAttr() throws Exception { - Embeddable embeddable = new Embeddable(); - - embeddable.addAttribute(new EmbeddableAttribute("name")); - checkNameAndOther(embeddable, NameCheckers.embeddableAttribute, "name"); - } - - @Test - public void testDatanode() throws Exception { - DataChannelDescriptor descriptor = new DataChannelDescriptor(); - - descriptor.getDataMaps().add(new DataMap("name")); - checkNameAndOther(descriptor, NameCheckers.dataMap, "name"); - - descriptor.getNodeDescriptors().add(new DataNodeDescriptor("name")); - checkNameAndOther(descriptor, NameCheckers.dataNodeDescriptor, "name"); - } - - @Test - public void testDataMap() throws Exception { - DataDomain dataDomain = new DataDomain("name"); - - dataDomain.addDataMap(new DataMap("name")); - checkNameAndOther(dataDomain, NameCheckers.dataMap, "name"); - - assertFalse(NameCheckers.dataMap.isNameInUse(null, "name")); - assertFalse(NameCheckers.dataMap.isNameInUse(1, "name")); - } - - private void checkNameAndOther(Object namingContainer, NameCheckers maker, String newName) { - assertTrue(maker.isNameInUse(namingContainer, newName)); - assertEquals(newName + "1", UniqueNameGenerator.generate(maker,namingContainer, newName)); - assertEquals("other" + newName, UniqueNameGenerator.generate(maker,namingContainer, "other" + newName)); - } - - @Test - public void testOverlappingAttributeAndCallbackNames() throws Exception { - ObjEntity namingContainer = new ObjEntity(); - - namingContainer.addAttribute(new ObjAttribute("myName")); - Assert.assertEquals("getMyName1", UniqueNameGenerator.generate(NameCheckers.objCallbackMethod, namingContainer, "getMyName")); - - namingContainer.getCallbackMap().getPostAdd().addCallbackMethod("getSecondName"); - Assert.assertEquals("SecondName1", UniqueNameGenerator.generate(NameCheckers.objAttribute, namingContainer, "SecondName")); - Assert.assertEquals("secondName1", UniqueNameGenerator.generate(NameCheckers.objAttribute, namingContainer, "secondName")); - Assert.assertEquals("SecondName1", UniqueNameGenerator.generate(NameCheckers.objRelationship, namingContainer, "SecondName")); - Assert.assertEquals("secondName1", UniqueNameGenerator.generate(NameCheckers.objRelationship, namingContainer, "secondName")); - } - - @Test - public void testAttributeDifferentInFirstLetterCases() throws Exception { - ObjEntity namingContainer = new ObjEntity(); - - namingContainer.addAttribute(new ObjAttribute("myName")); - Assert.assertTrue(NameCheckers.objAttribute.isNameInUse(namingContainer, "myName")); - Assert.assertFalse(NameCheckers.objAttribute.isNameInUse(namingContainer, "MyName")); - - namingContainer.getCallbackMap().getPostAdd().addCallbackMethod("getSecondName"); - Assert.assertEquals("SecondName1", UniqueNameGenerator.generate(NameCheckers.objAttribute, namingContainer, "SecondName")); - Assert.assertEquals("secondName1", UniqueNameGenerator.generate(NameCheckers.objAttribute, namingContainer, "secondName")); - } - - @Test - public void testEmbeddable() { - DataMap map = new DataMap(); - - map.addEmbeddable(new Embeddable("name")); - Assert.assertTrue(NameCheckers.embeddable.isNameInUse(map, "name")); - Assert.assertEquals("name1", UniqueNameGenerator.generate(NameCheckers.embeddable, map, "name")); - Assert.assertFalse(NameCheckers.embeddable.isNameInUse(map, "other-name")); - - map.setDefaultPackage("package"); - Assert.assertFalse(NameCheckers.embeddable.isNameInUse(map, "name")); - Assert.assertEquals("package.name", UniqueNameGenerator.generate(NameCheckers.embeddable, map, "name")); - map.addEmbeddable(new Embeddable("package.name")); - - Assert.assertTrue(NameCheckers.embeddable.isNameInUse(map, "name")); - Assert.assertEquals("package.name1", UniqueNameGenerator.generate(NameCheckers.embeddable, map, "name")); - Assert.assertFalse(NameCheckers.embeddable.isNameInUse(map, "other-name")); - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-server/src/test/java/org/apache/cayenne/util/UtilTest.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/util/UtilTest.java b/cayenne-server/src/test/java/org/apache/cayenne/util/UtilTest.java index 2db6987..eab7371 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/util/UtilTest.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/util/UtilTest.java @@ -295,4 +295,42 @@ public class UtilTest { assertEquals("1...78", Util.prettyTrim("12345678", 6)); } + @Test + public void testUnderscoredToJava1() throws Exception { + String expected = "ClassNameIdentifier"; + assertEquals(expected, Util.underscoredToJava( + "_CLASS_NAME_IDENTIFIER_", + true)); + } + + @Test + public void testUnderscoredToJava2() throws Exception { + String expected = "propNameIdentifier123"; + assertEquals(expected, Util.underscoredToJava( + "_prop_name_Identifier_123", + false)); + } + + @Test + public void testUnderscoredToJava3() throws Exception { + String expected = "lastName"; + assertEquals(expected, Util.underscoredToJava("lastName", false)); + } + + @Test + public void testUnderscoredToJava4() throws Exception { + String expected = "lastName"; + assertEquals(expected, Util.underscoredToJava("LastName", false)); + } + + @Test + public void testUnderscoredToJava5() throws Exception { + String expected = "LastName"; + assertEquals(expected, Util.underscoredToJava("LastName", true)); + } + + @Test + public void testUnderscoredToJavaSpecialChars() throws Exception { + assertEquals("ABCpoundXyz", Util.underscoredToJava("ABC#_XYZ", true)); + } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClientDataMapArtifact.java ---------------------------------------------------------------------- diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClientDataMapArtifact.java b/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClientDataMapArtifact.java index d99a577..a9d1dfe 100644 --- a/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClientDataMapArtifact.java +++ b/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClientDataMapArtifact.java @@ -19,7 +19,6 @@ package org.apache.cayenne.gen; -import org.apache.cayenne.dbsync.reverse.naming.NameConverter; import org.apache.cayenne.map.DataMap; import org.apache.cayenne.map.QueryDescriptor; import org.apache.cayenne.util.Util; @@ -46,6 +45,6 @@ public class ClientDataMapArtifact extends DataMapArtifact { clientPrefix = "Client_"; } - return dataMap.getNameWithDefaultClientPackage(NameConverter.underscoredToJava(clientPrefix + dataMap.getName(), true)); + return dataMap.getNameWithDefaultClientPackage(Util.underscoredToJava(clientPrefix + dataMap.getName(), true)); } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-tools/src/main/java/org/apache/cayenne/gen/DataMapArtifact.java ---------------------------------------------------------------------- diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/gen/DataMapArtifact.java b/cayenne-tools/src/main/java/org/apache/cayenne/gen/DataMapArtifact.java index e01d002..8e60495 100644 --- a/cayenne-tools/src/main/java/org/apache/cayenne/gen/DataMapArtifact.java +++ b/cayenne-tools/src/main/java/org/apache/cayenne/gen/DataMapArtifact.java @@ -19,9 +19,9 @@ package org.apache.cayenne.gen; -import org.apache.cayenne.dbsync.reverse.naming.NameConverter; import org.apache.cayenne.map.DataMap; import org.apache.cayenne.map.QueryDescriptor; +import org.apache.cayenne.util.Util; import org.apache.velocity.VelocityContext; import java.util.Collection; @@ -58,7 +58,7 @@ public class DataMapArtifact implements Artifact { } public String getQualifiedClassName() { - return dataMap.getNameWithDefaultPackage(NameConverter.underscoredToJava(dataMap.getName(), true)); + return dataMap.getNameWithDefaultPackage(Util.underscoredToJava(dataMap.getName(), true)); } public Object getObject() { http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-tools/src/main/java/org/apache/cayenne/gen/DataMapUtils.java ---------------------------------------------------------------------- diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/gen/DataMapUtils.java b/cayenne-tools/src/main/java/org/apache/cayenne/gen/DataMapUtils.java index 9d5c75a..a0013cc 100644 --- a/cayenne-tools/src/main/java/org/apache/cayenne/gen/DataMapUtils.java +++ b/cayenne-tools/src/main/java/org/apache/cayenne/gen/DataMapUtils.java @@ -19,17 +19,6 @@ package org.apache.cayenne.gen; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import org.apache.cayenne.exp.Expression; import org.apache.cayenne.exp.ExpressionException; import org.apache.cayenne.exp.ExpressionParameter; @@ -42,11 +31,22 @@ import org.apache.cayenne.map.ObjRelationship; import org.apache.cayenne.map.PathComponent; import org.apache.cayenne.map.QueryDescriptor; import org.apache.cayenne.map.SelectQueryDescriptor; -import org.apache.cayenne.dbsync.reverse.naming.NameConverter; import org.apache.cayenne.query.Ordering; import org.apache.cayenne.util.CayenneMapEntry; +import org.apache.cayenne.util.Util; import org.apache.commons.collections.set.ListOrderedSet; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * Attributes and Methods for working with Queries. * @@ -64,7 +64,7 @@ public class DataMapUtils { * @return Method name that perform query. */ public String getQueryMethodName(QueryDescriptor query) { - return NameConverter.underscoredToJava(query.getName(), true); + return Util.underscoredToJava(query.getName(), true); } /** @@ -136,7 +136,7 @@ public class DataMapUtils { Matcher matcher = pattern.matcher(qualifierString); while (matcher.find()) { String name = matcher.group(); - result.add(NameConverter.underscoredToJava(name.substring(1), false)); + result.add(Util.underscoredToJava(name.substring(1), false)); } return result; @@ -209,7 +209,7 @@ public class DataMapUtils { } for (String name : names) { - types.put(NameConverter.underscoredToJava(name, false), typeName); + types.put(Util.underscoredToJava(name, false), typeName); } return types; http://git-wip-us.apache.org/repos/asf/cayenne/blob/ad944755/cayenne-tools/src/main/java/org/apache/cayenne/gen/StringUtils.java ---------------------------------------------------------------------- diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/gen/StringUtils.java b/cayenne-tools/src/main/java/org/apache/cayenne/gen/StringUtils.java index 34ccfb3..5473142 100644 --- a/cayenne-tools/src/main/java/org/apache/cayenne/gen/StringUtils.java +++ b/cayenne-tools/src/main/java/org/apache/cayenne/gen/StringUtils.java @@ -20,7 +20,6 @@ package org.apache.cayenne.gen; import org.apache.cayenne.project.validation.NameValidationHelper; -import org.apache.cayenne.dbsync.reverse.naming.NameConverter; import org.apache.cayenne.util.Util; /** @@ -112,7 +111,27 @@ public class StringUtils { if (name == null || name.length() == 0) return name; - return NameConverter.javaToUnderscored(name); + // clear of non-java chars. While the method name implies that a passed identifier + // is pure Java, it is used to build pk columns names and such, so extra safety + // check is a good idea + name = Util.specialCharsToJava(name); + + char charArray[] = name.toCharArray(); + StringBuilder buffer = new StringBuilder(); + + for (int i = 0; i < charArray.length; i++) { + if ((Character.isUpperCase(charArray[i])) && (i != 0)) { + + char prevChar = charArray[i - 1]; + if ((Character.isLowerCase(prevChar))) { + buffer.append("_"); + } + } + + buffer.append(Character.toUpperCase(charArray[i])); + } + + return buffer.toString(); } /**
