You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2014/10/29 19:40:41 UTC
[6/7] CAY-1946 CDbimport improvements
http://git-wip-us.apache.org/repos/asf/cayenne/blob/fde7761f/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/fde7761f/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/fde7761f/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..5fde570
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/filters/EntityFilters.java
@@ -0,0 +1,399 @@
+/*****************************************************************
+ * 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.*;
+
+/**
+ * @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) {
+ for (String pattern : tableFilters.split(",")) {
+ this.tableFilters = this.tableFilters.join(include(pattern));
+ }
+
+ return this;
+ }
+
+ public Builder includeColumns(String columnFilters) {
+ for (String pattern : columnFilters.split(",")) {
+ this.columnFilters = this.columnFilters.join(include(pattern));
+ }
+
+ return this;
+ }
+
+ public Builder includeProcedures(String proceduresFilters) {
+ for (String pattern : proceduresFilters.split(",")) {
+ this.proceduresFilters = this.proceduresFilters.join(include(pattern));
+ }
+
+ return this;
+ }
+
+ public Builder excludeTables(String tableFilters) {
+ for (String pattern : tableFilters.split(",")) {
+ this.tableFilters = this.tableFilters.join(exclude(pattern));
+ }
+
+ return this;
+ }
+
+ public Builder excludeColumns(String columnFilters) {
+ for (String pattern : columnFilters.split(",")) {
+ this.columnFilters = this.columnFilters.join(exclude(pattern));
+ }
+
+ return this;
+ }
+
+ public Builder excludeProcedures(String proceduresFilters) {
+ 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/fde7761f/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..5bc794a
--- /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 3.2.
+ * @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/fde7761f/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/fde7761f/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/fde7761f/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/fde7761f/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/fde7761f/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/fde7761f/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/fde7761f/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/fde7761f/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/fde7761f/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/fde7761f/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 5d6a372..4764b69 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/fde7761f/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 5f1f10c..6441070 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/fde7761f/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 e84a5a8..69f661a 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/fde7761f/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 6fb47de..67317e3 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/fde7761f/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 c9989d4..95ab877 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/fde7761f/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 ea8f393..f86f043 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;
}
},