blob: f9b7981cffc0e8254eff5c5bf2228edf35fb87e0 [file] [log] [blame]
/*
* 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.empire.samples.db.advanced;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Connection;
import java.sql.DriverManager;
import java.time.LocalDate;
import java.util.List;
import java.util.Locale;
import org.apache.empire.commons.DateUtils;
import org.apache.empire.commons.ObjectUtils;
import org.apache.empire.commons.StringUtils;
import org.apache.empire.data.DataType;
import org.apache.empire.data.list.DataListEntry;
import org.apache.empire.db.DBCmdParam;
import org.apache.empire.db.DBCommand;
import org.apache.empire.db.DBDDLGenerator.DDLActionType;
import org.apache.empire.db.DBQuery;
import org.apache.empire.db.DBReader;
import org.apache.empire.db.DBRecord;
import org.apache.empire.db.DBSQLScript;
import org.apache.empire.db.DBTableColumn;
import org.apache.empire.db.exceptions.ConstraintViolationException;
import org.apache.empire.db.exceptions.RecordUpdateFailedException;
import org.apache.empire.db.exceptions.StatementFailedException;
import org.apache.empire.db.expr.compare.DBCompareExpr;
import org.apache.empire.dbms.DBMSHandler;
import org.apache.empire.samples.db.advanced.db.CarSalesDB;
import org.apache.empire.samples.db.advanced.db.CarSalesDB.DealerRating;
import org.apache.empire.samples.db.advanced.db.CarSalesDB.DealershipType;
import org.apache.empire.samples.db.advanced.db.CarSalesDB.EngineType;
import org.apache.empire.samples.db.advanced.db.DealerSalesView;
import org.apache.empire.samples.db.advanced.records.BrandRecord;
import org.apache.empire.samples.db.advanced.records.DealerRecord;
import org.apache.empire.samples.db.advanced.records.ModelRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SampleAdvApp
{
// Logger
private static final Logger log = LoggerFactory.getLogger(SampleAdvApp.class);
private static SampleAdvConfig config = new SampleAdvConfig();
private final CarSalesDB carSales = new CarSalesDB();
private SampleContext context;
/**
* <PRE>
* This is the entry point of the Empire-DB Sample Application
* Please check the config.xml configuration file for Database and Connection settings.
* </PRE>
* @param args arguments
*/
public static void main(String[] args)
{
// Init Configuration
config.init((args.length > 0 ? args[0] : "config.xml" ));
// create the app
SampleAdvApp app = new SampleAdvApp();
try
{ // Run
log.info("Running DB Sample...");
app.run();
// Done
log.info("DB Sample finished successfully.");
} catch (Exception e) {
// Error
log.error("Running SampleApp failed with Exception" + e.toString(), e);
if (app.context!=null)
app.context.rollback();
} finally {
if (app.context!=null)
app.context.discard();
}
}
/**
* This method runs all the example code
*/
public void run()
{
// STEP 1: Get a JDBC Connection
System.out.println("*** Step 1: getJDBCConnection() ***");
Connection conn = getJDBCConnection();
// STEP 2: Choose a dbms
System.out.println("*** Step 2: getDatabaseProvider() ***");
DBMSHandler dbms = getDBMSHandler(config.getDatabaseProvider());
// STEP 2.2: Create a Context
context = new SampleContext(carSales, dbms, conn);
// set optional context features
context.setPreparedStatementsEnabled(true);
context.setRollbackHandlingEnabled(false);
// STEP 3: Open Database (and create if not existing)
System.out.println("*** Step 3: openDatabase() ***");
// db.open(context);
carSales.open(context);
if (carSales.wasCreated())
{ // newly created
populateDatabase();
insertSalesUsingBatch();
context.commit();
}
// DQL-Demos
simpleQueryDemo();
queryViewDemo();
subqueryQueryDemo();
paramQueryDemo();
// DML-Demos
modelPriceIncrease();
modelPriceDecrease();
dealerRatingUpdate();
// Remember RollbackHandling
boolean prevRBHandling = context.isRollbackHandlingEnabled();
try {
// commit pending operations (just to be sure)
context.commit();
// run transaction demo
transactionDemo();
} finally {
context.setRollbackHandlingEnabled(prevRBHandling);
}
cascadeDeleteDemo();
ddlDemo("Beadles Volkswagen", "www.group1auto.co.uk", "https://www.group1auto.co.uk/volkswagen/locations/beadles-volkswagen-dartford");
// Done
log.info("DB Sample Advanced finished successfully.");
}
public void populateDatabase()
{
// Add some brands
BrandRecord brandVW = (new BrandRecord(context)).insert("WVW", "Volkswagen", "Germany");
BrandRecord brandFord = (new BrandRecord(context)).insert("1F", "Ford", "USA");
BrandRecord brandTesla = (new BrandRecord(context)).insert("5YJ", "Tesla", "USA");
BrandRecord brandToy = (new BrandRecord(context)).insert("JT", "Toyota", "Japan");
// Add some models
ModelRecord model = new ModelRecord(context);
model.insert(brandVW, "Golf", "Golf Style 1,5 l TSI", "Style", EngineType.P, 130, 30970d, LocalDate.of(2019, 10, 24));
model.insert(brandVW, "Golf", "Golf R-Line 2,0 l TSI 4MOTION","R-Line", EngineType.P, 190, 38650d, LocalDate.of(2019, 10, 24));
model.insert(brandVW, "Tiguan", "Tiguan Life 1,5 l TSI", "Life", EngineType.P, 150, 32545d, LocalDate.of(2016, 01, 01));
model.insert(brandVW, "Tiguan", "Tiguan Elegance 2,0 l TDI SCR","Elegance", EngineType.D, 150, 40845d, LocalDate.of(2016, 01, 01));
model.insert(brandVW, "Tiguan", "Tiguan R-Line 1,4 l eHybrid", "R-Line", EngineType.H, 150, 48090d, LocalDate.of(2016, 01, 01));
model.insert(brandVW, "Mulitvan", "Multivan 6.1 Highline 2.0TDI", "Highline", EngineType.D, 204, 84269d, LocalDate.of(2019, 10, 21));
// Tesla
model.insert(brandTesla,"Model 3", "Model 3 LR", "Long Range", EngineType.E, 261, 45940d, LocalDate.of(2017, 07, 01));
model.insert(brandTesla,"Model 3", "Model 3 Performance", "Performance", EngineType.E, 487, 53940d, LocalDate.of(2017, 07, 01));
model.insert(brandTesla,"Model Y", "Model Y LR", "Long Range", EngineType.E, 345, 53940d, LocalDate.of(2020, 03, 13));
model.insert(brandTesla,"Model Y", "Model Y Performance", "Performance", EngineType.E, 450, 58940d, LocalDate.of(2020, 03, 13));
model.insert(brandTesla,"Model S", "Model S Plaid", "Plaid", EngineType.E, 1020, 0d, LocalDate.of(2021, 12, 01));
// Ford
model.insert(brandFord, "Mustang", "Mustang GT 5,0 l Ti-VCT V8", "GT", EngineType.P, 449, 54300d, LocalDate.of(2017, 01, 01));
model.insert(brandFord, "Mustang", "Mustang Mach1 5,0 l Ti-VCT V8", "Mach1", EngineType.P, 460, 62800d, LocalDate.of(2020, 10, 16));
// Toyota
model.insert(brandToy, "Prius", "Prius Hybrid 1,8-l-VVT-i", "Basis", EngineType.H, 122, 38000d, LocalDate.of(2017, 01, 01));
model.insert(brandToy, "Supra", "GR Supra Pure 2,0 l Twin-Scroll Turbo","Pure", EngineType.P, 258, 49290d, LocalDate.of(2020, 03, 31));
// Add some dealers
DealerRecord dealerDE = (new DealerRecord(context)).insert("Autozentrum Schmitz", "Munich", "Germany");
DealerRecord dealerUK = (new DealerRecord(context)).insert("Beadles Volkswagen", "Dartford", "United Kingdom");
DealerRecord dealerUS = (new DealerRecord(context)).insert("Auto Nation", "Los Angeles", "USA");
DealerRecord dealerFR = (new DealerRecord(context)).insert("Vauban Motors Argenteuil", "Paris", "France");
DealerRecord dealerIT = (new DealerRecord(context)).insert("Autorigoldi S.p.A.", "Milan", "Italy");
// Add brands to dealers
CarSalesDB.DealerBrands DB = carSales.DEALER_BRANDS;
DBRecord rec = new DBRecord(context, DB);
rec.create(DBRecord.key(dealerDE, brandTesla)).set(DB.DEALERSHIP_TYPE, DealershipType.B).update();
rec.create(DBRecord.key(dealerDE, brandVW)) .set(DB.DEALERSHIP_TYPE, DealershipType.U).update();
rec.create(DBRecord.key(dealerUK, brandVW)) .set(DB.DEALERSHIP_TYPE, DealershipType.B).update();
rec.create(DBRecord.key(dealerUK, brandFord)) .set(DB.DEALERSHIP_TYPE, DealershipType.I).update();
rec.create(DBRecord.key(dealerUS, brandFord)) .set(DB.DEALERSHIP_TYPE, DealershipType.B).update();
rec.create(DBRecord.key(dealerUS, brandTesla)).set(DB.DEALERSHIP_TYPE, DealershipType.I).update();
rec.create(DBRecord.key(dealerFR, brandToy)) .set(DB.DEALERSHIP_TYPE, DealershipType.B).update();
rec.create(DBRecord.key(dealerIT, brandToy)) .set(DB.DEALERSHIP_TYPE, DealershipType.G).update();
rec.create(DBRecord.key(dealerIT, brandVW)) .set(DB.DEALERSHIP_TYPE, DealershipType.B).update();
}
private void insertSalesUsingBatch()
{
CarSalesDB db = this.carSales;
DBSQLScript batch = new DBSQLScript(context);
// get list of all dealers
DBCommand cmd = context.createCommand();
cmd.select(db.DEALER.ID);
List<Long> dealerIdList = context.getUtils().querySimpleList(Long.class, cmd);
// get all models
cmd.clear();
cmd.select(db.MODEL.ID, db.MODEL.SPECIFICATION, db.MODEL.BASE_PRICE); // select the ones we need (optional)
// no constraints on model
List<DataListEntry> modelList = context.getUtils().queryDataList(cmd);
for (DataListEntry model : modelList)
{
int count = generateRandomSales(batch, model, dealerIdList);
log.info("{} Sales added for Model {}", count, model.getString(db.MODEL.SPECIFICATION));
}
// execute the batch
int count = batch.executeBatch();
log.info("{} Sales added with batch", count);
}
private int generateRandomSales(DBSQLScript batch, DataListEntry model, List<Long> dealerIdList)
{
CarSalesDB db = this.carSales;
BigDecimal price = model.getDecimal(db.MODEL.BASE_PRICE);
if (ObjectUtils.isEmpty(price))
return 0;
int count = 0;
int baseYear = LocalDate.now().getYear()-3;
DBCommand cmd = context.createCommand();
for (int i = (int)(Math.random()*99)+25; i>0; i--)
{
int dealIdx = (int)(Math.random()*dealerIdList.size());
int year = (int)(Math.random()*3)+baseYear;
int month = (int)(Math.random()*12)+1;
BigDecimal variation = new BigDecimal((Math.random()*200) - 100.0);
variation = variation.setScale(2, RoundingMode.HALF_UP);
cmd.set(db.SALES.MODEL_ID.to(model.getRecordId(db.MODEL)))
.set(db.SALES.DEALER_ID.to(dealerIdList.get(dealIdx)))
.set(db.SALES.YEAR.to(year))
.set(db.SALES.MONTH.to(month))
.set(db.SALES.PRICE.to(price.add(variation)));
// add to batch
batch.addInsert(cmd);
count++;
}
return count;
}
/**
* The result Bean for the query Example
* @author rainer
*/
public static class QueryResult implements Serializable
{
private static final long serialVersionUID = 1L;
private String brand;
private String model;
private BigDecimal basePrice;
private int salesCount;
private BigDecimal avgSalesPrice;
private BigDecimal priceDifference;
/**
* Fields constructor for QueryResult
* Must match the SELECT phrase and will be used by queryBeanList()
* @param brand
* @param model
* @param basePrice
* @param salesCount
* @param avgSalesPrice
* @param priceDifference
*/
public QueryResult(String brand, String model, BigDecimal basePrice
, int salesCount, BigDecimal avgSalesPrice, BigDecimal priceDifference)
{
this.brand = brand;
this.model = model;
this.basePrice = basePrice;
this.salesCount = salesCount;
this.avgSalesPrice = avgSalesPrice;
this.priceDifference = priceDifference;
}
public String getBrand()
{
return brand;
}
public String getModel()
{
return model;
}
public BigDecimal getBasePrice()
{
return basePrice;
}
public int getSalesCount()
{
return salesCount;
}
public BigDecimal getAvgSalesPrice()
{
return avgSalesPrice;
}
public BigDecimal getPriceDifference()
{
return priceDifference;
}
}
public void subqueryQueryDemo()
{
// shortcuts (for convenience)
CarSalesDB.Model MODEL = carSales.MODEL;
CarSalesDB.Sales SALES = carSales.SALES;
// create command
// DBColumnExpr SALES_COUNT = SALES.count();
DBCommand sub = context.createCommand()
.selectQualified(SALES.MODEL_ID, SALES.count())
.groupBy(SALES.MODEL_ID);
DBQuery q = new DBQuery(sub);
// create command
DBCommand cmd = context.createCommand()
.select(MODEL.SPECIFICATION, q.column(SALES.count()))
.join(MODEL.ID, q.column(SALES.MODEL_ID));
List<DataListEntry> list = context.getUtils().queryDataList(cmd);
for (DataListEntry dle : list)
{
System.out.println(dle.toString());
}
}
public void simpleQueryDemo()
{
// shortcuts (for convenience)
CarSalesDB.Brand BRAND = carSales.BRAND;
CarSalesDB.Model MODEL = carSales.MODEL;
CarSalesDB.Sales SALES = carSales.SALES;
// .selectQualified(BRAND.NAME, MODEL.CONFIG_NAME)
// create a command
DBCommand cmd = context.createCommand()
.select (BRAND.NAME, MODEL.SPECIFICATION, MODEL.BASE_PRICE)
.select (SALES.MODEL_ID.count(), SALES.PRICE.avg())
.select (SALES.PRICE.avg().minus(MODEL.BASE_PRICE.avg()).round(2).as("DIFFERENCE"))
.join (MODEL.WMI, BRAND.WMI)
.joinLeft(MODEL.ID, SALES.MODEL_ID, SALES.YEAR.is(2021)) // only year 2021
.where (MODEL.ENGINE_TYPE.in(EngineType.P, EngineType.H, EngineType.E)) // Petrol, Hybrid, Electric
.where (MODEL.BASE_PRICE.isGreaterThan(30000))
.groupBy (BRAND.NAME, MODEL.SPECIFICATION, MODEL.BASE_PRICE)
.having (SALES.MODEL_ID.count().isGreaterThan(5)) // more than 5 sales
.orderBy (BRAND.NAME.desc(), MODEL.SPECIFICATION.asc());
// Return a list of Java beans (needs matching fields constructor or setter methods)
// This is just one of several options to obtain an process query results
List<QueryResult> list = context.getUtils().queryBeanList(cmd, QueryResult.class, null);
log.info("queryBeanList returnes {} items", list.size());
/*
List<DataListEntry> list = context.getUtils().queryDataList(cmd);
for (DataListEntry dle : list)
{
System.out.println(dle.toString());
}
*/
/*
DataListEntry entry = context.getUtils().queryDataEntry(cmd);
for (int i=0; i<entry.getFieldCount(); i++)
log.info("col {} -> {}", entry.getColumn(i).getName(), entry.getColumn(i).getBeanPropertyName());
*/
}
public void paramQueryDemo()
{
// shortcuts (for convenience)
CarSalesDB.Brand BRAND = carSales.BRAND;
CarSalesDB.Model MODEL = carSales.MODEL;
// create command
DBCommand cmd = context.createCommand();
// create params
DBCmdParam brandParam = cmd.addParam();
DBCmdParam engineTypeParam = cmd.addParam();
// create the command
cmd.select (BRAND.NAME, MODEL.SPECIFICATION, MODEL.BASE_PRICE, MODEL.ENGINE_TYPE, MODEL.ENGINE_POWER)
.join (MODEL.WMI, BRAND.WMI)
.where (BRAND.NAME.is(brandParam))
.where (MODEL.ENGINE_TYPE.is(engineTypeParam))
.orderBy (BRAND.NAME.desc(), MODEL.SPECIFICATION.asc());
// set the params
brandParam.setValue("Tesla");
engineTypeParam.setValue(EngineType.E);
// and run
List<DataListEntry> list = context.getUtils().queryDataList(cmd);
for (DataListEntry dle : list)
System.out.println(dle.toString());
// change params
brandParam.setValue("Volkswagen");
engineTypeParam.setValue(EngineType.P);
// and run again
list = context.getUtils().queryDataList(cmd);
for (DataListEntry dle : list)
System.out.println(dle.toString());
}
public void modelPriceIncrease()
{
// shortcuts (for convenience)
CarSalesDB.Brand BRAND = carSales.BRAND;
CarSalesDB.Model MODEL = carSales.MODEL;
// create command
// Sales-Info
String salesInfo = "Price update "+DateUtils.formatDate(LocalDate.now(), Locale.US);
// create command
DBCommand cmd = context.createCommand()
// increase model base prices by 5%
.select(BRAND.NAME, MODEL.SPECIFICATION, MODEL.BASE_PRICE, MODEL.BASE_PRICE.multiplyWith(105).divideBy(100).round(2).as("NEW_PRICE"))
// set update fields
.set (MODEL.BASE_PRICE.to(MODEL.BASE_PRICE.multiplyWith(105).divideBy(100).round(2)))
.set (MODEL.SALES_INFO.to(salesInfo))
// join with BRANDS
.join (MODEL.WMI, BRAND.WMI) // , BRAND.NAME.is("Tesla")
// on all Volkswagen with Diesel engine
.where(BRAND.NAME.upper().like("VOLKSWAGEN"))
.where(MODEL.ENGINE_TYPE.is(EngineType.D)); // (MODEL.NAME.is("Tiguan").and(
// Preview the change
for (DataListEntry item : context.getUtils().queryDataList(cmd))
System.out.println(item.toString());
/*
// cmd.removeWhereConstraint(MODEL.NAME.is("Tiguan").and(MODEL.ENGINE_TYPE.is(EngineType.D)));
// cmd.removeWhereConstraintOn(BRAND.NAME);
sql = cmd.getUpdate();
params = cmd.getParamValues();
System.out.println(sql);
System.out.println(StringUtils.arrayToString(params, "|"));
*/
// Execute the change
int count = context.executeUpdate(cmd);
log.info("{} models affected", count);
context.commit();
}
public void modelPriceDecrease()
{
// shortcuts (for convenience)
CarSalesDB.Brand BRAND = carSales.BRAND;
CarSalesDB.Model MODEL = carSales.MODEL;
// create command
DBCommand cmd = context.createCommand()
.select(MODEL.getColumns())
.join (MODEL.WMI, BRAND.WMI)
.where(BRAND.NAME.upper().like("VOLKSWAGEN"))
.where(MODEL.ENGINE_TYPE.is(EngineType.D)); // (MODEL.NAME.is("Tiguan").and(
// Use DBReader to process query result
DBReader reader = new DBReader(context);
try
{ // Open Reader
log.info("running modelPriceDecrease for cmd {}", cmd.getSelect());
reader.open(cmd);
// Print output
ModelRecord record = new ModelRecord(context);
// Disable rollback handling to improve performance
record.setRollbackHandlingEnabled(false);
BigDecimal factor = (new BigDecimal(1.05d)).setScale(2, RoundingMode.HALF_UP);
while (reader.moveNext())
{ // Init updateable record
reader.initRecord(record);
// Calculate Base-Price
BigDecimal oldPrice = reader.getDecimal(MODEL.BASE_PRICE);
BigDecimal newPrice = oldPrice.divide(factor, 2, RoundingMode.HALF_UP);
record.set(MODEL.BASE_PRICE, newPrice);
// update
record.update();
}
// Done
context.commit();
} finally {
// always close Reader
reader.close();
}
}
private void dealerRatingUpdate()
{
CarSalesDB.Dealer DEALER = carSales.DEALER;
// Clear all dealer ratings
DBCommand cmd = context.createCommand()
.set(DEALER.RATING.to(DealerRating.X))
.where(DEALER.RATING.isNot(null));
context.executeUpdate(cmd);
context.commit();
// Subquery to find TOP 3 dealers
CarSalesDB.Sales SALES = carSales.SALES;
DBCommand qryCmd = context.createCommand()
.select(SALES.DEALER_ID)
.where(SALES.YEAR.is(LocalDate.now().getYear()-1))
.groupBy(SALES.DEALER_ID)
.orderBy(SALES.PRICE.sum().desc())
.limitRows(3);
DBQuery qryTop = new DBQuery(qryCmd, "qtop");
// Dealer-Query
cmd.clear();
cmd.join(DEALER.ID, qryTop.column(SALES.DEALER_ID));
int index = 0;
List<DealerRecord> list = context.getUtils().queryRecordList(cmd, DEALER, DealerRecord.class);
for (DealerRecord dealer : list)
{
DealerRating oldRating = dealer.getEnum(DEALER.RATING);
DealerRating newRating = DealerRating.values()[index++];
log.info("Dealer \"{}\" rating changed from {} to {}", dealer.getString(DEALER.COMPANY_NAME), oldRating, newRating);
dealer.set(DEALER.RATING, newRating);
dealer.update();
}
context.commit();
}
private void queryViewDemo()
{
// query all
/*
DBCommand cmd = context.createCommand()
.select (DSV.getColumns())
.orderBy (DSV.SALE_YEAR, DSV.DEALER_COUNTRY);
List<DataListEntry> list = context.getUtils().queryDataList(cmd);
for (DataListEntry dle : list)
{
System.out.println(dle.toString());
}
*/
// shortcuts (for convenience)
DealerSalesView DSV = carSales.DEALER_SALES_VIEW;
DBCommand cmd = context.createCommand();
// Detect if Brand sold is the Dealer's Brand
DBCompareExpr IS_DEALER_BRAND = DSV.DEALERSHIP_TYPE.in(DealershipType.B, DealershipType.F);
// select
cmd.select(DSV.SALE_YEAR, DSV.DEALER_NAME, DSV.DEALER_COUNTRY);
cmd.select(DSV.SALE_COUNT.sum().as("TOTAL_SALES"));
cmd.select(carSales.caseWhen(IS_DEALER_BRAND, DSV.TURNOVER, 0).sum().as("TURNOVER_BRAND"));
cmd.select(DSV.TURNOVER.sum().as("TURNOVER_TOTAL"));
// group
cmd.groupBy(DSV.SALE_YEAR, DSV.DEALER_NAME, DSV.DEALER_COUNTRY);
// order
cmd.orderBy(DSV.SALE_YEAR, DSV.DEALER_NAME);
// query and print result
List<DataListEntry> list = context.getUtils().queryDataList(cmd);
for (DataListEntry dle : list)
{
System.out.println(dle.toString());
}
}
/**
* <PRE>
* Opens and returns a JDBC-Connection.
* JDBC url, user and password for the connection are obtained from the SampleConfig bean
* Please use the config.xml file to change connection params.
* </PRE>
*/
private static Connection getJDBCConnection()
{
// Establish a new database connection
Connection conn = null;
try
{
// Connect to the database
String jdbcDriverClass = config.getJdbcClass();
log.info("Creating JDBC-Driver of type \"{}\"", jdbcDriverClass);
Class.forName(jdbcDriverClass).newInstance();
log.info("Connecting to Database'" + config.getJdbcURL() + "' / User=" + config.getJdbcUser());
conn = DriverManager.getConnection(config.getJdbcURL(), config.getJdbcUser(), config.getJdbcPwd());
log.info("Connected successfully");
// set the AutoCommit to false this session. You must commit
// explicitly now
conn.setAutoCommit(false);
log.info("AutoCommit is " + conn.getAutoCommit());
} catch (Exception e)
{
log.error("Failed to connect to '" + config.getJdbcURL() + "' / User=" + config.getJdbcUser());
log.error(e.toString());
throw new RuntimeException(e);
}
return conn;
}
/**
* Creates an Empire-db DatabaseDriver for the given provider and applies dbms specific configuration
*/
private static DBMSHandler getDBMSHandler(String provider)
{
try
{ // Get Driver Class Name
String dbmsHandlerClass = config.getDbmsHandlerClass();
if (StringUtils.isEmpty(dbmsHandlerClass))
throw new RuntimeException("Configuration error: Element 'dbmsHandlerClass' not found in node 'properties-"+provider+"'");
// Create dbms
DBMSHandler dbms = (DBMSHandler) Class.forName(dbmsHandlerClass).newInstance();
// Configure dbms
config.readProperties(dbms, "properties-"+provider, "dbmsHandlerProperites");
// done
return dbms;
} catch (Exception e)
{ // catch any checked exception and forward it
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* This method demonstrates how to add, modify and delete a database column.<BR>
* This function demonstrates the use of the {@link DBMSHandler#getDDLScript(org.apache.empire.db.DDLActionType, org.apache.empire.db.DBObject, DBSQLScript)}<BR>
*
*/
private void ddlDemo(String dealerName, String websiteDomain, String websiteUrl)
{
// create shortcuts
DBMSHandler dbms = context.getDbms();
CarSalesDB.Dealer DEALER = carSales.DEALER;
// First, add a new column to the Table object
DBTableColumn WEBSITE = DEALER.addColumn("WEBSITE", DataType.VARCHAR, 20, false);
// Now create the corresponding DDL statement
log.info("Create new column named WEBSITE as varchar(20) for the DEALER table");
DBSQLScript script = new DBSQLScript(context);
dbms.getDDLScript(DDLActionType.CREATE, WEBSITE, script);
script.executeAll();
// Now load a record from that table and set the value for the website
log.info("Set the value for the WEBSITE field for dealer \"{}\"", dealerName);
DealerRecord rec = new DealerRecord(context);
rec.read(DEALER.COMPANY_NAME.is(dealerName));
rec.set (WEBSITE, websiteDomain);
rec.update();
// Now extend the size of the field from 40 to 80 characters
log.info("Extend the size of column WEBSITE from 20 to 80 characters");
WEBSITE.setSize(80);
script.clear();
dbms.getDDLScript(DDLActionType.ALTER, WEBSITE, script);
script.executeAll();
// Now set a longer value for the record
log.info("Change the value for the WEBSITE to a longer string \"{}\"", websiteUrl);
rec.set(WEBSITE, websiteUrl);
rec.update();
// Finally, drop the column again
log.info("Drop the WEBSITE column from the DEALER table:");
script.clear();
dbms.getDDLScript(DDLActionType.DROP, WEBSITE, script);
script.executeAll();
}
/**
* testTransactionCreate
* @param context
* @param idDep
*/
private void transactionDemo()
{
// Set RollbackHandlingEnabled to false if you want to play with fire!
// Note: You must set the RollbackHandling flag before creating a Record instance
context.setRollbackHandlingEnabled(true);
// User a model record
CarSalesDB.Model MODEL = carSales.MODEL;
ModelRecord model = new ModelRecord(context);
/*
* Part 1
*/
// Insert a new model
log.info("Insert a new Model");
model.create()
.set(MODEL.WMI , "WVW") // = Volkswagen
.set(MODEL.NAME , "ID.4")
.set(MODEL.SPECIFICATION , "ID.4 Pro Performance 150 kW 77 kWh")
.set(MODEL.TRIM , "Pro")
.set(MODEL.ENGINE_TYPE , EngineType.E)
.set(MODEL.ENGINE_POWER , 204)
.set(MODEL.FIRST_SALE , LocalDate.of(2021, 04, 04));
// State and timestampe before and after insert
log.debug("Record state={}, key={}, Timestamp={}", model.getState(), model.getKey(), model.get(MODEL.UPDATE_TIMESTAMP));
model.update();
log.debug("Record state={}, key={}, Timestamp={}", model.getState(), model.getKey(), model.get(MODEL.UPDATE_TIMESTAMP));
// Update even once again without committing
model.set(MODEL.BASE_PRICE, 44915);
model.update();
log.debug("Record state={}, key={}, Timestamp={}", model.getState(), model.getKey(), model.get(MODEL.UPDATE_TIMESTAMP));
// now, do the rollback
log.info("Performing rollback");
context.rollback();
log.debug("Record state={}, key={}, Timestamp={}", model.getState(), model.getKey(), model.get(MODEL.UPDATE_TIMESTAMP));
log.info("Update Model again, even though its not in the database because of the rollback, hence Model will be inserted again.");
log.info("This will fail, if Rollback handling is not enabled!");
try {
model.set(MODEL.BASE_PRICE, 44900); // Only to mark the record as modified if RollbackHandling is disabled!
model.update();
} catch(RecordUpdateFailedException e) {
log.error("Model update failed since rollback handling was not enabled for this context!", e);
return; // the rest will fail too
}
log.debug("Record state={}, key={}, Timestamp={}", model.getState(), model.getKey(), model.get(MODEL.UPDATE_TIMESTAMP));
/*
* Part 2
*/
// Delete the model
model.delete();
log.debug("Record state={}", model.getState());
log.info("Performing rollback again");
context.rollback();
log.debug("Record state={}, key={}, Timestamp={}", model.getState(), model.getKey(), model.get(MODEL.UPDATE_TIMESTAMP));
// Final update
log.info("Update Model again, even though a delete was executed but was not committed.");
log.info("This will once again lead to an insert as the insert was still not committed");
log.info("This will also fail, if Rollback handling is not enabled!");
try {
model.update();
} catch(RecordUpdateFailedException e) {
log.error("Model update failed since rollback handling was not enabled for this context!", e);
return; // the rest will fail too
}
log.debug("Record state={}, key={}, Timestamp={}", model.getState(), model.getKey(), model.get(MODEL.UPDATE_TIMESTAMP));
// Finally commit
log.info("Finally commit the transaction in order to finalize the Model insert");
context.commit();
log.debug("Record state={}, key={}, Timestamp={}", model.getState(), model.getKey(), model.get(MODEL.UPDATE_TIMESTAMP));
/*
* Part 3
*/
// Update example with two consecutive updates
log.info("Fist update will change the timestamp");
model.set(MODEL.BASE_PRICE, 44000);
model.update();
log.debug("Record state={}, key={}, Timestamp={}", model.getState(), model.getKey(), model.get(MODEL.UPDATE_TIMESTAMP));
log.info("Second update will change the timestamp again");
model.set(MODEL.BASE_PRICE, 42660);
model.update();
log.debug("Record state={}, key={}, Timestamp={}", model.getState(), model.getKey(), model.get(MODEL.UPDATE_TIMESTAMP));
log.info("Performing rollback for the previous two updates");
context.rollback();
log.debug("Record state={}, key={}, Timestamp={}", model.getState(), model.getKey(), model.get(MODEL.UPDATE_TIMESTAMP));
log.info("Update Model again, even though the previous two updates have been rolled back");
log.info("This will again fail, if Rollback handling is not enabled!");
try {
model.update();
} catch(RecordUpdateFailedException e) {
log.error("Model update failed since rollback handling was not enabled for this context!", e);
}
log.debug("Record state={}, key={}, Timestamp={}", model.getState(), model.getKey(), model.get(MODEL.UPDATE_TIMESTAMP));
// But now delete the model again, so we can rerun the example later
model.delete();
context.commit();
}
/**
* This function demonstrates cascaded deletes.
* See DBRelation.setOnDeleteAction()
*
* @param idEmployee the id of the employee to delete
* @param idDepartment the id of the department to delete
* @param conn the connection
*/
private void cascadeDeleteDemo()
{
// Read a brand record
BrandRecord brand = new BrandRecord(context);
brand.read(carSales.BRAND.WMI.is("WVW")); // = Volkswagen
// Read dealer record
DealerRecord dealer = new DealerRecord(context);
dealer.read(carSales.DEALER.COMPANY_NAME.is("Autorigoldi S.p.A."));
try {
// This delete is designed to succeed since cascaded deletes are enabled for this relation.
// see DEALER_BRANDS and SALES foreign key definition in CarSalesDB:
// DEALER_ID = addForeignKey("DEALER_ID", db.DEALER, true, true ); // Delete Cascade on
log.info("Deleting DEALER expecting to succeed since relationship to DEALER_BRANDS and SALES is cascading");
dealer.delete();
// This delete is designed to succeed since cascaded deletes are enabled for this relation.
log.info("Deleting BRAND expecting to fail since relationship to DEALER_BRANDS and MODEL is NOT cascading");
brand.delete();
} catch(ConstraintViolationException e) {
log.info("Delete operation failed due to existing depending records.");
} catch(StatementFailedException e) {
// Oops, the driver threw a SQLException instead
log.info("Delete operation failed with SQLException {}", e.getMessage());
} finally {
// we don't really want to do this
context.rollback();
}
}
/**
* This functions prints the results of a query which is performed using the supplied command
* @param cmd the command to be used for performing the query
* @param conn the connection
private void printQueryResults(DBCommand cmd)
{
// Query Records and print output
DBReader reader = new DBReader(context);
try
{ // Open Reader
System.out.println("Running Query:");
System.out.println(cmd.getSelect());
reader.open(cmd);
// Print column titles
System.out.println("---------------------------------");
int count = reader.getFieldCount();
for (int i=0; i<count; i++)
{ // Print all column names
DBColumnExpr c = reader.getColumn(i);
if (i>0)
System.out.print("\t");
System.out.print(c.getName());
}
// Print output
System.out.println("");
// Text-Output by iterating through all records.
while (reader.moveNext())
{
for (int i=0; i<count; i++)
{ // Print all field values
if (i>0)
System.out.print("\t");
// Check if conversion is necessary
DBColumnExpr c = reader.getColumn(i);
Options opt = c.getOptions();
if (opt!=null)
{ // Option Lookup
System.out.print(opt.get(reader.getValue(i)));
}
else
{ // Print String
System.out.print(reader.getString(i));
}
}
System.out.println("");
}
} finally
{ // always close Reader
reader.close();
}
}
*/
}