http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/access/loader/NamePatternMatcher.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/NamePatternMatcher.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/NamePatternMatcher.java new file mode 100644 index 0000000..6faa7e4 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/NamePatternMatcher.java @@ -0,0 +1,225 @@ +/***************************************************************** + * 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.access.loader; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import org.apache.cayenne.util.CayenneMapEntry; +import org.apache.commons.logging.Log; + +/** + * Provides name pattern matching functionality. + * + * @since 1.2 + */ +public class NamePatternMatcher implements NameFilter { + + private static final String[] EMPTY_ARRAY = new String[0]; + private static final Pattern COMMA = Pattern.compile(","); + + private final Pattern[] itemIncludeFilters; + private final Pattern[] itemExcludeFilters; + + public static NamePatternMatcher build(Log logger, String includePattern, String excludePattern) { + return new NamePatternMatcher(createPatterns(logger, includePattern), createPatterns(logger, excludePattern)); + } + + public NamePatternMatcher(Pattern[] itemIncludeFilters, Pattern[] itemExcludeFilters) { + this.itemIncludeFilters = itemIncludeFilters; + this.itemExcludeFilters = itemExcludeFilters; + } + + /** + * Applies preconfigured list of filters to the list, removing entities that do not + * pass the filter. + * + * @deprecated since 3.0 still used by AntDataPortDelegate, which itself should + * probably be deprecated + */ + @Deprecated + public List<?> filter(List<?> items) { + if (items == null || items.isEmpty()) { + return items; + } + + if (itemIncludeFilters.length == 0 && itemExcludeFilters.length == 0) { + return items; + } + + Iterator<?> it = items.iterator(); + while (it.hasNext()) { + CayenneMapEntry entity = (CayenneMapEntry) it.next(); + + if (!passedIncludeFilter(entity.getName())) { + it.remove(); + continue; + } + + if (!passedExcludeFilter(entity.getName())) { + it.remove(); + } + } + + return items; + } + + /** + * Returns an array of Patterns. Takes a comma-separated list of patterns, attempting + * to convert them to the java.util.regex.Pattern syntax. E.g. + * <p> + * <code>"billing_*,user?"</code> will become an array of two expressions: + * <p> + * <code>^billing_.*$</code><br> + * <code>^user.?$</code><br> + */ + public static Pattern[] createPatterns(Log logger, String patternString) { + if (patternString == null) { + return new Pattern[0]; + } + String[] patternStrings = tokenizePattern(patternString); + List<Pattern> patterns = new ArrayList<Pattern>(patternStrings.length); + + for (String patternString1 : patternStrings) { + + // test the pattern + try { + patterns.add(Pattern.compile(patternString1)); + } catch (PatternSyntaxException e) { + + if (logger != null) { + logger.warn("Ignoring invalid pattern [" + patternString1 + "], reason: " + e.getMessage()); + } + } + } + + return patterns.toArray(new Pattern[patterns.size()]); + } + + /** + * Returns an array of valid regular expressions. Takes a comma-separated list of + * patterns, attempting to convert them to the java.util.regex.Pattern syntax. E.g. + * <p> + * <code>"billing_*,user?"</code> will become an array of two expressions: + * <p> + * <code>^billing_.*$</code><br> + * <code>^user.?$</code><br> + */ + public static String[] tokenizePattern(String pattern) { + if (pattern == null || pattern.isEmpty()) { + return EMPTY_ARRAY; + } + + String[] patterns = COMMA.split(pattern); + if (patterns.length == 0) { + return EMPTY_ARRAY; + } + + for (int i = 0; i < patterns.length; i++) { + // convert * into regex syntax + // e.g. abc*x becomes ^abc.*x$ + // or abc?x becomes ^abc.?x$ + patterns[i] = "^" + patterns[i].replaceAll("[*?]", ".$0") + "$"; + } + + return patterns; + } + + /** + * Returns true if a given object property satisfies the include/exclude patterns. + * + * @since 3.0 + */ + @Override + public boolean isIncluded(String string) { + return passedIncludeFilter(string) && passedExcludeFilter(string); + } + + /** + * Returns true if an object matches any one of the "include" patterns, or if there is + * no "include" patterns defined. + * + * @since 3.0 + */ + private boolean passedIncludeFilter(String item) { + if (itemIncludeFilters.length == 0) { + return true; + } + + for (Pattern itemIncludeFilter : itemIncludeFilters) { + if (itemIncludeFilter.matcher(item).find()) { + return true; + } + } + + return false; + } + + /** + * Returns true if an object does not match any one of the "exclude" patterns, or if + * there is no "exclude" patterns defined. + * + * @since 3.0 + */ + private boolean passedExcludeFilter(String item) { + if (itemExcludeFilters.length == 0) { + return true; + } + + for (Pattern itemExcludeFilter : itemExcludeFilters) { + if (itemExcludeFilter.matcher(item).find()) { + return false; + } + } + + return true; + } + + public static String replaceWildcardInStringWithString( + String wildcard, + String pattern, + String replacement) { + + if (pattern == null || wildcard == null) { + return pattern; + } + + StringBuilder buffer = new StringBuilder(); + int lastPos = 0; + int wildCardPos = pattern.indexOf(wildcard); + while (wildCardPos != -1) { + if (lastPos != wildCardPos) { + buffer.append(pattern.substring(lastPos, wildCardPos)); + } + buffer.append(replacement); + lastPos += wildCardPos + wildcard.length(); + wildCardPos = pattern.indexOf(wildcard, lastPos); + } + + if (lastPos < pattern.length()) { + buffer.append(pattern.substring(lastPos)); + } + + return buffer.toString(); + } +}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/DbPath.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/DbPath.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/DbPath.java new file mode 100644 index 0000000..b9db92d --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/DbPath.java @@ -0,0 +1,154 @@ +/***************************************************************** + * 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.access.loader.filters; + +import java.util.regex.Pattern; + +/** +* @since 3.2. +* @Immutable +*/ +public class DbPath implements Comparable<DbPath> { + + public static final DbPath EMPTY = new DbPath(); + + public static final String SEPARATOR = "/"; + public final String catalog; + public final String schema; + public final String tablePattern; + + private final String path; + + public DbPath() { + this(null, null, null); + } + + public DbPath(String catalog) { + this(catalog, null, null); + } + + public DbPath(String catalog, String schema) { + this(catalog, schema, null); + } + + public DbPath(String catalog, String schema, String tablePattern) { + this.catalog = prepareValue(catalog); + this.schema = prepareValue(schema); + this.tablePattern = prepareValue(tablePattern); + + this.path = join(this.catalog, this.schema, this.tablePattern); + } + + private static String join(String first, String second) { + if (second == null || second.equals("%")) { + return first; + } else { + return escapeNull(first) + SEPARATOR + second; + } + } + + private static String join(String catalog, String schema, String table) { + String join = join(catalog, join(schema, table)); + return escapeNull(join); + } + + private static String escapeNull(String join) { + return join == null ? "%" : join; + } + + private String prepareValue(String value) { + return value == null ? null : value.trim(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + DbPath dbPath = (DbPath) o; + + return path.equals(dbPath.path); + } + + + @Override + public int hashCode() { + return path.hashCode(); + } + + @Override + public String toString() { + return path; + } + + @Override + public int compareTo(DbPath o) { + return path.compareTo(o.path); + } + + public boolean isCover(String catalog, String schema) { + return isCover(catalog, schema, null); + } + + public boolean isCover(String catalog, String schema, String table) { + if (this.catalog == null && catalog == null) { + return schemaCover(schema, table); + } else if (this.catalog == null) { + return schemaCover(schema, table); + } else { + return this.catalog.equalsIgnoreCase(catalog) && schemaCover(schema, table); + } + } + + private boolean schemaCover(String schema, String table) { + if (this.schema == null && schema == null) { + return tableCover(table); + } else if (this.schema == null) { + return tableCover(table); + } else { + return this.schema.equalsIgnoreCase(schema) && tableCover(table); + } + } + + private boolean tableCover(String table) { + return this.tablePattern == null + || table != null && Pattern.compile(this.tablePattern, Pattern.CASE_INSENSITIVE).matcher(table).matches(); + } + + public boolean isCover(DbPath dbPath) { + if (dbPath == null) { + throw new IllegalArgumentException("dbPath can't be null"); + } + return isCover(dbPath.catalog, dbPath.schema, dbPath.tablePattern); + } + + public DbPath merge(DbPath path) { + if (this.isCover(path)) { + return this; + } else if (path.isCover(this)) { + return path; + } else { + return null; + } + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/EntityFilters.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/EntityFilters.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/EntityFilters.java new file mode 100644 index 0000000..83e9a48 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/EntityFilters.java @@ -0,0 +1,424 @@ +/***************************************************************** + * 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.access.loader.filters; + +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.Procedure; +import org.apache.cayenne.util.EqualsBuilder; +import org.apache.cayenne.util.HashCodeBuilder; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import static org.apache.cayenne.access.loader.filters.FilterFactory.*; +import static org.apache.commons.lang.StringUtils.isBlank; + +/** + * @since 3.2. + * @Immutable + */ +public class EntityFilters { + + private static final Log LOG = LogFactory.getLog(Filter.class); + + private final DbPath dbPath; + + private final Filter<String> tableFilters; + private final Filter<String> columnFilters; + private final Filter<String> proceduresFilters; + + + public EntityFilters(DbPath dbPath) { + this(dbPath, NULL, NULL, NULL); + } + public EntityFilters(DbPath dbPath, Filter<String> tableFilters, Filter<String> columnFilters, Filter<String> proceduresFilters) { + this.dbPath = dbPath; + this.tableFilters = set(tableFilters); + this.columnFilters = set(columnFilters); + this.proceduresFilters = set(proceduresFilters); + } + + public boolean isEmpty() { + return (tableFilters == null || NULL.equals(tableFilters)) + && (columnFilters == null || NULL.equals(columnFilters)) + && (proceduresFilters == null || NULL.equals(proceduresFilters)); + } + + public DbPath getDbPath() { + return dbPath; + } + + private Filter<String> set(Filter<String> tableFilters) { + return tableFilters == null ? NULL : tableFilters; + } + + public Filter<DbEntity> tableFilter() { + return new DbEntityFilter(dbPath, tableFilters); + } + + public Filter<DbAttribute> columnFilter() { + return new DbAttributeFilter(dbPath, columnFilters); + } + + public Filter<Procedure> procedureFilter() { + return new ProcedureFilter(dbPath, proceduresFilters); + } + + public EntityFilters join(EntityFilters filter) { + if (filter == null) { + return this; + } + + DbPath path; + if (this.dbPath == null) { + path = filter.dbPath; + } else if (filter.dbPath == null) { + path = this.dbPath; + } else { + path = this.dbPath.merge(filter.dbPath); + } + + return new EntityFilters(path, + this.tableFilters.join(filter.tableFilters), + this.columnFilters.join(filter.columnFilters), + this.proceduresFilters.join(filter.proceduresFilters)); + } + + @Override + public String toString() { + StringBuilder res = new StringBuilder(); + res.append(dbPath).append(":\n"); + if (tableFilters != null) { + res.append(" Table: ").append(tableFilters).append("\n"); + } + + if (columnFilters != null) { + res.append(" Column: ").append(columnFilters).append("\n"); + } + + if (proceduresFilters != null) { + res.append(" Procedures: ").append(proceduresFilters).append("\n"); + } + + return res.toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj == this) { + return true; + } + if (obj.getClass() != getClass()) { + return false; + } + + EntityFilters rhs = (EntityFilters) obj; + return new EqualsBuilder() + .append(this.dbPath, rhs.dbPath) + .append(this.tableFilters, rhs.tableFilters) + .append(this.columnFilters, rhs.columnFilters) + .append(this.proceduresFilters, rhs.proceduresFilters) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder() + .append(dbPath) + .append(tableFilters) + .append(columnFilters) + .append(proceduresFilters) + .toHashCode(); + } + + /** + * @Immutable + * @param <T> + */ + private abstract static class EntityFilter<T> implements Filter<T> { + + private final DbPath dbPath; + private final Filter<String> filter; + + protected EntityFilter(DbPath dbPath, Filter<String> filter) { + this.dbPath = dbPath; + this.filter = filter; + } + + DbPath getDbPath() { + return dbPath; + } + + Filter<String> getFilter() { + return filter; + } + + @Override + public EntityFilter<T> join(Filter<T> filter) { + if (!(filter instanceof EntityFilter)) { + throw new IllegalArgumentException("Unexpected filter join '" + this + "' and '" + filter + "'"); + } + + EntityFilter<T> entityFilter = (EntityFilter<T>) filter; + DbPath dbPath; + if (entityFilter.dbPath.isCover(this.dbPath)) { + dbPath = entityFilter.dbPath; + } else if (this.dbPath.isCover(entityFilter.dbPath)) { + dbPath = this.dbPath; + } else { + throw new IllegalArgumentException("Attempt to merge filter with incompatible tuples: '" + entityFilter.dbPath + "'"); + } + + return create(dbPath, this.filter.join(entityFilter.filter)); + } + + @Override + public String toString() { + return getClass().getSimpleName() + " (" + dbPath + " -> " + filter + ")"; + } + + public abstract EntityFilter<T> create(DbPath dbPath, Filter<String> filter); + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null) { + return false; + } + + if (o instanceof Filter) { // TODO + return filter.equals(o); + } + + if (getClass() != o.getClass()) { + return false; + } + + return filter.equals(((EntityFilter) o).filter); + + } + + @Override + public int hashCode() { + return filter.hashCode(); + } + } + + private static class DbEntityFilter extends EntityFilter<DbEntity> { + + public DbEntityFilter(DbPath dbPath, Filter<String> filter) { + super(dbPath, filter); + } + + @Override + public boolean isInclude(DbEntity obj) { + if (LOG.isTraceEnabled() + && this.getDbPath().isCover(obj.getCatalog(), obj.getSchema())) { + + LOG.warn("Attempt to apply inconvenient filter '" + this + "' for dbEntity '" + obj + "'"); + } + + return this.getFilter().isInclude(obj.getName()); + } + + @Override + public EntityFilter<DbEntity> create(DbPath dbPath, Filter<String> filter) { + return new DbEntityFilter(dbPath, filter); + } + } + + private static class DbAttributeFilter extends EntityFilter<DbAttribute> { + + public DbAttributeFilter(DbPath dbPath, Filter<String> filter) { + super(dbPath, filter); + } + + @Override + public boolean isInclude(DbAttribute obj) { + DbEntity entity = obj.getEntity(); + if (LOG.isTraceEnabled() + && this.getDbPath().isCover(entity.getCatalog(), entity.getSchema(), entity.getName())) { + + LOG.warn("Attempt to apply inconvenient filter '" + this + "' for attribute '" + obj + "'"); + } + + return this.getFilter().isInclude(obj.getName()); + } + + @Override + public EntityFilter<DbAttribute> create(DbPath dbPath, Filter<String> filter) { + return new DbAttributeFilter(dbPath, filter); + } + } + + private static class ProcedureFilter extends EntityFilter<Procedure> { + + public ProcedureFilter(DbPath dbPath, Filter<String> filter) { + super(dbPath, filter); + } + + @Override + public boolean isInclude(Procedure obj) { + if (LOG.isTraceEnabled() + && this.getDbPath().isCover(obj.getCatalog(), obj.getSchema())) { + + LOG.warn("Attempt to apply inconvenient filter '" + this + "' for procedure '" + obj + "'"); + } + return this.getFilter().isInclude(obj.getName()); + } + + @Override + public EntityFilter<Procedure> create(DbPath dbPath, Filter<String> filter) { + return new ProcedureFilter(dbPath, filter); + } + } + + + public static final class Builder { + private String catalog; + private String schema; + + private Filter<String> tableFilters = NULL; + private Filter<String> columnFilters = NULL; + private Filter<String> proceduresFilters = NULL; + + public Builder() { + } + + public Builder catalog(String catalog) { + this.catalog = catalog; + return this; + } + + public Builder schema(String schema) { + this.schema = schema; + return this; + } + + public String schema() { + return schema; + } + + public Builder includeTables(String tableFilters) { + if (isBlank(tableFilters)) { + return this; + } + + for (String pattern : tableFilters.split(",")) { + this.tableFilters = this.tableFilters.join(include(pattern)); + } + + return this; + } + + public Builder includeColumns(String columnFilters) { + if (isBlank(columnFilters)) { + return this; + } + + for (String pattern : columnFilters.split(",")) { + this.columnFilters = this.columnFilters.join(include(pattern)); + } + + return this; + } + + public Builder includeProcedures(String proceduresFilters) { + if (isBlank(proceduresFilters)) { + return this; + } + + for (String pattern : proceduresFilters.split(",")) { + this.proceduresFilters = this.proceduresFilters.join(include(pattern)); + } + + return this; + } + + public Builder excludeTables(String tableFilters) { + if (isBlank(tableFilters)) { + return this; + } + + for (String pattern : tableFilters.split(",")) { + this.tableFilters = this.tableFilters.join(exclude(pattern)); + } + + return this; + } + + public Builder excludeColumns(String columnFilters) { + if (isBlank(columnFilters)) { + return this; + } + + for (String pattern : columnFilters.split(",")) { + this.columnFilters = this.columnFilters.join(exclude(pattern)); + } + + return this; + } + + public Builder excludeProcedures(String proceduresFilters) { + if (isBlank(proceduresFilters)) { + return this; + } + + for (String pattern : proceduresFilters.split(",")) { + this.proceduresFilters = this.proceduresFilters.join(exclude(pattern)); + } + + return this; + } + + public Filter<String> tableFilters() { + return tableFilters; + } + + public Filter<String> columnFilters() { + return columnFilters; + } + + public Filter<String> proceduresFilters() { + return proceduresFilters; + } + + public void setTableFilters(Filter<String> tableFilters) { + this.tableFilters = tableFilters; + } + + public void setColumnFilters(Filter<String> columnFilters) { + this.columnFilters = columnFilters; + } + + public void setProceduresFilters(Filter<String> proceduresFilters) { + this.proceduresFilters = proceduresFilters; + } + + public EntityFilters build() { + return new EntityFilters(new DbPath(catalog, schema), tableFilters, columnFilters, proceduresFilters); + } + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/ExcludeFilter.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/ExcludeFilter.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/ExcludeFilter.java new file mode 100644 index 0000000..932531f --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/ExcludeFilter.java @@ -0,0 +1,42 @@ +/***************************************************************** + * 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.access.loader.filters; + +import java.util.regex.Pattern; + +/** + * @since 4.0 + * @Immutable + */ +public class ExcludeFilter extends IncludeFilter { + + ExcludeFilter(Pattern pattern) { + super(pattern); + } + + @Override + public boolean isInclude(String obj) { + return !super.isInclude(obj); + } + + @Override + public String toString() { + return "-(" + super.getPattern() + ')'; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/Filter.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/Filter.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/Filter.java new file mode 100644 index 0000000..c499276 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/Filter.java @@ -0,0 +1,31 @@ +/***************************************************************** + * 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.access.loader.filters; + +/** + * @since 3.2. + * @Immutable + */ +public interface Filter<T> { + + boolean isInclude(T obj); + + Filter<T> join(Filter<T> filter); + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/FilterFactory.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/FilterFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/FilterFactory.java new file mode 100644 index 0000000..88f3d8d --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/FilterFactory.java @@ -0,0 +1,94 @@ +/***************************************************************** + * 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.access.loader.filters; + +import java.util.regex.Pattern; + +/** + * @since 3.2. + */ +public class FilterFactory { + + public static Filter<String> TRUE = new Filter<String>() { + @Override + public boolean isInclude(String obj) { + return true; + } + + @Override + public Filter<String> join(Filter<String> filter) { + return filter == null || NULL.equals(filter) ? this : filter; + } + + @Override + public boolean equals(Object o) { + return this == o || o != null && getClass() == o.getClass(); + } + + @Override + public String toString() { + return "true"; + } + }; + + public static Filter<String> NULL = new Filter<String>() { + + @Override + public boolean isInclude(String obj) { + return false; + } + + @Override + public Filter<String> join(Filter<String> filter) { + return filter == null ? this : filter; + } + + @Override + public boolean equals(Object o) { + return this == o || o != null && getClass() == o.getClass(); + } + + @Override + public String toString() { + return "null"; + } + }; + + public static Filter<String> include(String tablePattern) { + return new IncludeFilter(pattern(tablePattern)); + } + + public static Filter<String> exclude(String tablePattern) { + return new ExcludeFilter(pattern(tablePattern)); + } + + public static Filter<String> list(Filter<String> ... filters) { + Filter<String> res = NULL; + for (Filter<String> filter : filters) { + res = res.join(filter); + } + return res; + } + + public static Pattern pattern(String tablePattern) { + return Pattern.compile(tablePattern, Pattern.CASE_INSENSITIVE); + } + + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/FiltersConfig.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/FiltersConfig.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/FiltersConfig.java new file mode 100644 index 0000000..4e79811 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/FiltersConfig.java @@ -0,0 +1,180 @@ +/***************************************************************** + * 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.access.loader.filters; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * @since 3.2. + * @Immutable + */ +public class FiltersConfig { + + private final List<DbPath> dbPaths; + private final Map<DbPath, EntityFilters> filters; + + private List<DbPath> pathsForQueries; + + public FiltersConfig(EntityFilters ... filters) { + this(Arrays.asList(filters)); + } + + public FiltersConfig(Collection<EntityFilters> filters) { + this.dbPaths = new LinkedList<DbPath>(); + this.filters = new HashMap<DbPath, EntityFilters>(); + for (EntityFilters filter : filters) { + if (filter == null) { + continue; + } + + DbPath path = filter.getDbPath(); + if (this.dbPaths.contains(path)) { + this.filters.put(path, this.filters.get(path).join(filter)); + continue; + } + + this.dbPaths.add(path); + this.filters.put(path, filter); + } + + Collections.sort(this.dbPaths); + } + + /** + * Used for loading tables and procedures, it's aim avoid unnecessary queries by compacting pairs of + * (Catalog, Schema) + * + * Example: + * <ul> + * <li>"aaa", null</li> + * <li>"aaa", "11"</li> + * <li>"aa", null</li> + * <li>"aa", "a"</li> + * <li>"aa", "aa"</li> + * <li>"aa", "aa"</li> + * </ul> + * + * Should return + * <ul> + * <li>"aa", null</li> + * <li>"aaa", null</li> + * </ul> + * For more examples please see tests. + * + * @return list of pairs (Catalog, Schema) for which getTables and getProcedures should be called + * + **/ + public List<DbPath> pathsForQueries() { + if (pathsForQueries != null) { + return pathsForQueries; + } + + pathsForQueries = new LinkedList<DbPath>(); + if (filters.isEmpty()) { + return pathsForQueries; + } + + boolean save = true; + String catalog = null; + String schema = null; + for (DbPath path : dbPaths) { + if (save || catalog != null && !catalog.equals(path.catalog)) { + catalog = path.catalog; + schema = null; + save = true; + } + + if (save || schema != null && !schema.equals(path.schema)) { + schema = path.schema; + save = true; + } + + if (save) { + save = false; + pathsForQueries.add(new DbPath(catalog, schema)); + } + } + + return pathsForQueries; + } + + /** + * TODO comment + * + * Return filters that applicable for path (filters which path covering path passed in method) + * */ + public EntityFilters filter(DbPath path) { + EntityFilters res = new EntityFilters(path); + for (Map.Entry<DbPath, EntityFilters> entry : filters.entrySet()) { + if (entry.getKey().isCover(path)) { + res = res.join(entry.getValue()); + } + } + + return res; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Map<DbPath, EntityFilters> filters = ((FiltersConfig) o).filters; + if (this.filters.size() != filters.size()) { + return false; + } + + for (Map.Entry<DbPath, EntityFilters> entry : this.filters.entrySet()) { + EntityFilters f = filters.get(entry.getKey()); + if (f == null || !f.equals(entry.getValue())) { + return false; + } + } + return true; + } + + @Override + public String toString() { + StringBuilder res = new StringBuilder(); + for (DbPath dbPath : dbPaths) { + res.append(" ").append(dbPath).append(" -> ").append(filters.get(dbPath)).append("\n"); + } + + return res.toString(); + } + + @Override + public int hashCode() { + return filters.hashCode(); + } + + public List<DbPath> getDbPaths() { + return dbPaths; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/IncludeFilter.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/IncludeFilter.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/IncludeFilter.java new file mode 100644 index 0000000..eeb90dc --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/IncludeFilter.java @@ -0,0 +1,76 @@ +/***************************************************************** + * 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.access.loader.filters; + +import java.util.regex.Pattern; + +/** + * @since 3.2. + * @Immutable + */ +public class IncludeFilter implements Filter<String> { + + private final Pattern pattern; + + IncludeFilter(Pattern pattern) { + this.pattern = pattern; + } + + @Override + public boolean isInclude(String obj) { + return pattern.matcher(obj).matches(); + } + + @Override + public Filter join(Filter filter) { + return ListFilter.create(this, filter); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o instanceof ListFilter) { + return o.equals(this); + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + return pattern.toString().equals(((IncludeFilter) o).pattern.toString()); + + } + + @Override + public int hashCode() { + return pattern.hashCode(); + } + + @Override + public String toString() { + return "+(" + pattern + ')'; + } + + protected Pattern getPattern() { + return pattern; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/ListFilter.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/ListFilter.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/ListFilter.java new file mode 100644 index 0000000..49fdb38 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/ListFilter.java @@ -0,0 +1,123 @@ +/***************************************************************** + * 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.access.loader.filters; + +import org.apache.commons.lang.StringUtils; + +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; + +import static org.apache.cayenne.access.loader.filters.FilterFactory.NULL; +import static org.apache.cayenne.access.loader.filters.FilterFactory.TRUE; + +/** + * @since 3.2. + * @Immutable + */ +public class ListFilter<T> implements Filter<T> { + + private final Collection<Filter<T>> filters; + + public ListFilter(Collection<Filter<T>> filters) { + this.filters = filters; + } + + @Override + public boolean isInclude(T obj) { + for (Filter<T> filter : filters) { + if (!filter.isInclude(obj)) { + return false; + } + } + + return true; + } + + @Override + public Filter<T> join(Filter<T> filter) { + LinkedList<Filter<T>> list = new LinkedList<Filter<T>>(filters); + if (TRUE.equals(filter) || NULL.equals(filter)) { + // Do nothing. + } else if (filter instanceof ListFilter) { + list.addAll(((ListFilter<T>) filter).filters); + } else { + list.add(filter); + } + + return new ListFilter<T>(list); + } + + public static <T> Filter<T> create(Filter<T> filter1, Filter<T> filter2) { + if (filter1 == null || TRUE.equals(filter1) || NULL.equals(filter1)) { + return filter2; + } + + if (filter2 == null || TRUE.equals(filter2) || NULL.equals(filter2)) { + return filter1; + } + + if (filter1 instanceof ListFilter) { + return filter1.join(filter2); + } + + if (filter2 instanceof ListFilter) { + return filter2.join(filter1); + } + + if (filter1.equals(filter2)) { + return filter1; + } + + return new ListFilter<T>(Arrays.asList(filter1, filter2)); + } + + @Override + public String toString() { + return StringUtils.join(filters, " & "); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null) { + return false; + } + + if (getClass() != o.getClass()) { + if (o instanceof Filter && filters.size() == 1) { + return o.equals(filters.iterator().next()); + } else { + return false; + } + } + + ListFilter that = (ListFilter) o; + return filters != null ? filters.equals(that.filters) : that.filters == null; + + } + + @Override + public int hashCode() { + return filters != null ? filters.hashCode() : 0; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/DbType.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/DbType.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/DbType.java new file mode 100644 index 0000000..731f824 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/DbType.java @@ -0,0 +1,195 @@ +/***************************************************************** + * 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.access.loader.mapper; + +import org.apache.cayenne.util.EqualsBuilder; +import org.apache.cayenne.util.HashCodeBuilder; +import org.apache.commons.lang.builder.CompareToBuilder; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import static org.apache.commons.lang.StringUtils.isBlank; + +/** + * @since 3.2. + * @Immutable + */ +public class DbType implements Comparable<DbType> { + + private static final Log LOG = LogFactory.getLog(DbType.class); + + public final String jdbc; + + public final Integer length; + public final Integer precision; + public final Integer scale; + public final Boolean notNull; + + public DbType(String jdbc) { + this(jdbc, null, null, null, null); + } + + public DbType(String jdbc, Integer length, Integer precision, Integer scale, Boolean notNull) { + if (isBlank(jdbc)) { + throw new IllegalArgumentException("Jdbc type can't be null"); + } + this.jdbc = jdbc; + + this.length = getValidInt(length); + this.precision = getValidInt(precision); + this.scale = getValidInt(scale); + this.notNull = notNull; + } + + public String getJdbc() { + return jdbc; + } + + public Integer getLength() { + return length; + } + + public Integer getPrecision() { + return precision; + } + + public Integer getScale() { + return scale; + } + + public Boolean getNotNull() { + return notNull; + } + + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj == this) { + return true; + } + if (obj.getClass() != getClass()) { + return false; + } + DbType rhs = (DbType) obj; + return new EqualsBuilder() + .append(this.jdbc, rhs.jdbc) + .append(this.length, rhs.length) + .append(this.precision, rhs.precision) + .append(this.scale, rhs.scale) + .append(this.notNull, rhs.notNull) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder() + .append(jdbc) + .append(length) + .append(precision) + .append(scale) + .append(notNull) + .toHashCode(); + } + + + @Override + public String toString() { + String res = jdbc; + + String len = "*"; + if (isPositive(length)) { + len = length.toString(); + } + if (isPositive(precision)) { + len = precision.toString(); + } + + res += " (" + len; + if (isPositive(scale)) { + res += ", " + scale; + } + res += ")"; + + if (notNull != null && notNull) { + res += " NOT NULL"; + } + + return res; + } + + private boolean isPositive(Integer num) { + return num != null && num > 0; + } + + private Integer getValidInt(Integer num) { + if (num == null || num > 0) { + return num; + } + + LOG.warn("Invalid int value '" + num + "'"); + return null; + } + + /** + * Compare by specificity the most specific DbPath should be first in ordered list + */ + @Override + public int compareTo(DbType dbType) { + return new CompareToBuilder() + .append(dbType.jdbc, jdbc) + .append(dbType.getSpecificity(), getSpecificity()) + .append(dbType.length, length) + .append(dbType.precision, precision) + .append(dbType.scale, scale) + .append(dbType.notNull, notNull) + .toComparison(); + } + + private int getSpecificity() { + int res = 0; + if (isPositive(length)) { + res += 100; + } + if (isPositive(precision)) { + res += 100; + } + if (isPositive(scale)) { + res += 10; + } + if (this.notNull != null) { + res += 5; + } + + return res; + } + + public boolean isCover(DbType type) { + return this.jdbc.equals(type.jdbc) + && (isCover(length, type.length) || length == null && type.length == null && isCover(precision, type.precision)) + && isCover(scale, type.scale) + && isCover(notNull, type.notNull); + } + + private boolean isCover(Object a, Object b) { + return a == null || a.equals(b); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/DefaultJdbc2JavaTypeMapper.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/DefaultJdbc2JavaTypeMapper.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/DefaultJdbc2JavaTypeMapper.java new file mode 100644 index 0000000..7f37eb7 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/DefaultJdbc2JavaTypeMapper.java @@ -0,0 +1,282 @@ +/***************************************************************** + * 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.access.loader.mapper; + +import org.apache.cayenne.dba.TypesMapping; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.util.Util; + +import java.io.Serializable; +import java.math.BigInteger; +import java.sql.Types; +import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +/** + * @since 3.2. + */ +public class DefaultJdbc2JavaTypeMapper implements Jdbc2JavaTypeMapper { + + // Never use "-1" or any other normal integer, since there + // is a big chance it is being reserved in java.sql.Types + public static final int NOT_DEFINED = Integer.MAX_VALUE; + + // char constants for Java data types + public static final String JAVA_LONG = "java.lang.Long"; + public static final String JAVA_BYTES = "byte[]"; + public static final String JAVA_BOOLEAN = "java.lang.Boolean"; + public static final String JAVA_STRING = "java.lang.String"; + public static final String JAVA_SQLDATE = "java.sql.Date"; + public static final String JAVA_UTILDATE = "java.util.Date"; + public static final String JAVA_BIGDECIMAL = "java.math.BigDecimal"; + public static final String JAVA_DOUBLE = "java.lang.Double"; + public static final String JAVA_FLOAT = "java.lang.Float"; + public static final String JAVA_INTEGER = "java.lang.Integer"; + public static final String JAVA_SHORT = "java.lang.Short"; + public static final String JAVA_BYTE = "java.lang.Byte"; + public static final String JAVA_TIME = "java.sql.Time"; + public static final String JAVA_TIMESTAMP = "java.sql.Timestamp"; + public static final String JAVA_BLOB = "java.sql.Blob"; + + /** + * Keys: java class names, Values: SQL int type definitions from java.sql.Types + */ + private final Map<String, Integer> javaSqlEnum = new HashMap<String, Integer>(); + + private final Map<DbType, String> mapping = new HashMap<DbType, String>(); + private final SortedSet<DbType> dbTypes = new TreeSet<DbType>(); + + private Map<String, String> classToPrimitive; + + { + add(Types.BIGINT, JAVA_LONG); + add(Types.BINARY, JAVA_BYTES); + add(Types.BIT, JAVA_BOOLEAN); + add(Types.BOOLEAN, JAVA_BOOLEAN); + add(Types.BLOB, JAVA_BYTES); + add(Types.CLOB, JAVA_STRING); + add(Types.CHAR, JAVA_STRING); + add(Types.DATE, JAVA_UTILDATE); + add(Types.DECIMAL, JAVA_BIGDECIMAL); + add(Types.DOUBLE, JAVA_DOUBLE); + add(Types.FLOAT, JAVA_FLOAT); + add(Types.INTEGER, JAVA_INTEGER); + add(Types.LONGVARCHAR, JAVA_STRING); + add(Types.LONGVARBINARY, JAVA_BYTES); + add(Types.NUMERIC, JAVA_BIGDECIMAL); + add(Types.REAL, JAVA_FLOAT); + add(Types.SMALLINT, JAVA_SHORT); + add(Types.TINYINT, JAVA_SHORT); + add(Types.TIME, JAVA_UTILDATE); + add(Types.TIMESTAMP, JAVA_UTILDATE); + add(Types.VARBINARY, JAVA_BYTES); + add(Types.VARCHAR, JAVA_STRING); + + javaSqlEnum.put(JAVA_LONG, Types.BIGINT); + javaSqlEnum.put(JAVA_BYTES, Types.BINARY); + javaSqlEnum.put(JAVA_BOOLEAN, Types.BIT); + javaSqlEnum.put(JAVA_STRING, Types.VARCHAR); + javaSqlEnum.put(JAVA_SQLDATE, Types.DATE); + javaSqlEnum.put(JAVA_UTILDATE, Types.DATE); + javaSqlEnum.put(JAVA_TIMESTAMP, Types.TIMESTAMP); + javaSqlEnum.put(JAVA_BIGDECIMAL, Types.DECIMAL); + javaSqlEnum.put(JAVA_DOUBLE, Types.DOUBLE); + javaSqlEnum.put(JAVA_FLOAT, Types.FLOAT); + javaSqlEnum.put(JAVA_INTEGER, Types.INTEGER); + javaSqlEnum.put(JAVA_SHORT, Types.SMALLINT); + javaSqlEnum.put(JAVA_BYTE, Types.SMALLINT); + javaSqlEnum.put(JAVA_TIME, Types.TIME); + javaSqlEnum.put(JAVA_TIMESTAMP, Types.TIMESTAMP); + + // add primitives + javaSqlEnum.put("byte", Types.TINYINT); + javaSqlEnum.put("int", Types.INTEGER); + javaSqlEnum.put("short", Types.SMALLINT); + javaSqlEnum.put("char", Types.CHAR); + javaSqlEnum.put("double", Types.DOUBLE); + javaSqlEnum.put("long", Types.BIGINT); + javaSqlEnum.put("float", Types.FLOAT); + javaSqlEnum.put("boolean", Types.BIT); + + classToPrimitive = new HashMap<String, String>(); + classToPrimitive.put(Byte.class.getName(), "byte"); + classToPrimitive.put(Long.class.getName(), "long"); + classToPrimitive.put(Double.class.getName(), "double"); + classToPrimitive.put(Boolean.class.getName(), "boolean"); + classToPrimitive.put(Float.class.getName(), "float"); + classToPrimitive.put(Short.class.getName(), "short"); + classToPrimitive.put(Integer.class.getName(), "int"); + } + + private Boolean usePrimitives; + + + /** + * Returns default java.sql.Types type by the Java type name. + * + * @param className Fully qualified Java Class name. + * @return The SQL type or NOT_DEFINED if no type found. + */ + public int getJdbcTypeByJava(DbAttribute attribute, String className) { + if (className == null) { + return NOT_DEFINED; + } + + Integer type = javaSqlEnum.get(className); + if (type != null) { + return type; + } + + // try to load a Java class - some nonstandard mappings may work + try { + return getSqlTypeByJava(attribute, Util.getJavaClass(className)); + } catch (Throwable th) { + return NOT_DEFINED; + } + } + + + public void add(int jdbcType, String java) { + add(new DbType(TypesMapping.getSqlNameByType(jdbcType)), java); + } + + @Override + public void add(DbType type, String java) { + mapping.put(type, java); + dbTypes.add(type); + } + + /** + * Guesses a default JDBC type for the Java class. + * + * @since 1.1 + */ + protected int getSqlTypeByJava(DbAttribute attribute, Class<?> javaClass) { + if (javaClass == null) { + return NOT_DEFINED; + } + + // check standard mapping of class and superclasses + Class<?> aClass = javaClass; + while (aClass != null) { + + String name; + + if (aClass.isArray()) { + name = aClass.getComponentType().getName() + "[]"; + } else { + name = aClass.getName(); + } + + Object type = javaSqlEnum.get(name); + if (type != null) { + return ((Number) type).intValue(); + } + + aClass = aClass.getSuperclass(); + } + + // check non-standard JDBC types that are still supported by JPA + if (javaClass.isArray()) { + + Class<?> elementType = javaClass.getComponentType(); + if (Character.class.isAssignableFrom(elementType) + || Character.TYPE.isAssignableFrom(elementType)) { + return Types.VARCHAR; + } + else if (Byte.class.isAssignableFrom(elementType) + || Byte.TYPE.isAssignableFrom(elementType)) { + return Types.VARBINARY; + } + } + + if (Calendar.class.isAssignableFrom(javaClass)) { + return Types.TIMESTAMP; + } + + if (BigInteger.class.isAssignableFrom(javaClass)) { + return Types.BIGINT; + } + + if (Serializable.class.isAssignableFrom(javaClass)) { + // serializable check should be the last one when all other mapping attempts failed + return Types.VARBINARY; + } + + return NOT_DEFINED; + } + + /** + * Get the corresponding Java type by its java.sql.Types counterpart. Note that this + * method should be used as a last resort, with explicit mapping provided by user used + * as a first choice, as it can only guess how to map certain types, such as NUMERIC, + * etc. + * + * @return Fully qualified Java type name or null if not found. + */ + @Override + public String getJavaByJdbcType(DbAttribute attribute, int type) { + String jdbcType = TypesMapping.getSqlNameByType(type); + DbType dbType; + if (attribute != null) { + dbType = new DbType( + jdbcType, + attribute.getMaxLength(), + attribute.getAttributePrecision(), + attribute.getScale(), + attribute.isMandatory()); + } else { + dbType = new DbType(jdbcType); + } + + String typeName = getJavaByJdbcType(dbType); + + if (usePrimitives != null && usePrimitives) { + String primitive = classToPrimitive.get(typeName); + if (primitive != null) { + return primitive; + } + } + + return typeName; + } + + public String getJavaByJdbcType(DbType type) { + for (DbType t : dbTypes) { + if (t.isCover(type)) { + // because dbTypes sorted by specificity we will take first and the most specific matching + // that applicable for attribute + return mapping.get(t); + } + } + + return null; + } + + public Boolean getUsePrimitives() { + return usePrimitives; + } + + public void setUsePrimitives(Boolean usePrimitives) { + this.usePrimitives = usePrimitives; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/Jdbc2JavaTypeMapper.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/Jdbc2JavaTypeMapper.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/Jdbc2JavaTypeMapper.java new file mode 100644 index 0000000..8e4510c --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/Jdbc2JavaTypeMapper.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.access.loader.mapper; + +import org.apache.cayenne.map.DbAttribute; + +/** + * @since 3.2. + */ +public interface Jdbc2JavaTypeMapper { + + String getJavaByJdbcType(DbAttribute attribute, int type); + + int getJdbcTypeByJava(DbAttribute attribute, String className); + + void add(DbType type, String java); +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/configuration/DefaultConfigurationNameMapper.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/DefaultConfigurationNameMapper.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/DefaultConfigurationNameMapper.java index ba7dcd4..08bf584 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/DefaultConfigurationNameMapper.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/DefaultConfigurationNameMapper.java @@ -1,21 +1,21 @@ -/***************************************************************** - * 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 +/* + * 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 + * 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. - ****************************************************************/ + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package org.apache.cayenne.configuration; import org.apache.cayenne.map.DataMap; @@ -31,7 +31,7 @@ public class DefaultConfigurationNameMapper implements ConfigurationNameMapper { private static final String DATA_MAP_SUFFIX = ".map.xml"; - protected ConfigurationNodeVisitor<String> nameMapper; + private final ConfigurationNodeVisitor<String> nameMapper; public DefaultConfigurationNameMapper() { nameMapper = new NameMapper(); @@ -41,23 +41,18 @@ public class DefaultConfigurationNameMapper implements ConfigurationNameMapper { return node.acceptVisitor(nameMapper); } - public String configurationLocation( - Class<? extends ConfigurationNode> type, - String name) { + public String configurationLocation(Class<? extends ConfigurationNode> type, String name) { if (DataChannelDescriptor.class.isAssignableFrom(type)) { return getDataChannelName(name); } - else if (DataMap.class.isAssignableFrom(type)) { + if (DataMap.class.isAssignableFrom(type)) { return getDataMapName(name); } - throw new IllegalArgumentException("Unrecognized configuration type: " - + type.getName()); + throw new IllegalArgumentException("Unrecognized configuration type: " + type.getName()); } - public String configurationNodeName( - Class<? extends ConfigurationNode> type, - Resource resource) { + public String configurationNodeName(Class<? extends ConfigurationNode> type, Resource resource) { String path = resource.getURL().getPath(); if (path == null || path.length() == 0) { @@ -80,37 +75,36 @@ public class DefaultConfigurationNameMapper implements ConfigurationNameMapper { return null; } - return path.substring(CAYENNE_PREFIX.length(), path.length() - - CAYENNE_SUFFIX.length()); + return path.substring(CAYENNE_PREFIX.length(), path.length() - CAYENNE_SUFFIX.length()); } - else if (DataMap.class.isAssignableFrom(type)) { + + if (DataMap.class.isAssignableFrom(type)) { if (!path.endsWith(DATA_MAP_SUFFIX)) { return null; } return path.substring(0, path.length() - DATA_MAP_SUFFIX.length()); } - throw new IllegalArgumentException("Unrecognized configuration type: " - + type.getName()); + throw new IllegalArgumentException("Unrecognized configuration type: " + type.getName()); } - protected String getDataChannelName(String name) { + protected static String getDataChannelName(String name) { if (name == null) { - throw new NullPointerException("Null DataChannelDescriptor name"); + throw new IllegalArgumentException("Null DataChannelDescriptor name"); } return CAYENNE_PREFIX + name + CAYENNE_SUFFIX; } - protected String getDataMapName(String name) { + protected static String getDataMapName(String name) { if (name == null) { - throw new NullPointerException("Null DataMap name"); + throw new IllegalArgumentException("Null DataMap name"); } return name + DATA_MAP_SUFFIX; } - final class NameMapper extends BaseConfigurationNodeVisitor<String> { + private final class NameMapper extends BaseConfigurationNodeVisitor<String> { @Override public String visitDataChannelDescriptor(DataChannelDescriptor descriptor) { http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/dba/JdbcAdapter.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/JdbcAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/JdbcAdapter.java index a91126a..b57dc33 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/JdbcAdapter.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/JdbcAdapter.java @@ -1,21 +1,21 @@ -/***************************************************************** - * 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 +/* + * 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 + * 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. - ****************************************************************/ + * 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.dba; @@ -335,10 +335,11 @@ public class JdbcAdapter implements DbAdapter { boolean firstPk = true; while (pkit.hasNext()) { - if (firstPk) + if (firstPk) { firstPk = false; - else + } else { sqlBuffer.append(", "); + } DbAttribute at = pkit.next(); @@ -355,43 +356,41 @@ public class JdbcAdapter implements DbAdapter { */ @Override public void createTableAppendColumn(StringBuffer sqlBuffer, DbAttribute column) { - - String[] types = externalTypesForJdbcType(column.getType()); - if (types == null || types.length == 0) { - String entityName = column.getEntity() != null ? ((DbEntity) column.getEntity()).getFullyQualifiedName() - : "<null>"; - throw new CayenneRuntimeException("Undefined type for attribute '" + entityName + "." + column.getName() - + "': " + column.getType()); - } - - String type = types[0]; sqlBuffer.append(quotingStrategy.quotedName(column)); - sqlBuffer.append(' ').append(type); - - // append size and precision (if applicable)s - if (typeSupportsLength(column.getType())) { - int len = column.getMaxLength(); + sqlBuffer.append(' ').append(getType(this, column)); - int scale = (TypesMapping.isDecimal(column.getType()) && column.getType() != Types.FLOAT) ? column - .getScale() : -1; + sqlBuffer.append(sizeAndPrecision(this, column)); + sqlBuffer.append(column.isMandatory() ? " NOT NULL" : " NULL"); + } - // sanity check - if (scale > len) { - scale = -1; - } + public static String sizeAndPrecision(DbAdapter adapter, DbAttribute column) { + if (!adapter.typeSupportsLength(column.getType())) { + return ""; + } - if (len > 0) { - sqlBuffer.append('(').append(len); + int len = column.getMaxLength(); + int scale = TypesMapping.isDecimal(column.getType()) && column.getType() != Types.FLOAT ? column.getScale() : -1; - if (scale >= 0) { - sqlBuffer.append(", ").append(scale); - } + // sanity check + if (scale > len) { + scale = -1; + } - sqlBuffer.append(')'); - } + if (len > 0) { + return "(" + len + (scale >= 0 ? ", " + scale : "") + ")"; } - sqlBuffer.append(column.isMandatory() ? " NOT NULL" : " NULL"); + return ""; + } + + public static String getType(DbAdapter adapter, DbAttribute column) { + String[] types = adapter.externalTypesForJdbcType(column.getType()); + if (types == null || types.length == 0) { + String entityName = column.getEntity() != null ? column.getEntity().getFullyQualifiedName() : "<null>"; + throw new CayenneRuntimeException("Undefined type for attribute '" + + entityName + "." + column.getName() + "': " + column.getType()); + } + return types[0]; } /** http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/map/DataMap.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/DataMap.java b/cayenne-server/src/main/java/org/apache/cayenne/map/DataMap.java index 48c6502..2d8be80 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/map/DataMap.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/map/DataMap.java @@ -1356,4 +1356,39 @@ public class DataMap implements Serializable, ConfigurationNode, XMLSerializable clearQueries(); clearResultSets(); } + + /** + * + * @return package + "." + name when it is possible otherwise just name + * + * @since 3.2 + */ + public String getNameWithDefaultPackage(String name) { + return getNameWithPackage(defaultPackage, name); + } + + /** + * + * @return package + "." + name when it is possible otherwise just name + * + * @since 3.2 + */ + public static String getNameWithPackage(String pack, String name) { + if (Util.isEmptyString(pack)) { + return name; + } else { + return pack + (pack.endsWith(".") ? "" : ".") + name; + } + } + + /** + * + * @param name + * @return package + "." + name when it is possible otherwise just name + * + * @since 3.2 + */ + public String getNameWithDefaultClientPackage(String name) { + return getNameWithPackage(defaultClientPackage, name); + } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java b/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java index c595f56..5234ff4 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java @@ -196,8 +196,9 @@ public class DbRelationship extends Relationship implements ConfigurationNode { TestJoin testJoin = new TestJoin(this); for (DbRelationship rel : target.getRelationships()) { - if (rel.getTargetEntity() != src) + if (rel.getTargetEntity() != src) { continue; + } List<DbJoin> otherJoins = rel.getJoins(); if (otherJoins.size() != joins.size()) { @@ -273,7 +274,7 @@ public class DbRelationship extends Relationship implements ConfigurationNode { } DbRelationship revRel = getReverseRelationship(); - return (revRel != null) ? revRel.isToDependentPK() : false; + return revRel != null && revRel.isToDependentPK(); } /** @@ -315,7 +316,7 @@ public class DbRelationship extends Relationship implements ConfigurationNode { DbAttribute target = join.getTarget(); DbAttribute source = join.getSource(); - if ((target != null && !target.isPrimaryKey()) || (source != null && !source.isPrimaryKey())) { + if (target != null && !target.isPrimaryKey() || source != null && !source.isPrimaryKey()) { return false; } } @@ -390,8 +391,7 @@ public class DbRelationship extends Relationship implements ConfigurationNode { // handle generic case: numJoins > 1 else { idMap = new HashMap<String, Object>(numJoins * 2); - for (int i = 0; i < numJoins; i++) { - DbJoin join = joins.get(i); + for (DbJoin join : joins) { DbAttribute source = join.getSource(); Object val = srcSnapshot.get(join.getSourceName()); @@ -437,8 +437,7 @@ public class DbRelationship extends Relationship implements ConfigurationNode { // general case Map<String, Object> idMap = new HashMap<String, Object>(len * 2); - for (int i = 0; i < len; i++) { - DbJoin join = joins.get(i); + for (DbJoin join : joins) { Object val = targetSnapshot.get(join.getTargetName()); idMap.put(join.getSourceName(), val); } @@ -468,8 +467,10 @@ public class DbRelationship extends Relationship implements ConfigurationNode { * relationship is "to one". */ public Map<String, Object> srcPkSnapshotWithTargetSnapshot(Map<String, Object> targetSnapshot) { - if (!isToMany()) + if (!isToMany()) { throw new CayenneRuntimeException("Only 'to many' relationships support this method."); + } + return srcSnapshotWithTargetSnapshot(targetSnapshot); } @@ -491,7 +492,7 @@ public class DbRelationship extends Relationship implements ConfigurationNode { return false; } - final static class JoinTransformers { + static final class JoinTransformers { static final Transformer targetExtractor = new Transformer() { @@ -509,7 +510,7 @@ public class DbRelationship extends Relationship implements ConfigurationNode { } // a join used for comparison - final static class TestJoin extends DbJoin { + static final class TestJoin extends DbJoin { TestJoin(DbRelationship relationship) { super(relationship); http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/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 dba2c08..94ddfca 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 @@ -55,8 +55,8 @@ import org.apache.commons.collections.Transformer; */ public class ObjEntity extends Entity implements ObjEntityListener, ConfigurationNode { - final public static int LOCK_TYPE_NONE = 0; - final public static int LOCK_TYPE_OPTIMISTIC = 1; + public static final int LOCK_TYPE_NONE = 0; + public static final int LOCK_TYPE_OPTIMISTIC = 1; // do not import CayenneDataObject as it introduces unneeded client // dependency @@ -320,7 +320,7 @@ public class ObjEntity extends Entity implements ObjEntityListener, Configuratio try { return Util.getJavaClass(name); } catch (ClassNotFoundException e) { - throw new CayenneRuntimeException("Failed to load class " + name + ": " + e.getMessage(), e); + throw new CayenneRuntimeException("Failed to doLoad class " + name + ": " + e.getMessage(), e); } } @@ -461,7 +461,7 @@ public class ObjEntity extends Entity implements ObjEntityListener, Configuratio * @since 1.2 */ public boolean isClientAllowed() { - return (getDataMap() == null || isServerOnly()) ? false : getDataMap().isClientSupported(); + return getDataMap() != null && !isServerOnly() && getDataMap().isClientSupported(); } public boolean isAbstract() { @@ -948,12 +948,13 @@ public class ObjEntity extends Entity implements ObjEntityListener, Configuratio * Clears mapping between entities, attributes and relationships. */ public void clearDbMapping() { - if (dbEntityName == null) + if (dbEntityName == null) { return; + } for (ObjAttribute attribute : getAttributeMap().values()) { DbAttribute dbAttr = attribute.getDbAttribute(); - if (null != dbAttr) { + if (dbAttr != null) { attribute.setDbAttributePath(null); } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/cayenne-server/src/main/java/org/apache/cayenne/map/naming/DefaultUniqueNameGenerator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/naming/DefaultUniqueNameGenerator.java b/cayenne-server/src/main/java/org/apache/cayenne/map/naming/DefaultUniqueNameGenerator.java index 0117a4f..409a48e 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/map/naming/DefaultUniqueNameGenerator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/map/naming/DefaultUniqueNameGenerator.java @@ -49,12 +49,7 @@ public class DefaultUniqueNameGenerator implements UniqueNameGenerator { generator = new DefaultUniqueNameGenerator(NameCheckers.embeddable, pattern) { @Override public String generate(Object namingContext, String nameBase) { - String name = super.generate(namingContext, nameBase); - DataMap map = (DataMap) namingContext; - if (map.getDefaultPackage() != null) { - return map.getDefaultPackage() + "." + name; - } - return name; + return ((DataMap) namingContext).getNameWithDefaultPackage(super.generate(namingContext, nameBase)); } }; } else { http://git-wip-us.apache.org/repos/asf/cayenne/blob/276f049c/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 index 20b250c..eb7fb37 100644 --- 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 @@ -75,11 +75,7 @@ public enum NameCheckers implements NameChecker { @Override public boolean isNameInUse(Object namingContext, String name) { DataMap map = (DataMap) namingContext; - if (map.getDefaultPackage() != null) { - return map - .getEmbeddable((map.getDefaultPackage() + "." + name)) != null; - } - return map.getEmbeddable(name) != null; + return map.getEmbeddable(map.getNameWithDefaultPackage(name)) != null; } },