/**
* 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.metamodel;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.sql.Connection;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.sql.DataSource;
import org.apache.metamodel.cassandra.CassandraDataContext;
import org.apache.metamodel.couchdb.CouchDbDataContext;
import org.apache.metamodel.csv.CsvConfiguration;
import org.apache.metamodel.csv.CsvDataContext;
import org.apache.metamodel.elasticsearch.nativeclient.ElasticSearchDataContext;
import org.apache.metamodel.elasticsearch.rest.ElasticSearchRestDataContext;
import org.apache.metamodel.excel.ExcelConfiguration;
import org.apache.metamodel.excel.ExcelDataContext;
import org.apache.metamodel.fixedwidth.FixedWidthConfiguration;
import org.apache.metamodel.fixedwidth.FixedWidthDataContext;
import org.apache.metamodel.hbase.HBaseConfiguration;
import org.apache.metamodel.hbase.HBaseDataContext;
import org.apache.metamodel.jdbc.JdbcDataContext;
import org.apache.metamodel.json.JsonDataContext;
import org.apache.metamodel.mongodb.mongo3.MongoDbDataContext;
import org.apache.metamodel.openoffice.OpenOfficeDataContext;
import org.apache.metamodel.pojo.PojoDataContext;
import org.apache.metamodel.pojo.TableDataProvider;
import org.apache.metamodel.salesforce.SalesforceDataContext;
import org.apache.metamodel.schema.TableType;
import org.apache.metamodel.sugarcrm.SugarCrmDataContext;
import org.apache.metamodel.util.FileHelper;
import org.apache.metamodel.util.Resource;
import org.apache.metamodel.util.SimpleTableDef;
import org.apache.metamodel.xml.XmlDomDataContext;
import org.ektorp.http.StdHttpClient.Builder;
import org.elasticsearch.client.Client;
import org.xml.sax.InputSource;
import com.datastax.driver.core.Cluster;
import com.google.common.base.Strings;
import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoDatabase;
import io.searchbox.client.JestClient;
/**
* A factory for DataContext objects. This class substantially easens the task
* of creating and initializing DataContext objects and/or their strategies for
* reading datastores.
*
* @see DataContext
*/
public class DataContextFactory {
public static final char DEFAULT_CSV_SEPARATOR_CHAR = CsvConfiguration.DEFAULT_SEPARATOR_CHAR;
public static final char DEFAULT_CSV_QUOTE_CHAR = CsvConfiguration.DEFAULT_QUOTE_CHAR;
private DataContextFactory() {
// Prevent instantiation
}
/**
* Creates a composite DataContext based on a set of delegate DataContexts.
*
* Composite DataContexts enables cross-DataContext querying and unified
* schema exploration
*
* @param delegates
* an array/var-args of delegate DataContexts
* @return a DataContext that matches the request
*/
public static DataContext createCompositeDataContext(DataContext... delegates) {
return new CompositeDataContext(delegates);
}
/**
* Creates a composite DataContext based on a set of delegate DataContexts.
*
* Composite DataContexts enables cross-DataContext querying and unified
* schema exploration
*
* @param delegates
* a collection of delegate DataContexts
* @return a DataContext that matches the request
*/
public static DataContext createCompositeDataContext(Collection<DataContext> delegates) {
return new CompositeDataContext(delegates);
}
/**
* Creates a DataContext that connects to a Salesforce.com instance.
*
* @param username
* the Salesforce username
* @param password
* the Salesforce password
* @param securityToken
* the Salesforce security token
* @return a DataContext object that matches the request
*/
public static DataContext createSalesforceDataContext(String username, String password, String securityToken) {
return new SalesforceDataContext(username, password, securityToken);
}
/**
* Create a DataContext that connects to a SugarCRM system.
*
* @param baseUrl
* the base URL of the system, e.g. http://localhost/sugarcrm
* @param username
* the SugarCRM username
* @param password
* the SugarCRM password
* @param applicationName
* the name of the application you are connecting with
* @return a DataContext object that matches the request
*/
public static DataContext createSugarCrmDataContext(String baseUrl, String username, String password,
String applicationName) {
return new SugarCrmDataContext(baseUrl, username, password, applicationName);
}
/**
* Creates a DataContext based on a CSV file
*
* @param file
* a CSV file
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createCsvDataContext(File file) {
return createCsvDataContext(file, DEFAULT_CSV_SEPARATOR_CHAR, DEFAULT_CSV_QUOTE_CHAR);
}
/**
* Creates a DataContext based on a JSON file
*/
public static DataContext createJsonDataContext(File file) {
return new JsonDataContext(file);
}
/**
* Creates a DataContext based on a CSV file
*
* @param file
* a CSV file
* @param separatorChar
* the char to use for separating values
* @param quoteChar
* the char used for quoting values (typically if they include
* the separator char)
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createCsvDataContext(File file, char separatorChar, char quoteChar) {
return createCsvDataContext(file, separatorChar, quoteChar, FileHelper.DEFAULT_ENCODING);
}
/**
* Creates a DataContext based on a CSV file
*
* @param file
* a CSV file
* @param separatorChar
* the char to use for separating values
* @param quoteChar
* the char used for quoting values (typically if they include
* the separator char)
* @param encoding
* the character encoding of the file
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createCsvDataContext(File file, char separatorChar, char quoteChar,
String encoding) {
final CsvConfiguration configuration = new CsvConfiguration(CsvConfiguration.DEFAULT_COLUMN_NAME_LINE, encoding,
separatorChar, quoteChar, CsvConfiguration.DEFAULT_ESCAPE_CHAR);
final CsvDataContext dc = new CsvDataContext(file, configuration);
return dc;
}
/**
* Creates a DataContext based on a CSV file
*
* @param file
* a CSV file
* @param configuration
* the CSV configuration to use
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createCsvDataContext(File file, CsvConfiguration configuration) {
final CsvDataContext dc = new CsvDataContext(file, configuration);
return dc;
}
/**
* Creates a DataContext based on CSV-content through an input stream
*
* @param inputStream
* the input stream to read from
* @param separatorChar
* the char to use for separating values
* @param quoteChar
* the char used for quoting values (typically if they include
* the separator char)
* @return a DataContext object that matches the request
*/
public static DataContext createCsvDataContext(InputStream inputStream, char separatorChar, char quoteChar) {
return createCsvDataContext(inputStream, separatorChar, quoteChar, FileHelper.DEFAULT_ENCODING);
}
/**
* Creates a DataContext based on CSV-content through an input stream
*
* @param inputStream
* the input stream to read from
* @param separatorChar
* the char to use for separating values
* @param quoteChar
* the char used for quoting values (typically if they include
* the separator char)
* @return a DataContext object that matches the request
*/
public static DataContext createCsvDataContext(InputStream inputStream, char separatorChar, char quoteChar,
String encoding) {
final CsvConfiguration configuration = new CsvConfiguration(CsvConfiguration.DEFAULT_COLUMN_NAME_LINE, encoding,
separatorChar, quoteChar, CsvConfiguration.DEFAULT_ESCAPE_CHAR);
final CsvDataContext dc = new CsvDataContext(inputStream, configuration);
return dc;
}
/**
* Creates a DataContext based on CSV-content through an input stream
*
* @param inputStream
* the input stream to read from
* @param configuration
* the CSV configuration to use
* @return a DataContext object that matches the request
*/
public static DataContext createCsvDataContext(InputStream inputStream, CsvConfiguration configuration) {
final CsvDataContext dc = new CsvDataContext(inputStream, configuration);
return dc;
}
/**
* Creates a DataContext based on a fixed width file.
*
* @param file
* the file to read from.
* @param fileEncoding
* the character encoding of the file.
* @param fixedValueWidth
* the (fixed) width of values in the file.
* @return a DataContext object that matches the request
*/
public static DataContext createFixedWidthDataContext(File file, String fileEncoding, int fixedValueWidth) {
return createFixedWidthDataContext(file, new FixedWidthConfiguration(
FixedWidthConfiguration.DEFAULT_COLUMN_NAME_LINE, fileEncoding, fixedValueWidth));
}
/**
* Creates a DataContext based on a fixed width file.
*
* @param file
* the file to read from.
* @param configuration
* the fixed width configuration to use
* @return a DataContext object that matches the request
*/
public static DataContext createFixedWidthDataContext(File file, FixedWidthConfiguration configuration) {
final FixedWidthDataContext dc = new FixedWidthDataContext(file, configuration);
return dc;
}
/**
* Creates a DataContext based on a fixed width file.
*
* @param resource
* the resource to read from.
* @param configuration
* the fixed width configuration to use
* @return a DataContext object that matches the request
*/
public static DataContext createFixedWidthDataContext(Resource resource, FixedWidthConfiguration configuration) {
final FixedWidthDataContext dc = new FixedWidthDataContext(resource, configuration);
return dc;
}
/**
* Creates a DataContext based on a fixed width file.
*
* @param file
* the file to read from.
* @param fileEncoding
* the character encoding of the file.
* @param fixedValueWidth
* the (fixed) width of values in the file.
* @param headerLineNumber
* the line number of the column headers.
* @return a DataContext object that matches the request
*/
public static DataContext createFixedWidthDataContext(File file, String fileEncoding, int fixedValueWidth,
int headerLineNumber) {
return createFixedWidthDataContext(file, new FixedWidthConfiguration(
FixedWidthConfiguration.DEFAULT_COLUMN_NAME_LINE, fileEncoding, fixedValueWidth));
}
/**
* Creates a DataContet based on an Excel spreadsheet file
*
* @param file
* an excel spreadsheet file
* @param configuration
* the configuration with metadata for reading the spreadsheet
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createExcelDataContext(File file, ExcelConfiguration configuration) {
return new ExcelDataContext(file, configuration);
}
/**
* Creates a DataContext based on an Excel spreadsheet file
*
* @param file
* an Excel spreadsheet file
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createExcelDataContext(File file) {
return createExcelDataContext(file, new ExcelConfiguration());
}
/**
* Creates a DataContext based on XML-content from an input source.
*
* Tables are created by examining the data in the XML file, NOT by reading
* XML Schemas (xsd/dtd's). This enables compliancy with ALL xml formats but
* also raises a risk that two XML files with the same format wont
* nescesarily yield the same table model if some optional attributes or
* tags are omitted in one of the files.
*
* @param inputSource
* an input source feeding XML content
* @param schemaName
* the name to be used for the main schema
* @param autoFlattenTables
* a boolean indicating if MetaModel should flatten very simple
* table structures (where tables only contain a single
* data-carrying column) for greater usability of the generated
* table-based model
* @return a DataContext object that matches the request
*/
public static DataContext createXmlDataContext(InputSource inputSource, String schemaName,
boolean autoFlattenTables) {
XmlDomDataContext dc = new XmlDomDataContext(inputSource, schemaName, autoFlattenTables);
return dc;
}
/**
* Creates a DataContext based on XML-content from a File.
*
* Tables are created by examining the data in the XML file, NOT by reading
* XML Schemas (xsd/dtd's). This enables compliancy with ALL xml formats but
* also raises a risk that two XML files with the same format wont
* nescesarily yield the same table model if some optional attributes or
* tags are omitted in one of the files.
*
* @param file
* the File to use for feeding XML content
* @param autoFlattenTables
* a boolean indicating if MetaModel should flatten very simple
* table structures (where tables only contain a single
* data-carrying column) for greater usability of the generated
* table-based model
* @return a DataContext object that matches the request
*/
public static DataContext createXmlDataContext(File file, boolean autoFlattenTables) {
XmlDomDataContext dc = new XmlDomDataContext(file, autoFlattenTables);
return dc;
}
/**
* Creates a DataContext based on XML-content from a URL.
*
* Tables are created by examining the data in the XML file, NOT by reading
* XML Schemas (xsd/dtd's). This enables compliancy with ALL xml formats but
* also raises a risk that two XML files with the same format wont
* nescesarily yield the same table model if some optional attributes or
* tags are omitted in one of the files.
*
* @param url
* the URL to use for feeding XML content
* @param autoFlattenTables
* a boolean indicating if MetaModel should flatten very simple
* table structures (where tables only contain a single
* data-carrying column) for greater usability of the generated
* table-based model
* @return a DataContext object that matches the request
*/
public static DataContext createXmlDataContext(URL url, boolean autoFlattenTables) {
XmlDomDataContext dc = new XmlDomDataContext(url, autoFlattenTables);
return dc;
}
/**
* Creates a DataContext based on an OpenOffice.org database file.
*
* @param file
* an OpenOffice.org database file
* @return a DataContext object that matches the request
*/
public static DataContext createOpenOfficeDataContext(File file) {
return new OpenOfficeDataContext(file);
}
/**
* Creates a DataContext based on a JDBC connection
*
* @param connection
* a JDBC connection
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createJdbcDataContext(Connection connection) {
return new JdbcDataContext(connection);
}
/**
* Creates a DataContext based on a JDBC datasource
*
* @param ds
* a JDBC datasource
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createJdbcDataContext(DataSource ds) {
return new JdbcDataContext(ds);
}
/**
* Creates a DataContext based on a JDBC connection
*
* @param connection
* a JDBC connection
* @param catalogName
* a catalog name to use
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createJdbcDataContext(Connection connection, String catalogName) {
return new JdbcDataContext(connection, TableType.DEFAULT_TABLE_TYPES, catalogName);
}
/**
* Creates a DataContext based on a JDBC connection
*
* @param connection
* a JDBC connection
* @param tableTypes
* the types of tables to include in the generated schemas
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createJdbcDataContext(Connection connection, TableType... tableTypes) {
return new JdbcDataContext(connection, tableTypes, null);
}
/**
* Creates a DataContext based on a JDBC connection
*
* @param connection
* a JDBC connection
* @param catalogName
* a catalog name to use
* @param tableTypes
* the types of tables to include in the generated schemas
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createJdbcDataContext(Connection connection, String catalogName,
TableType[] tableTypes) {
return new JdbcDataContext(connection, tableTypes, catalogName);
}
/**
* Creates a DataContext based on a JDBC datasource
*
* @param ds
* a JDBC datasource
* @param tableTypes
* the types of tables to include in the generated schemas
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createJdbcDataContext(DataSource ds, TableType... tableTypes) {
return new JdbcDataContext(ds, tableTypes, null);
}
/**
* Creates a DataContext based on a JDBC datasource
*
* @param ds
* a JDBC datasource
* @param catalogName
* a catalog name to use
* @param tableTypes
* the types of tables to include in the generated schemas
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createJdbcDataContext(DataSource ds, String catalogName,
TableType[] tableTypes) {
return new JdbcDataContext(ds, tableTypes, catalogName);
}
/**
* Creates a DataContext based on a JDBC datasource
*
* @param ds
* a JDBC datasource
* @param catalogName
* a catalog name to use
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createJdbcDataContext(DataSource ds, String catalogName) {
return new JdbcDataContext(ds, TableType.DEFAULT_TABLE_TYPES, catalogName);
}
/**
* Creates a new MongoDB datacontext.
*
* @param hostname
* The hostname of the MongoDB instance
* @param port
* the port of the MongoDB instance, or null if the default port
* should be used.
* @param databaseName
* the name of the database
* @param username
* the username, or null if unauthenticated access should be used
* @param password
* the password, or null if unathenticated access should be used
* @param tableDefs
* an array of table definitions, or null if table definitions
* should be autodetected.
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createMongoDbDataContext(String hostname, Integer port, String databaseName,
String username, char[] password, SimpleTableDef[] tableDefs) {
try {
final ServerAddress serverAddress;
if (port == null) {
serverAddress = new ServerAddress(hostname);
} else {
serverAddress = new ServerAddress(hostname, port);
}
final MongoClient mongoClient;
final MongoDatabase mongoDb;
if (Strings.isNullOrEmpty(username)) {
mongoClient = new MongoClient(serverAddress);
} else {
final MongoCredential credential = MongoCredential.createCredential(username, databaseName, password);
mongoClient = new MongoClient(serverAddress, Arrays.asList(credential));
}
mongoDb = mongoClient.getDatabase(databaseName);
if (tableDefs == null || tableDefs.length == 0) {
return new MongoDbDataContext(mongoDb);
}
return new MongoDbDataContext(mongoDb, tableDefs);
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
throw new IllegalStateException(e);
}
}
/**
* Creates a new MongoDB datacontext.
*
* @param hostname
* The hostname of the MongoDB instance
* @param port
* the port of the MongoDB instance, or null if the default port
* should be used.
* @param databaseName
* the name of the database
* @param username
* the username, or null if unauthenticated access should be used
* @param password
* the password, or null if unathenticated access should be used
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createMongoDbDataContext(String hostname, Integer port, String databaseName,
String username, char[] password) {
return createMongoDbDataContext(hostname, port, databaseName, username, password, null);
}
/**
* Creates a new CouchDB datacontext.
*
* @param hostname
* The hostname of the CouchDB instance
* @param port
* the port of the CouchDB instance, or null if the default port
* should be used.
* @param username
* the username, or null if unauthenticated access should be used
* @param password
* the password, or null if unathenticated access should be used
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createCouchDbDataContext(String hostname, Integer port, String username,
String password) {
return createCouchDbDataContext(hostname, port, username, password, null);
}
/**
* Creates a new CouchDB datacontext.
*
* @param hostname
* The hostname of the CouchDB instance
* @param port
* the port of the CouchDB instance, or null if the default port
* should be used.
* @param username
* the username, or null if unauthenticated access should be used
* @param password
* the password, or null if unathenticated access should be used
* @param tableDefs
* an array of table definitions, or null if table definitions
* should be autodetected.
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createCouchDbDataContext(String hostname, Integer port, String username,
String password, SimpleTableDef[] tableDefs) {
final Builder httpClientBuilder = new Builder();
httpClientBuilder.host(hostname);
if (port != null) {
httpClientBuilder.port(port);
}
if (username != null) {
httpClientBuilder.username(username);
}
if (password != null) {
httpClientBuilder.password(password);
}
// increased timeouts (20 sec) - metamodel typically does quite some
// batching so it might take a bit of time to provide a connection.
httpClientBuilder.connectionTimeout(20000);
httpClientBuilder.socketTimeout(20000);
if (tableDefs == null || tableDefs.length == 0) {
return new CouchDbDataContext(httpClientBuilder);
}
return new CouchDbDataContext(httpClientBuilder, tableDefs);
}
/**
* Creates a new JSON-based ElasticSearch datacontext.
* @param client
* The Jest client
* @param indexName
* The ElasticSearch index name
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createElasticSearchDataContext(JestClient client, String indexName) {
return new ElasticSearchRestDataContext(client, indexName);
}
/**
* Creates a new ElasticSearch datacontext.
*
* @param client
* The ElasticSearch client
* @param indexName
* The ElasticSearch index name
* @return a DataContext object that matches the request
*/
public static UpdateableDataContext createElasticSearchDataContext(Client client, String indexName) {
return new ElasticSearchDataContext(client, indexName);
}
/**
* Creates a new Cassandra datacontext.
*
* @param cluster
* The Cassandra client
* @param keySpaceName
* The Cassandra key space name
* @return a DataContext object that matches the request
*/
public static DataContext createCassandraDataContext(Cluster cluster, String keySpaceName) {
return new CassandraDataContext(cluster, keySpaceName);
}
/**
* Creates a new HBase datacontext.
*
* @param configuration
* {@code HBaseConfiguration} object containing detailed HBase
* configuration properties.
*
* @return a DataContext object that matches the request
*/
public static DataContext createHBaseDataContext(HBaseConfiguration configuration){
return new HBaseDataContext(configuration);
}
/**
* Creates a new HBase datacontext.
*
* @param configuration
* {@code HBaseConfiguration} object containing detailed HBase
* configuration properties.
*
* @param connection
* A cluster connection encapsulating lower level individual
* connections to actual servers and a connection to zookeeper.
*
* @return a DataContext object that matches the request
*/
public static DataContext createHBaseDataContext(HBaseConfiguration configuration,org.apache.hadoop.hbase.client.Connection connection) {
return new HBaseDataContext(configuration, connection);
}
/**
* Creates a new POJO data context that is empty but can be populated at
* will.
*
* @return a DataContext object that matches the request
*
*/
public static DataContext createPojoDataContext() {
return new PojoDataContext();
}
/**
* Creates a new POJO data context based on the provided
* {@link TableDataProvider}s.
*
* @param tables
* list of tables
*
* @return DataContext object that matches the request
*/
public static DataContext createPojoDataContext(List<TableDataProvider<?>> tables) {
return new PojoDataContext(tables);
}
/**
* Creates a new POJO data context based on the provided
* {@link TableDataProvider}s.
*
* @param schemaName
* the name of the created schema
*
* @param tables
* table information
*
* @return DataContext object that matches the request
*
*/
public static DataContext createPojoDataContext(String schemaName,TableDataProvider<?>[] tables) {
return new PojoDataContext(schemaName, tables);
}
/**
* Creates a new POJO data context based on the provided
* {@link TableDataProvider}s.
*
* @param schemaName
* the name of the created schema
*
* @param tables
* list of tables
*
* @return DataContext object that matches the request
*/
public static DataContext createPojoDataContext(String schemaName,List<TableDataProvider<?>> tables) {
return new PojoDataContext(schemaName, tables);
}
}