You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metamodel.apache.org by ka...@apache.org on 2013/07/22 10:10:55 UTC
[42/64] [partial] Hard rename of all 'org/eobjects' folders to
'org/apache'.
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/parser/QueryPartProcessor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/parser/QueryPartProcessor.java b/core/src/main/java/org/apache/metamodel/query/parser/QueryPartProcessor.java
new file mode 100644
index 0000000..27a5d88
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/parser/QueryPartProcessor.java
@@ -0,0 +1,38 @@
+/**
+ * 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.eobjects.metamodel.query.parser;
+
+/**
+ * Callback of the {@link QueryPartParser}, which recieves notifications
+ * whenever a token is identified/parsed. A {@link QueryPartProcessor} is used
+ * to perform the actual processing of identified tokens.
+ */
+public interface QueryPartProcessor {
+
+ /**
+ * Method invoked whenever the {@link QueryPartParser} identifies a token.
+ *
+ * @param delim
+ * the (previous) delimitor identified before the token. This
+ * will always be null in case of the first token.
+ * @param token
+ * the token identified.
+ */
+ public void parse(String delim, String token);
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/parser/SelectItemParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/parser/SelectItemParser.java b/core/src/main/java/org/apache/metamodel/query/parser/SelectItemParser.java
new file mode 100644
index 0000000..2810a4a
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/parser/SelectItemParser.java
@@ -0,0 +1,170 @@
+/**
+ * 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.eobjects.metamodel.query.parser;
+
+import org.eobjects.metamodel.MetaModelException;
+import org.eobjects.metamodel.query.FromItem;
+import org.eobjects.metamodel.query.FunctionType;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+
+public final class SelectItemParser implements QueryPartProcessor {
+
+ public static class MultipleSelectItemsParsedException extends IllegalArgumentException {
+
+ private static final long serialVersionUID = 1L;
+
+ private final FromItem _fromItem;
+
+ public MultipleSelectItemsParsedException(FromItem fromItem) {
+ _fromItem = fromItem;
+ }
+
+ public FromItem getFromItem() {
+ return _fromItem;
+ }
+ }
+
+ private final Query _query;
+ private final boolean _allowExpressionBasedSelectItems;
+
+ public SelectItemParser(Query query, boolean allowExpressionBasedSelectItems) {
+ _query = query;
+ _allowExpressionBasedSelectItems = allowExpressionBasedSelectItems;
+ }
+
+ @Override
+ public void parse(String delim, String itemToken) throws MetaModelException {
+ if ("*".equals(itemToken)) {
+ _query.selectAll();
+ return;
+ }
+
+ String alias = null;
+ final int indexOfAlias = itemToken.toUpperCase().lastIndexOf(" AS ");
+ if (indexOfAlias != -1) {
+ alias = itemToken.substring(indexOfAlias + " AS ".length());
+ itemToken = itemToken.substring(0, indexOfAlias);
+ }
+
+ try {
+ final SelectItem selectItem = findSelectItem(itemToken);
+ if (selectItem == null) {
+ throw new QueryParserException("Not capable of parsing SELECT token: " + itemToken);
+ }
+
+ if (alias != null) {
+ selectItem.setAlias(alias);
+ }
+
+ _query.select(selectItem);
+ } catch (MultipleSelectItemsParsedException e) {
+ FromItem fromItem = e.getFromItem();
+ if (fromItem != null) {
+ _query.selectAll(fromItem);
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * Finds/creates a SelectItem based on the given expression. Unlike the
+ * {@link #parse(String, String)} method, this method will not actually add
+ * the selectitem to the query.
+ *
+ * @param expression
+ * @return
+ *
+ * @throws MultipleSelectItemsParsedException
+ * if an expression yielding multiple select-items (such as "*")
+ * was passed in the expression
+ */
+ public SelectItem findSelectItem(String expression) throws MultipleSelectItemsParsedException {
+ if ("*".equals(expression)) {
+ throw new MultipleSelectItemsParsedException(null);
+ }
+
+ if ("COUNT(*)".equalsIgnoreCase(expression)) {
+ return SelectItem.getCountAllItem();
+ }
+
+ final FunctionType function;
+ final int startParenthesis = expression.indexOf('(');
+ if (startParenthesis > 0 && expression.endsWith(")")) {
+ String functionName = expression.substring(0, startParenthesis);
+ function = FunctionType.get(functionName);
+ if (function != null) {
+ expression = expression.substring(startParenthesis + 1, expression.length() - 1).trim();
+ if (function == FunctionType.COUNT && "*".equals(expression)) {
+ return SelectItem.getCountAllItem();
+ }
+ }
+ } else {
+ function = null;
+ }
+
+ int lastIndexOfDot = expression.lastIndexOf(".");
+
+ String columnName = null;
+ FromItem fromItem = null;
+
+ if (lastIndexOfDot != -1) {
+ String prefix = expression.substring(0, lastIndexOfDot);
+ columnName = expression.substring(lastIndexOfDot + 1);
+ fromItem = _query.getFromClause().getItemByReference(prefix);
+ }
+
+ if (fromItem == null) {
+ if (_query.getFromClause().getItemCount() == 1) {
+ fromItem = _query.getFromClause().getItem(0);
+ columnName = expression;
+ } else {
+ fromItem = null;
+ columnName = null;
+ }
+ }
+
+ if (fromItem != null) {
+ if ("*".equals(columnName)) {
+ throw new MultipleSelectItemsParsedException(fromItem);
+ } else if (fromItem.getTable() != null) {
+ Column column = fromItem.getTable().getColumnByName(columnName);
+ if (column != null) {
+ SelectItem selectItem = new SelectItem(function, column, fromItem);
+ return selectItem;
+ }
+ } else if (fromItem.getSubQuery() != null) {
+ final Query subQuery = fromItem.getSubQuery();
+ final SelectItem subQuerySelectItem = new SelectItemParser(subQuery, _allowExpressionBasedSelectItems).findSelectItem(columnName);
+ if (subQuerySelectItem == null) {
+ return null;
+ }
+ return new SelectItem(subQuerySelectItem, fromItem);
+ }
+ }
+
+ if (_allowExpressionBasedSelectItems) {
+ return new SelectItem(function, expression, null);
+ }
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/parser/WhereItemParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/parser/WhereItemParser.java b/core/src/main/java/org/apache/metamodel/query/parser/WhereItemParser.java
new file mode 100644
index 0000000..764fbdc
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/parser/WhereItemParser.java
@@ -0,0 +1,35 @@
+/**
+ * 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.eobjects.metamodel.query.parser;
+
+import org.eobjects.metamodel.query.Query;
+
+final class WhereItemParser implements QueryPartProcessor {
+
+ private final Query _query;
+
+ public WhereItemParser(Query query) {
+ _query = query;
+ }
+
+ @Override
+ public void parse(String delim, String itemToken) {
+ _query.where(itemToken);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/AbstractColumn.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/AbstractColumn.java b/core/src/main/java/org/apache/metamodel/schema/AbstractColumn.java
new file mode 100644
index 0000000..85cc2e4
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/AbstractColumn.java
@@ -0,0 +1,104 @@
+/**
+ * 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.eobjects.metamodel.schema;
+
+/**
+ * Abstract {@link Column} implementation. Implements most common and trivial
+ * methods.
+ *
+ * @author Kasper Sørensen
+ */
+public abstract class AbstractColumn implements Column {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public final String getQuotedName() {
+ String quote = getQuote();
+ if (quote == null) {
+ return getName();
+ }
+ return quote + getName() + quote;
+ }
+
+ @Override
+ public final String getQualifiedLabel() {
+ StringBuilder sb = new StringBuilder();
+ Table table = getTable();
+ if (table != null) {
+ sb.append(table.getQualifiedLabel());
+ sb.append('.');
+ }
+ sb.append(getName());
+ return sb.toString();
+ }
+
+ @Override
+ public final int compareTo(Column that) {
+ int diff = getQualifiedLabel().compareTo(that.getQualifiedLabel());
+ if (diff == 0) {
+ diff = toString().compareTo(that.toString());
+ }
+ return diff;
+ }
+
+ @Override
+ public final String toString() {
+ return "Column[name=" + getName() + ",columnNumber=" + getColumnNumber() + ",type=" + getType() + ",nullable="
+ + isNullable() + ",nativeType=" + getNativeType() + ",columnSize=" + getColumnSize() + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ return getName().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Column) {
+ Column other = (Column) obj;
+ if (!getName().equals(other.getName())) {
+ return false;
+ }
+ if (getType() != other.getType()) {
+ return false;
+ }
+
+ final Table table1 = getTable();
+ final Table table2 = other.getTable();
+ if (table1 == null) {
+ if (table2 != null) {
+ return false;
+ }
+ } else {
+ if (!table1.equals(table2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/AbstractRelationship.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/AbstractRelationship.java b/core/src/main/java/org/apache/metamodel/schema/AbstractRelationship.java
new file mode 100644
index 0000000..c1d5646
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/AbstractRelationship.java
@@ -0,0 +1,119 @@
+/**
+ * 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.eobjects.metamodel.schema;
+
+import java.util.List;
+
+import org.eobjects.metamodel.util.BaseObject;
+
+public abstract class AbstractRelationship extends BaseObject implements
+ Relationship {
+
+ private static final long serialVersionUID = 1L;
+
+ protected static Table checkSameTable(Column[] columns) {
+ if (columns == null || columns.length == 0) {
+ throw new IllegalArgumentException(
+ "At least one key-column must exist on both "
+ + "primary and foreign side for "
+ + "a relation to exist.");
+ }
+ Table table = null;
+ for (int i = 0; i < columns.length; i++) {
+ Column column = columns[i];
+ if (i == 0) {
+ table = column.getTable();
+ } else {
+ if (table != column.getTable()) {
+ throw new IllegalArgumentException(
+ "Key-columns did not have same table");
+ }
+ }
+ }
+ return table;
+ }
+
+ @Override
+ public Table getForeignTable() {
+ return getForeignColumns()[0].getTable();
+ }
+
+ @Override
+ public Table getPrimaryTable() {
+ return getPrimaryColumns()[0].getTable();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Relationship[");
+ sb.append("primaryTable=" + getPrimaryTable().getName());
+ Column[] columns = getPrimaryColumns();
+ sb.append(",primaryColumns=[");
+ for (int i = 0; i < columns.length; i++) {
+ if (i != 0) {
+ sb.append(", ");
+ }
+ sb.append(columns[i].getName());
+ }
+ sb.append("]");
+ sb.append(",foreignTable=" + getForeignTable().getName());
+ columns = getForeignColumns();
+ sb.append(",foreignColumns=[");
+ for (int i = 0; i < columns.length; i++) {
+ if (i != 0) {
+ sb.append(", ");
+ }
+ sb.append(columns[i].getName());
+ }
+ sb.append("]");
+ sb.append("]");
+ return sb.toString();
+ }
+
+ public int compareTo(Relationship that) {
+ return toString().compareTo(that.toString());
+ }
+
+ @Override
+ protected final void decorateIdentity(List<Object> identifiers) {
+ identifiers.add(getPrimaryColumns());
+ identifiers.add(getForeignColumns());
+ }
+
+ @Override
+ protected final boolean classEquals(BaseObject obj) {
+ return obj instanceof Relationship;
+ }
+
+ @Override
+ public boolean containsColumnPair(Column pkColumn, Column fkColumn) {
+ if (pkColumn != null && fkColumn != null) {
+ Column[] primaryColumns = getPrimaryColumns();
+ Column[] foreignColumns = getForeignColumns();
+ for (int i = 0; i < primaryColumns.length; i++) {
+ if (pkColumn.equals(primaryColumns[i])
+ && fkColumn.equals(foreignColumns[i])) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/AbstractSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/AbstractSchema.java b/core/src/main/java/org/apache/metamodel/schema/AbstractSchema.java
new file mode 100644
index 0000000..79ccb09
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/AbstractSchema.java
@@ -0,0 +1,198 @@
+/**
+ * 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.eobjects.metamodel.schema;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eobjects.metamodel.util.Action;
+import org.eobjects.metamodel.util.CollectionUtils;
+import org.eobjects.metamodel.util.EqualsBuilder;
+import org.eobjects.metamodel.util.HasNameMapper;
+import org.eobjects.metamodel.util.Predicate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract implementation of the {@link Schema} interface. Implements most
+ * common and trivial methods.
+ *
+ * @author Kasper Sørensen
+ */
+public abstract class AbstractSchema implements Schema {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final Logger logger = LoggerFactory.getLogger(AbstractSchema.class);
+
+ @Override
+ public final String getQuotedName() {
+ String quote = getQuote();
+ if (quote == null) {
+ return getName();
+ }
+ return quote + getName() + quote;
+ }
+
+ @Override
+ public Relationship[] getRelationships() {
+ final Set<Relationship> result = new LinkedHashSet<Relationship>();
+ CollectionUtils.forEach(getTables(), new Action<Table>() {
+ @Override
+ public void run(Table table) {
+ Relationship[] relations = table.getRelationships();
+ for (int i = 0; i < relations.length; i++) {
+ Relationship relation = relations[i];
+ result.add(relation);
+ }
+ }
+ });
+ return result.toArray(new Relationship[result.size()]);
+ }
+
+ @Override
+ public Table getTable(int index) throws IndexOutOfBoundsException {
+ Table[] tables = getTables();
+ return tables[index];
+ }
+
+ @Override
+ public final String getQualifiedLabel() {
+ return getName();
+ }
+
+ @Override
+ public final int getTableCount(TableType type) {
+ return getTables(type).length;
+ }
+
+ @Override
+ public final int getRelationshipCount() {
+ return getRelationships().length;
+ }
+
+ @Override
+ public final int getTableCount() {
+ return getTables().length;
+ }
+
+ @Override
+ public final Table[] getTables(final TableType type) {
+ return CollectionUtils.filter(getTables(), new Predicate<Table>() {
+ @Override
+ public Boolean eval(Table table) {
+ return table.getType() == type;
+ }
+ }).toArray(new Table[0]);
+ }
+
+ @Override
+ public final Table getTableByName(String tableName) {
+ if (tableName == null) {
+ return null;
+ }
+
+ final List<Table> foundTables = new ArrayList<Table>(1);
+ // Search for table matches, case insensitive.
+ for (Table table : getTables()) {
+ if (tableName.equalsIgnoreCase(table.getName())) {
+ foundTables.add(table);
+ }
+ }
+
+ final int numTables = foundTables.size();
+ if (logger.isDebugEnabled()) {
+ logger.debug("Found {} tables(s) matching '{}': {}", new Object[] { numTables, tableName, foundTables });
+ }
+
+ if (numTables == 0) {
+ return null;
+ } else if (numTables == 1) {
+ return foundTables.get(0);
+ }
+
+ // If more matches are found, search case sensitive
+ for (Table table : foundTables) {
+ if (tableName.equals(table.getName())) {
+ return table;
+ }
+ }
+
+ // if none matches case sensitive, pick the first one.
+ return foundTables.get(0);
+ }
+
+ @Override
+ public final String[] getTableNames() {
+ Table[] tables = getTables();
+ return CollectionUtils.map(tables, new HasNameMapper()).toArray(new String[tables.length]);
+ }
+
+ @Override
+ public final String toString() {
+ return "Schema[name=" + getName() + "]";
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Schema) {
+ Schema other = (Schema) obj;
+ EqualsBuilder eb = new EqualsBuilder();
+ eb.append(getName(), other.getName());
+ eb.append(getQuote(), other.getQuote());
+ if (eb.isEquals()) {
+ try {
+ int tableCount1 = getTableCount();
+ int tableCount2 = other.getTableCount();
+ eb.append(tableCount1, tableCount2);
+ } catch (Exception e) {
+ // might occur when schemas are disconnected. Omit this check then.
+ }
+ }
+ return eb.isEquals();
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ String name = getName();
+ if (name == null) {
+ return -1;
+ }
+ return name.hashCode();
+ }
+
+ @Override
+ public final int compareTo(Schema that) {
+ int diff = getQualifiedLabel().compareTo(that.getQualifiedLabel());
+ if (diff == 0) {
+ diff = toString().compareTo(that.toString());
+ }
+ return diff;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/AbstractTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/AbstractTable.java b/core/src/main/java/org/apache/metamodel/schema/AbstractTable.java
new file mode 100644
index 0000000..3728751
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/AbstractTable.java
@@ -0,0 +1,329 @@
+/**
+ * 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.eobjects.metamodel.schema;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eobjects.metamodel.MetaModelHelper;
+import org.eobjects.metamodel.util.Action;
+import org.eobjects.metamodel.util.CollectionUtils;
+import org.eobjects.metamodel.util.HasNameMapper;
+import org.eobjects.metamodel.util.Predicate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract {@link Table} implementation. Includes most common/trivial methods.
+ *
+ * @author Kasper Sørensen
+ */
+public abstract class AbstractTable implements Table {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final Logger logger = LoggerFactory.getLogger(AbstractTable.class);
+
+ @Override
+ public final int getColumnCount() {
+ return getColumns().length;
+ }
+
+ @Override
+ public Column getColumn(int index) throws IndexOutOfBoundsException {
+ Column[] columns = getColumns();
+ return columns[index];
+ }
+
+ @Override
+ public final Column getColumnByName(final String columnName) {
+ if (columnName == null) {
+ return null;
+ }
+
+ final List<Column> foundColumns = new ArrayList<Column>(1);
+
+ // Search for column matches, case insensitive.
+ for (Column column : getColumns()) {
+ final String candidateName = column.getName();
+ if (columnName.equalsIgnoreCase(candidateName)) {
+ foundColumns.add(column);
+ }
+ }
+
+ final int numColumns = foundColumns.size();
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Found {} column(s) matching '{}': {}", new Object[] { numColumns, columnName, foundColumns });
+ }
+
+ if (numColumns == 0) {
+ return null;
+ } else if (numColumns == 1) {
+ // if there's only one, return it.
+ return foundColumns.get(0);
+ }
+
+ // If more matches are found, search case sensitive
+ for (Column column : foundColumns) {
+ if (columnName.equals(column.getName())) {
+ return column;
+ }
+ }
+
+ // if none matches case sensitive, pick the first one.
+ return foundColumns.get(0);
+ }
+
+ @Override
+ public final int getRelationshipCount() {
+ return getRelationships().length;
+ }
+
+ @Override
+ public final Column[] getNumberColumns() {
+ return CollectionUtils.filter(getColumns(), new Predicate<Column>() {
+ @Override
+ public Boolean eval(Column col) {
+ ColumnType type = col.getType();
+ return type != null && type.isNumber();
+ }
+ }).toArray(new Column[0]);
+ }
+
+ @Override
+ public final Column[] getLiteralColumns() {
+ return CollectionUtils.filter(getColumns(), new Predicate<Column>() {
+ @Override
+ public Boolean eval(Column col) {
+ ColumnType type = col.getType();
+ return type != null && type.isLiteral();
+ }
+ }).toArray(new Column[0]);
+ }
+
+ @Override
+ public final Column[] getTimeBasedColumns() {
+ return CollectionUtils.filter(getColumns(), new Predicate<Column>() {
+ @Override
+ public Boolean eval(Column col) {
+ ColumnType type = col.getType();
+ return type != null && type.isTimeBased();
+ }
+ }).toArray(new Column[0]);
+ }
+
+ @Override
+ public final Column[] getBooleanColumns() {
+ return CollectionUtils.filter(getColumns(), new Predicate<Column>() {
+ @Override
+ public Boolean eval(Column col) {
+ ColumnType type = col.getType();
+ return type != null && type.isBoolean();
+ }
+ }).toArray(new Column[0]);
+ }
+
+ @Override
+ public final Column[] getIndexedColumns() {
+ return CollectionUtils.filter(getColumns(), new Predicate<Column>() {
+ @Override
+ public Boolean eval(Column col) {
+ return col.isIndexed();
+ }
+ }).toArray(new Column[0]);
+ }
+
+ @Override
+ public final Relationship[] getForeignKeyRelationships() {
+ return CollectionUtils.filter(getRelationships(), new Predicate<Relationship>() {
+ @Override
+ public Boolean eval(Relationship arg) {
+ return AbstractTable.this.equals(arg.getForeignTable());
+ }
+ }).toArray(new Relationship[0]);
+ }
+
+ @Override
+ public final Relationship[] getPrimaryKeyRelationships() {
+ return CollectionUtils.filter(getRelationships(), new Predicate<Relationship>() {
+ @Override
+ public Boolean eval(Relationship arg) {
+ return AbstractTable.this.equals(arg.getPrimaryTable());
+ }
+ }).toArray(new Relationship[0]);
+ }
+
+ @Override
+ public final Column[] getForeignKeys() {
+ final Set<Column> columns = new HashSet<Column>();
+ final Relationship[] relationships = getForeignKeyRelationships();
+ CollectionUtils.forEach(relationships, new Action<Relationship>() {
+ @Override
+ public void run(Relationship arg) {
+ Column[] foreignColumns = arg.getForeignColumns();
+ for (Column column : foreignColumns) {
+ columns.add(column);
+ }
+ }
+ });
+ return columns.toArray(new Column[columns.size()]);
+ }
+
+ @Override
+ public final Column[] getPrimaryKeys() {
+ final List<Column> primaryKeyColumns = new ArrayList<Column>();
+ final Column[] columnsInTable = getColumns();
+ for (Column column : columnsInTable) {
+ if (column.isPrimaryKey()) {
+ primaryKeyColumns.add(column);
+ }
+ }
+ return primaryKeyColumns.toArray(new Column[primaryKeyColumns.size()]);
+ }
+
+ @Override
+ public final String[] getColumnNames() {
+ Column[] columns = getColumns();
+ return CollectionUtils.map(columns, new HasNameMapper()).toArray(new String[columns.length]);
+ }
+
+ @Override
+ public final Column[] getColumnsOfType(ColumnType columnType) {
+ Column[] columns = getColumns();
+ return MetaModelHelper.getColumnsByType(columns, columnType);
+ }
+
+ @Override
+ public final Column[] getColumnsOfSuperType(final SuperColumnType superColumnType) {
+ Column[] columns = getColumns();
+ return MetaModelHelper.getColumnsBySuperType(columns, superColumnType);
+ }
+
+ @Override
+ public final Relationship[] getRelationships(final Table otherTable) {
+ Relationship[] relationships = getRelationships();
+
+ return CollectionUtils.filter(relationships, new Predicate<Relationship>() {
+ @Override
+ public Boolean eval(Relationship relation) {
+ if (relation.getForeignTable() == otherTable && relation.getPrimaryTable() == AbstractTable.this) {
+ return true;
+ } else if (relation.getForeignTable() == AbstractTable.this && relation.getPrimaryTable() == otherTable) {
+ return true;
+ }
+ return false;
+ }
+ }).toArray(new Relationship[0]);
+ }
+
+ @Override
+ public final String getQuotedName() {
+ String quote = getQuote();
+ if (quote == null) {
+ return getName();
+ }
+ return quote + getName() + quote;
+ }
+
+ @Override
+ public final String getQualifiedLabel() {
+ StringBuilder sb = new StringBuilder();
+ Schema schema = getSchema();
+ if (schema != null && schema.getName() != null) {
+ sb.append(schema.getQualifiedLabel());
+ sb.append('.');
+ }
+ sb.append(getName());
+ return sb.toString();
+ }
+
+ @Override
+ public final String toString() {
+ return "Table[name=" + getName() + ",type=" + getType() + ",remarks=" + getRemarks() + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ return getName().hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Table) {
+ final Table other = (Table) obj;
+ if (!getQualifiedLabel().equals(other.getQualifiedLabel())) {
+ return false;
+ }
+ if (getType() != other.getType()) {
+ return false;
+ }
+ final Schema sch1 = getSchema();
+ final Schema sch2 = other.getSchema();
+ if (sch1 != null) {
+ if (!sch1.equals(sch2)) {
+ return false;
+ }
+ } else {
+ if (sch2 != null) {
+ return false;
+ }
+ }
+
+ try {
+ final String[] columnNames1 = getColumnNames();
+ final String[] columnNames2 = other.getColumnNames();
+
+ if (columnNames1 != null && columnNames1.length != 0) {
+ if (columnNames2 != null && columnNames2.length != 0) {
+ if (!Arrays.equals(columnNames1, columnNames2)) {
+ return false;
+ }
+ }
+ }
+ } catch (Exception e) {
+ // going "down stream" may throw exceptions, e.g. due to
+ // de-serialization issues. We will be tolerant to such
+ // exceptions
+ logger.debug("Caught (and ignoring) exception while comparing column names of tables", e);
+ }
+
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public final int compareTo(Table that) {
+ int diff = getQualifiedLabel().compareTo(that.getQualifiedLabel());
+ if (diff == 0) {
+ diff = toString().compareTo(that.toString());
+ }
+ return diff;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/Column.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/Column.java b/core/src/main/java/org/apache/metamodel/schema/Column.java
new file mode 100644
index 0000000..1208368
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/Column.java
@@ -0,0 +1,108 @@
+/**
+ * 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.eobjects.metamodel.schema;
+
+import java.io.Serializable;
+
+/**
+ * Represents a column and it's metadata description. Columns reside within a
+ * Table and can be used as keys for relationships between tables.
+ *
+ * @see Table
+ *
+ * @author Kasper Sørensen
+ */
+public interface Column extends Comparable<Column>, Serializable, NamedStructure {
+
+ /**
+ * Gets the name of this Column
+ *
+ * @return the name of this Column
+ */
+ @Override
+ public String getName();
+
+ /**
+ * Returns the column number or index. Note: This column number is 0-based
+ * whereas the JDBC is 1-based.
+ *
+ * @return the number of this column.
+ */
+ public int getColumnNumber();
+
+ /**
+ * Gets the type of the column
+ *
+ * @return this column's type.
+ */
+ public ColumnType getType();
+
+ /**
+ * Gets the table for which this column belong
+ *
+ * @return this column's table.
+ */
+ public Table getTable();
+
+ /**
+ * Determines whether or not this column accepts null values.
+ *
+ * @return true if this column accepts null values, false if not and null if
+ * not known.
+ */
+ public Boolean isNullable();
+
+ /**
+ * Gets any remarks/comments to this column.
+ *
+ * @return any remarks/comments to this column.
+ */
+ public String getRemarks();
+
+ /**
+ * Gets the data type size of this column.
+ *
+ * @return the data type size of this column or null if the size is not
+ * determined or known.
+ */
+ public Integer getColumnSize();
+
+ /**
+ * Gets the native type of this column. A native type is the name of the
+ * data type as defined in the datastore.
+ *
+ * @return the name of the native type.
+ */
+ public String getNativeType();
+
+ /**
+ * Determines if this column is indexed.
+ *
+ * @return true if this column is indexed or false if not (or not known)
+ */
+ public boolean isIndexed();
+
+ /**
+ * Determines if this column is (one of) the primary key(s) of its table.
+ *
+ * @return true if this column is a primary key, or false if not (or if this
+ * is not determinable).
+ */
+ public boolean isPrimaryKey();
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/ColumnType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/ColumnType.java b/core/src/main/java/org/apache/metamodel/schema/ColumnType.java
new file mode 100644
index 0000000..ea938e6
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/ColumnType.java
@@ -0,0 +1,292 @@
+/**
+ * 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.eobjects.metamodel.schema;
+
+import static org.eobjects.metamodel.schema.SuperColumnType.BINARY_TYPE;
+import static org.eobjects.metamodel.schema.SuperColumnType.BOOLEAN_TYPE;
+import static org.eobjects.metamodel.schema.SuperColumnType.LITERAL_TYPE;
+import static org.eobjects.metamodel.schema.SuperColumnType.NUMBER_TYPE;
+import static org.eobjects.metamodel.schema.SuperColumnType.OTHER_TYPE;
+import static org.eobjects.metamodel.schema.SuperColumnType.TIME_TYPE;
+
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import org.eobjects.metamodel.util.NumberComparator;
+import org.eobjects.metamodel.util.ObjectComparator;
+import org.eobjects.metamodel.util.TimeComparator;
+import org.eobjects.metamodel.util.ToStringComparator;
+
+/**
+ * Represents the data-type of columns. Most of the elements in this enum are
+ * based on the JDBC {@link Types} class, but with a few additions.
+ */
+public enum ColumnType {
+
+ /**
+ * Literal
+ */
+ CHAR(LITERAL_TYPE), VARCHAR(LITERAL_TYPE), LONGVARCHAR(LITERAL_TYPE), CLOB(LITERAL_TYPE), NCHAR(LITERAL_TYPE), NVARCHAR(
+ LITERAL_TYPE), LONGNVARCHAR(LITERAL_TYPE), NCLOB(LITERAL_TYPE),
+
+ /**
+ * Numbers
+ */
+ TINYINT(NUMBER_TYPE), SMALLINT(NUMBER_TYPE), INTEGER(NUMBER_TYPE), BIGINT(NUMBER_TYPE), FLOAT(NUMBER_TYPE), REAL(
+ NUMBER_TYPE), DOUBLE(NUMBER_TYPE), NUMERIC(NUMBER_TYPE), DECIMAL(NUMBER_TYPE),
+
+ /**
+ * Time based
+ */
+ DATE(TIME_TYPE), TIME(TIME_TYPE), TIMESTAMP(TIME_TYPE),
+
+ /**
+ * Booleans
+ */
+ BIT(BOOLEAN_TYPE), BOOLEAN(BOOLEAN_TYPE),
+
+ /**
+ * Binary types
+ */
+ BINARY(BINARY_TYPE), VARBINARY(BINARY_TYPE), LONGVARBINARY(BINARY_TYPE), BLOB(BINARY_TYPE),
+
+ /**
+ * Other types (as defined in {@link Types}).
+ */
+ NULL(OTHER_TYPE), OTHER(OTHER_TYPE), JAVA_OBJECT(OTHER_TYPE), DISTINCT(OTHER_TYPE), STRUCT(OTHER_TYPE), ARRAY(
+ OTHER_TYPE), REF(OTHER_TYPE), DATALINK(OTHER_TYPE), ROWID(OTHER_TYPE), SQLXML(OTHER_TYPE),
+
+ /**
+ * Additional types (added by MetaModel for non-JDBC datastores)
+ */
+ LIST(OTHER_TYPE), MAP(OTHER_TYPE);
+
+ private SuperColumnType _superType;
+
+ private ColumnType(SuperColumnType superType) {
+ if (superType == null) {
+ throw new IllegalArgumentException("SuperColumnType cannot be null");
+ }
+ _superType = superType;
+ }
+
+ public Comparator<Object> getComparator() {
+ if (isTimeBased()) {
+ return TimeComparator.getComparator();
+ }
+ if (isNumber()) {
+ return NumberComparator.getComparator();
+ }
+ if (isLiteral()) {
+ return ToStringComparator.getComparator();
+ }
+ return ObjectComparator.getComparator();
+ }
+
+ public boolean isBoolean() {
+ return _superType == BOOLEAN_TYPE;
+ }
+
+ public boolean isBinary() {
+ return _superType == BINARY_TYPE;
+ }
+
+ public boolean isNumber() {
+ return _superType == NUMBER_TYPE;
+ }
+
+ public boolean isTimeBased() {
+ return _superType == TIME_TYPE;
+ }
+
+ public boolean isLiteral() {
+ return _superType == LITERAL_TYPE;
+ }
+
+ public boolean isLargeObject() {
+ switch (this) {
+ case BLOB:
+ case CLOB:
+ case NCLOB:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * @return a java class that is appropriate for handling column values of
+ * this column type
+ */
+ public Class<?> getJavaEquivalentClass() {
+ switch (this) {
+ case TINYINT:
+ case SMALLINT:
+ return Short.class;
+ case INTEGER:
+ return Integer.class;
+ case BIGINT:
+ return BigInteger.class;
+ case DECIMAL:
+ case NUMERIC:
+ case FLOAT:
+ case REAL:
+ case DOUBLE:
+ return Double.class;
+ case DATE:
+ case TIME:
+ case TIMESTAMP:
+ return Date.class;
+ case BLOB:
+ return Blob.class;
+ case CLOB:
+ case NCLOB:
+ return Clob.class;
+ case MAP:
+ return Map.class;
+ case LIST:
+ return List.class;
+ default:
+ // All other types have fitting java equivalent classes in the super
+ // type
+ return _superType.getJavaEquivalentClass();
+ }
+ }
+
+ public SuperColumnType getSuperType() {
+ return _superType;
+ }
+
+ /**
+ * Finds the ColumnType enum corresponding to the incoming JDBC
+ * type-constant
+ */
+ public static ColumnType convertColumnType(int jdbcType) {
+ try {
+ Field[] fields = JdbcTypes.class.getFields();
+ // We assume that the JdbcTypes class only consists of constant
+ // integer types, so we make no assertions here
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+ int value = (Integer) field.getInt(null);
+ if (value == jdbcType) {
+ String fieldName = field.getName();
+ ColumnType[] enumConstants = ColumnType.class.getEnumConstants();
+ for (int j = 0; j < enumConstants.length; j++) {
+ ColumnType columnType = enumConstants[j];
+ if (fieldName.equals(columnType.toString())) {
+ return columnType;
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("Could not access fields in JdbcTypes", e);
+ }
+ return OTHER;
+ }
+
+ /**
+ * Gets the JDBC type as per the {@link Types} class.
+ *
+ * @return an int representing one of the constants in the {@link Types}
+ * class.
+ * @throws IllegalStateException
+ * in case getting the JDBC type was unsuccesful.
+ */
+ public int getJdbcType() throws IllegalStateException {
+ final String name = this.toString();
+ try {
+ // We assume that the JdbcTypes class only consists of constant
+ // integer types, so we make no assertions here
+ final Field[] fields = JdbcTypes.class.getFields();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+ String fieldName = field.getName();
+ if (fieldName.equals(name)) {
+ int value = (Integer) field.getInt(null);
+ return value;
+ }
+ }
+ throw new IllegalStateException("No JdbcType found with field name: " + name);
+ } catch (Exception e) {
+ throw new IllegalStateException("Could not access fields in JdbcTypes", e);
+ }
+ }
+
+ /**
+ * Finds the ColumnType enum corresponding to the incoming Java class.
+ *
+ * @param cls
+ * @return
+ */
+ public static ColumnType convertColumnType(Class<?> cls) {
+ if (cls == null) {
+ throw new IllegalArgumentException("Class cannot be null");
+ }
+
+ final ColumnType type;
+ if (cls == String.class) {
+ type = ColumnType.VARCHAR;
+ } else if (cls == Boolean.class || cls == boolean.class) {
+ type = ColumnType.BOOLEAN;
+ } else if (cls == Character.class || cls == char.class || cls == Character[].class || cls == char[].class) {
+ type = ColumnType.CHAR;
+ } else if (cls == Byte.class || cls == byte.class) {
+ type = ColumnType.TINYINT;
+ } else if (cls == Short.class || cls == short.class) {
+ type = ColumnType.SMALLINT;
+ } else if (cls == Integer.class || cls == int.class) {
+ type = ColumnType.INTEGER;
+ } else if (cls == Long.class || cls == long.class || cls == BigInteger.class) {
+ type = ColumnType.BIGINT;
+ } else if (cls == Float.class || cls == float.class) {
+ type = ColumnType.FLOAT;
+ } else if (cls == Double.class || cls == double.class) {
+ type = ColumnType.DOUBLE;
+ } else if (cls == BigDecimal.class) {
+ type = ColumnType.DECIMAL;
+ } else if (Map.class.isAssignableFrom(cls)) {
+ type = ColumnType.MAP;
+ } else if (List.class.isAssignableFrom(cls)) {
+ type = ColumnType.LIST;
+ } else if (cls == java.sql.Date.class) {
+ type = ColumnType.DATE;
+ } else if (cls == Timestamp.class) {
+ type = ColumnType.TIMESTAMP;
+ } else if (cls == Time.class) {
+ type = ColumnType.TIME;
+ } else if (Date.class.isAssignableFrom(cls)) {
+ type = ColumnType.TIMESTAMP;
+ } else {
+ type = ColumnType.OTHER;
+ }
+ return type;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/CompositeSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/CompositeSchema.java b/core/src/main/java/org/apache/metamodel/schema/CompositeSchema.java
new file mode 100644
index 0000000..f4f75e1
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/CompositeSchema.java
@@ -0,0 +1,91 @@
+/**
+ * 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.eobjects.metamodel.schema;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eobjects.metamodel.DataContext;
+import org.eobjects.metamodel.util.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A composite schema, comprising tables from several {@link DataContext}s.
+ *
+ * @author Kasper Sørensen
+ */
+public class CompositeSchema extends AbstractSchema {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final Logger logger = LoggerFactory.getLogger(CompositeSchema.class);
+
+ private final String name;
+ private final Collection<? extends Schema> delegates;
+
+ public CompositeSchema(String name, Collection<? extends Schema> delegates) {
+ super();
+ this.name = name;
+ this.delegates = delegates;
+ if (logger.isWarnEnabled()) {
+ Set<String> names = new HashSet<String>();
+ for (Table table : getTables()) {
+ if (names.contains(table.getName())) {
+ logger.warn("Name-clash detected for Table {}.", table.getName());
+ logger.warn("getTableByName(\"{}\") will return just the first table.", table.getName());
+ } else {
+ names.add(table.getName());
+ }
+ }
+ if (!names.isEmpty()) {
+ logger.warn("The following table names clashes in composite schema: " + names);
+ }
+ }
+ }
+
+ @Override
+ public Relationship[] getRelationships() {
+ Relationship[] result = new Relationship[0];
+ for (Schema delegate : delegates) {
+ result = CollectionUtils.array(result, delegate.getRelationships());
+ }
+ return result;
+ }
+
+ @Override
+ public Table[] getTables() {
+ Table[] result = new Table[0];
+ for (Schema delegate : delegates) {
+ result = CollectionUtils.array(result, delegate.getTables());
+ }
+ return result;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getQuote() {
+ return null;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/ImmutableColumn.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/ImmutableColumn.java b/core/src/main/java/org/apache/metamodel/schema/ImmutableColumn.java
new file mode 100644
index 0000000..3236c00
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/ImmutableColumn.java
@@ -0,0 +1,173 @@
+/**
+ * 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.eobjects.metamodel.schema;
+
+import java.io.Serializable;
+
+/**
+ * Immutable implementation of the Column interface.
+ *
+ * It is not intended to be instantiated on it's own. Rather, use the
+ * constructor in ImmutableSchema.
+ *
+ * @see ImmutableSchema
+ *
+ * @author Kasper Sørensen
+ */
+public final class ImmutableColumn extends AbstractColumn implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final int columnNumber;
+ private final ColumnType type;
+ private final Table table;
+ private final Boolean nullable;
+ private final String remarks;
+ private final Integer columnSize;
+ private final String nativeType;
+ private final boolean indexed;
+ private final boolean primaryKey;
+ private final String name;
+ private final String quote;
+
+ /**
+ * Constructs a new {@link ImmutableColumn}.
+ *
+ * @param name
+ * the name of the column
+ * @param type
+ * the type of the column
+ * @param table
+ * the table which the constructed column will pertain to
+ * @param columnNumber
+ * the column number of the column
+ * @param columnSize
+ * the size of the column
+ * @param nativeType
+ * the native type of the column
+ * @param nullable
+ * whether the column's values are nullable
+ * @param remarks
+ * the remarks of the column
+ * @param indexed
+ * whether the column is indexed or not
+ * @param quote
+ * the quote character(s) of the column
+ * @param primaryKey
+ * whether the column is a primary key or not
+ */
+ public ImmutableColumn(String name, ColumnType type, Table table, int columnNumber, Integer columnSize,
+ String nativeType, Boolean nullable, String remarks, boolean indexed, String quote, boolean primaryKey) {
+ this.name = name;
+ this.type = type;
+ this.table = table;
+ this.columnNumber = columnNumber;
+ this.columnSize = columnSize;
+ this.nativeType = nativeType;
+ this.nullable = nullable;
+ this.remarks = remarks;
+ this.indexed = indexed;
+ this.quote = quote;
+ this.primaryKey = primaryKey;
+ }
+
+ /**
+ * Constructs an {@link ImmutableColumn} based on an existing column and a
+ * table.
+ *
+ * @param column
+ * the column to immitate
+ * @param table
+ * the table that the constructed column will pertain to
+ */
+ public ImmutableColumn(Column column, Table table) {
+ this.name = column.getName();
+ this.type = column.getType();
+ this.table = table;
+ this.columnNumber = column.getColumnNumber();
+ this.columnSize = column.getColumnSize();
+ this.nativeType = column.getNativeType();
+ this.nullable = column.isNullable();
+ this.remarks = column.getRemarks();
+ this.indexed = column.isIndexed();
+ this.quote = column.getQuote();
+ this.primaryKey = column.isPrimaryKey();
+ }
+
+ protected ImmutableColumn(Column column, ImmutableTable table) {
+ this(column.getName(), column.getType(), table, column.getColumnNumber(), column.getColumnSize(), column
+ .getNativeType(), column.isNullable(), column.getRemarks(), column.isIndexed(), column.getQuote(),
+ column.isPrimaryKey());
+ }
+
+ @Override
+ public int getColumnNumber() {
+ return columnNumber;
+ }
+
+ @Override
+ public ColumnType getType() {
+ return type;
+ }
+
+ @Override
+ public Table getTable() {
+ return table;
+ }
+
+ @Override
+ public Boolean isNullable() {
+ return nullable;
+ }
+
+ @Override
+ public String getRemarks() {
+ return remarks;
+ }
+
+ @Override
+ public Integer getColumnSize() {
+ return columnSize;
+ }
+
+ @Override
+ public String getNativeType() {
+ return nativeType;
+ }
+
+ @Override
+ public boolean isIndexed() {
+ return indexed;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isPrimaryKey() {
+ return primaryKey;
+ }
+
+ @Override
+ public String getQuote() {
+ return quote;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/ImmutableRelationship.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/ImmutableRelationship.java b/core/src/main/java/org/apache/metamodel/schema/ImmutableRelationship.java
new file mode 100644
index 0000000..43f2cf0
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/ImmutableRelationship.java
@@ -0,0 +1,82 @@
+/**
+ * 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.eobjects.metamodel.schema;
+
+import java.io.Serializable;
+
+public final class ImmutableRelationship extends AbstractRelationship implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final Column[] primaryColumns;
+ private final Column[] foreignColumns;
+
+ public static void create(Relationship origRelationship,
+ ImmutableSchema schema) {
+ ImmutableTable primaryTable = getSimilarTable(
+ origRelationship.getPrimaryTable(), schema);
+ assert primaryTable != null;
+ Column[] primaryColumns = getSimilarColumns(
+ origRelationship.getPrimaryColumns(), primaryTable);
+ checkSameTable(primaryColumns);
+
+ ImmutableTable foreignTable = getSimilarTable(
+ origRelationship.getForeignTable(), schema);
+ assert foreignTable != null;
+ Column[] foreignColumns = getSimilarColumns(
+ origRelationship.getForeignColumns(), foreignTable);
+ checkSameTable(foreignColumns);
+
+ ImmutableRelationship relationship = new ImmutableRelationship(
+ primaryColumns, foreignColumns);
+ primaryTable.addRelationship(relationship);
+ foreignTable.addRelationship(relationship);
+ }
+
+ private static Column[] getSimilarColumns(Column[] columns, Table table) {
+ Column[] result = new Column[columns.length];
+ for (int i = 0; i < columns.length; i++) {
+ String name = columns[i].getName();
+ result[i] = table.getColumnByName(name);
+ }
+ return result;
+ }
+
+ private static ImmutableTable getSimilarTable(Table table,
+ ImmutableSchema schema) {
+ String name = table.getName();
+ return (ImmutableTable) schema.getTableByName(name);
+ }
+
+ private ImmutableRelationship(Column[] primaryColumns,
+ Column[] foreignColumns) {
+ this.primaryColumns = primaryColumns;
+ this.foreignColumns = foreignColumns;
+ }
+
+ @Override
+ public Column[] getPrimaryColumns() {
+ return primaryColumns;
+ }
+
+ @Override
+ public Column[] getForeignColumns() {
+ return foreignColumns;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/ImmutableSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/ImmutableSchema.java b/core/src/main/java/org/apache/metamodel/schema/ImmutableSchema.java
new file mode 100644
index 0000000..8ac8a79
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/ImmutableSchema.java
@@ -0,0 +1,72 @@
+/**
+ * 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.eobjects.metamodel.schema;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An immutable implementation of the {@link Schema} interface.
+ *
+ * @author Kasper Sørensen
+ */
+public final class ImmutableSchema extends AbstractSchema implements
+ Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final List<ImmutableTable> tables = new ArrayList<ImmutableTable>();
+ private String name;
+ private String quote;
+
+ private ImmutableSchema(String name, String quote) {
+ super();
+ this.name = name;
+ this.quote = quote;
+ }
+
+ public ImmutableSchema(Schema schema) {
+ this(schema.getName(), schema.getQuote());
+ Table[] origTables = schema.getTables();
+ for (Table table : origTables) {
+ tables.add(new ImmutableTable(table, this));
+ }
+
+ Relationship[] origRelationships = schema.getRelationships();
+ for (Relationship relationship : origRelationships) {
+ ImmutableRelationship.create(relationship, this);
+ }
+ }
+
+ @Override
+ public Table[] getTables() {
+ return tables.toArray(new Table[tables.size()]);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getQuote() {
+ return quote;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/ImmutableTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/ImmutableTable.java b/core/src/main/java/org/apache/metamodel/schema/ImmutableTable.java
new file mode 100644
index 0000000..a4d6d81
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/ImmutableTable.java
@@ -0,0 +1,106 @@
+/**
+ * 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.eobjects.metamodel.schema;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An immutable implementation of the Table interface.
+ *
+ * It is not intended to be instantiated on it's own. Rather, use the
+ * constructor in ImmutableSchema.
+ *
+ * @see ImmutableSchema
+ *
+ * @author Kasper Sørensen
+ */
+final class ImmutableTable extends AbstractTable implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final List<ImmutableColumn> columns = new ArrayList<ImmutableColumn>();
+ private final List<ImmutableRelationship> relationships = new ArrayList<ImmutableRelationship>();
+ private final ImmutableSchema schema;
+ private final TableType type;
+ private final String remarks;
+ private final String name;
+ private final String quote;
+
+ protected ImmutableTable(String name, TableType type, ImmutableSchema schema,
+ String remarks, String quote) {
+ this.name = name;
+ this.type = type;
+ this.schema = schema;
+ this.remarks = remarks;
+ this.quote = quote;
+ }
+
+ protected ImmutableTable(Table table, ImmutableSchema schema) {
+ this(table.getName(), table.getType(), schema, table.getRemarks(),
+ table.getQuote());
+ Column[] origColumns = table.getColumns();
+ for (Column column : origColumns) {
+ columns.add(new ImmutableColumn(column, this));
+ }
+ }
+
+ protected void addRelationship(ImmutableRelationship relationship) {
+ if (!relationships.contains(relationship)) {
+ relationships.add(relationship);
+ }
+ }
+
+ @Override
+ public Column[] getColumns() {
+ return columns.toArray(new Column[columns.size()]);
+ }
+
+ @Override
+ public Schema getSchema() {
+ return schema;
+ }
+
+ @Override
+ public TableType getType() {
+ return type;
+ }
+
+ @Override
+ public Relationship[] getRelationships() {
+ return relationships.toArray(new Relationship[relationships.size()]);
+ }
+
+ @Override
+ public String getRemarks() {
+ return remarks;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getQuote() {
+ return quote;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/JdbcTypes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/JdbcTypes.java b/core/src/main/java/org/apache/metamodel/schema/JdbcTypes.java
new file mode 100644
index 0000000..4531921
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/JdbcTypes.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.eobjects.metamodel.schema;
+
+/**
+ * This is a copy of the content (comments removed) of Java 6.0's
+ * java.sql.Types. It is backwards compatible with older versions, but have
+ * additional types (confirmed by JavaTypesTest). It is being used to convert
+ * JDBC types to ColumnType enumerations.
+ */
+final class JdbcTypes {
+
+ // Prevent instantiation
+ private JdbcTypes() {
+ }
+
+ public final static int BIT = -7;
+ public final static int TINYINT = -6;
+ public final static int SMALLINT = 5;
+ public final static int INTEGER = 4;
+ public final static int BIGINT = -5;
+ public final static int FLOAT = 6;
+ public final static int REAL = 7;
+ public final static int DOUBLE = 8;
+ public final static int NUMERIC = 2;
+ public final static int DECIMAL = 3;
+ public final static int CHAR = 1;
+ public final static int VARCHAR = 12;
+ public final static int LONGVARCHAR = -1;
+ public final static int DATE = 91;
+ public final static int TIME = 92;
+ public final static int TIMESTAMP = 93;
+ public final static int BINARY = -2;
+ public final static int VARBINARY = -3;
+ public final static int LONGVARBINARY = -4;
+ public final static int NULL = 0;
+ public final static int OTHER = 1111;
+ public final static int JAVA_OBJECT = 2000;
+ public final static int DISTINCT = 2001;
+ public final static int STRUCT = 2002;
+ public final static int ARRAY = 2003;
+ public final static int BLOB = 2004;
+ public final static int CLOB = 2005;
+ public final static int REF = 2006;
+ public final static int DATALINK = 70;
+ public final static int BOOLEAN = 16;
+ public final static int ROWID = -8;
+ public static final int NCHAR = -15;
+ public static final int NVARCHAR = -9;
+ public static final int LONGNVARCHAR = -16;
+ public static final int NCLOB = 2011;
+ public static final int SQLXML = 2009;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/MutableColumn.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/MutableColumn.java b/core/src/main/java/org/apache/metamodel/schema/MutableColumn.java
new file mode 100644
index 0000000..d4c464d
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/MutableColumn.java
@@ -0,0 +1,185 @@
+/**
+ * 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.eobjects.metamodel.schema;
+
+import java.io.Serializable;
+
+/**
+ * Represents a column and it's metadata description. Columns reside within a
+ * Table and can be used as keys for relationships between tables.
+ *
+ * @see MutableTable
+ * @see Relationship
+ */
+public class MutableColumn extends AbstractColumn implements Serializable {
+
+ private static final long serialVersionUID = -353183696233890927L;
+ private int _columnNumber;
+ private String _name;
+ private ColumnType _type;
+ private Table _table;
+ private Boolean _nullable = null;
+ private String _remarks;
+ private boolean _indexed = false;
+ private boolean _primaryKey = false;
+ private Integer _columnSize = null;
+ private String _nativeType = null;
+ private String _quoteString = null;
+
+ public MutableColumn() {
+ super();
+ }
+
+ public MutableColumn(String name) {
+ this();
+ setName(name);
+ }
+
+ public MutableColumn(String name, ColumnType type) {
+ this(name);
+ setType(type);
+ }
+
+ public MutableColumn(String name, ColumnType type, Table table, int columnNumber, Boolean nullable) {
+ this(name, type);
+ setColumnNumber(columnNumber);
+ setTable(table);
+ setNullable(nullable);
+ }
+
+ public MutableColumn(String name, ColumnType type, Table table, int columnNumber, Integer columnSize,
+ String nativeType, Boolean nullable, String remarks, boolean indexed, String quote) {
+ this(name, type, table, columnNumber, nullable);
+ setColumnSize(columnSize);
+ setNativeType(nativeType);
+ setRemarks(remarks);
+ setIndexed(indexed);
+ setQuote(quote);
+ }
+
+ @Override
+ public int getColumnNumber() {
+ return _columnNumber;
+ }
+
+ public MutableColumn setColumnNumber(int columnNumber) {
+ _columnNumber = columnNumber;
+ return this;
+ }
+
+ @Override
+ public String getName() {
+ return _name;
+ }
+
+ public MutableColumn setName(String name) {
+ _name = name;
+ return this;
+ }
+
+ @Override
+ public ColumnType getType() {
+ return _type;
+ }
+
+ public MutableColumn setType(ColumnType type) {
+ _type = type;
+ return this;
+ }
+
+ @Override
+ public Table getTable() {
+ return _table;
+ }
+
+ public MutableColumn setTable(Table table) {
+ _table = table;
+ return this;
+ }
+
+ @Override
+ public Boolean isNullable() {
+ return _nullable;
+ }
+
+ public MutableColumn setNullable(Boolean nullable) {
+ _nullable = nullable;
+ return this;
+ }
+
+ @Override
+ public String getRemarks() {
+ return _remarks;
+ }
+
+ public MutableColumn setRemarks(String remarks) {
+ _remarks = remarks;
+ return this;
+ }
+
+ @Override
+ public Integer getColumnSize() {
+ return _columnSize;
+ }
+
+ public MutableColumn setColumnSize(Integer columnSize) {
+ _columnSize = columnSize;
+ return this;
+ }
+
+ @Override
+ public String getNativeType() {
+ return _nativeType;
+ }
+
+ public MutableColumn setNativeType(String nativeType) {
+ _nativeType = nativeType;
+ return this;
+ }
+
+ @Override
+ public boolean isIndexed() {
+ return _indexed;
+ }
+
+ public MutableColumn setIndexed(boolean indexed) {
+ _indexed = indexed;
+ return this;
+ }
+
+ @Override
+ public String getQuote() {
+ return _quoteString;
+ }
+
+ public MutableColumn setQuote(String quoteString) {
+ _quoteString = quoteString;
+ return this;
+ }
+
+ @Override
+ public boolean isPrimaryKey() {
+ return _primaryKey;
+ }
+
+ public MutableColumn setPrimaryKey(boolean primaryKey) {
+ _primaryKey = primaryKey;
+ return this;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/MutableRelationship.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/MutableRelationship.java b/core/src/main/java/org/apache/metamodel/schema/MutableRelationship.java
new file mode 100644
index 0000000..8762222
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/MutableRelationship.java
@@ -0,0 +1,132 @@
+/**
+ * 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.eobjects.metamodel.schema;
+
+import java.io.Serializable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Immutable implementation of the Relationship interface.
+ *
+ * The immutability help ensure integrity of object-relationships. To create
+ * relationsips use the <code>createRelationship</code> method.
+ *
+ * @author Kasper Sørensen
+ */
+public class MutableRelationship extends AbstractRelationship implements
+ Serializable, Relationship {
+
+ private static final long serialVersionUID = 238786848828528822L;
+ private static final Logger logger = LoggerFactory
+ .getLogger(MutableRelationship.class);
+
+ private final Column[] _primaryColumns;
+ private final Column[] _foreignColumns;
+
+ /**
+ * Factory method to create relations between two tables by specifying which
+ * columns from the tables that enforce the relationship.
+ *
+ * @param primaryColumns
+ * the columns from the primary key table
+ * @param foreignColumns
+ * the columns from the foreign key table
+ * @return the relation created
+ */
+ public static Relationship createRelationship(Column[] primaryColumns,
+ Column[] foreignColumns) {
+ Table primaryTable = checkSameTable(primaryColumns);
+ Table foreignTable = checkSameTable(foreignColumns);
+ MutableRelationship relation = new MutableRelationship(primaryColumns,
+ foreignColumns);
+
+ if (primaryTable instanceof MutableTable) {
+ try {
+ ((MutableTable) primaryTable).addRelationship(relation);
+ } catch (UnsupportedOperationException e) {
+ // this is an allowed behaviour - not all tables need to support
+ // this method.
+ logger.debug(
+ "primary table ({}) threw exception when adding relationship",
+ primaryTable);
+ }
+
+ // Ticket #144: Some tables have relations with them selves and then
+ // the
+ // relationship should only be added once.
+ if (foreignTable != primaryTable
+ && foreignTable instanceof MutableTable) {
+ try {
+ ((MutableTable) foreignTable).addRelationship(relation);
+ } catch (UnsupportedOperationException e) {
+ // this is an allowed behaviour - not all tables need to
+ // support this method.
+ logger.debug(
+ "foreign table ({}) threw exception when adding relationship",
+ foreignTable);
+ }
+ }
+ }
+ return relation;
+ }
+
+ public void remove() {
+ Table primaryTable = getPrimaryTable();
+ if (primaryTable instanceof MutableTable) {
+ ((MutableTable) primaryTable).removeRelationship(this);
+ }
+ Table foreignTable = getForeignTable();
+ if (foreignTable instanceof MutableTable) {
+ ((MutableTable) foreignTable).removeRelationship(this);
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ remove();
+ }
+
+ public static Relationship createRelationship(Column primaryColumn,
+ Column foreignColumn) {
+ return createRelationship(new Column[] { primaryColumn },
+ new Column[] { foreignColumn });
+ }
+
+ /**
+ * Prevent external instantiation
+ */
+ private MutableRelationship(Column[] primaryColumns, Column[] foreignColumns) {
+ _primaryColumns = primaryColumns;
+ _foreignColumns = foreignColumns;
+ }
+
+ @Override
+ public Column[] getPrimaryColumns() {
+ return _primaryColumns;
+ }
+
+ @Override
+ public Column[] getForeignColumns() {
+ return _foreignColumns;
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/schema/MutableSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/schema/MutableSchema.java b/core/src/main/java/org/apache/metamodel/schema/MutableSchema.java
new file mode 100644
index 0000000..71d05d2
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/schema/MutableSchema.java
@@ -0,0 +1,106 @@
+/**
+ * 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.eobjects.metamodel.schema;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Represents a schema and it's metadata. Schemas represent a collection of
+ * tables.
+ *
+ * @see Table
+ */
+public class MutableSchema extends AbstractSchema implements Serializable,
+ Schema {
+
+ private static final long serialVersionUID = 4465197783868238863L;
+
+ private String _name;
+ private final List<MutableTable> _tables;
+
+ public MutableSchema() {
+ super();
+ _tables = new ArrayList<MutableTable>();
+ }
+
+ public MutableSchema(String name) {
+ this();
+ _name = name;
+ }
+
+ public MutableSchema(String name, MutableTable... tables) {
+ this(name);
+ setTables(tables);
+ }
+
+ @Override
+ public String getName() {
+ return _name;
+ }
+
+ public MutableSchema setName(String name) {
+ _name = name;
+ return this;
+ }
+
+ @Override
+ public MutableTable[] getTables() {
+ MutableTable[] array = new MutableTable[_tables.size()];
+ return _tables.toArray(array);
+ }
+
+ public MutableSchema setTables(Collection<? extends MutableTable> tables) {
+ clearTables();
+ for (MutableTable table : tables) {
+ _tables.add(table);
+ }
+ return this;
+ }
+
+ public MutableSchema setTables(MutableTable... tables) {
+ clearTables();
+ for (MutableTable table : tables) {
+ _tables.add(table);
+ }
+ return this;
+ }
+
+ public MutableSchema clearTables() {
+ _tables.clear();
+ return this;
+ }
+
+ public MutableSchema addTable(MutableTable table) {
+ _tables.add(table);
+ return this;
+ }
+
+ public MutableSchema removeTable(Table table) {
+ _tables.remove(table);
+ return this;
+ }
+
+ @Override
+ public String getQuote() {
+ return null;
+ }
+}
\ No newline at end of file