blob: 4117833b7447a14e7b29ef121d96c45bdd4df210 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.tools.history;
import java.util.*;
import org.eclipse.persistence.history.*;
import org.eclipse.persistence.internal.databaseaccess.DatasourcePlatform;
import org.eclipse.persistence.internal.helper.*;
import org.eclipse.persistence.internal.history.*;
import org.eclipse.persistence.mappings.*;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.sessions.*;
import org.eclipse.persistence.queries.*;
import org.eclipse.persistence.sessions.broker.*;
import org.eclipse.persistence.tools.schemaframework.*;
import org.eclipse.persistence.sessions.server.*;
/**
* <b>Purpose:</b>One stop shopping for all your history needs.
*
* @author Stephen McRitchie
* @since Oracle 10g AS
*/
public class HistoryFacade {
private static Map timeOffsetsMap = new IdentityHashMap();
protected HistoryFacade() {
}
protected static void buildHistoricalTableDefinition(HistoryPolicy policy,
String name,
TableDefinition def,
TableCreator creator) {
if (def == null) {
return;
}
TableDefinition histDef = (TableDefinition)def.clone();
histDef.setName(name);
FieldDefinition fieldDef = new FieldDefinition();
fieldDef.setName(policy.getStartFieldName());
fieldDef.setType(ClassConstants.TIMESTAMP);
fieldDef.setSize(6);
histDef.addField(fieldDef);
fieldDef = new FieldDefinition();
fieldDef.setName(policy.getEndFieldName());
fieldDef.setType(ClassConstants.TIMESTAMP);
fieldDef.setSize(6);
histDef.addField(fieldDef);
histDef.setForeignKeys(new Vector());
for (FieldDefinition fieldDef2 : histDef.getFields()) {
// For now foreign key constraints are not supported, because shallow inserts are not...
fieldDef2.setForeignKeyFieldName(null);
if (fieldDef2.getName().equals("ROW_START") &&
(!histDef.getPrimaryKeyFieldNames().isEmpty())) {
fieldDef2.setIsPrimaryKey(true);
}
if (fieldDef2.getName().equals("VERSION") &&
(!histDef.getPrimaryKeyFieldNames().isEmpty())) {
fieldDef2.setIsPrimaryKey(true);
}
}
creator.addTableDefinition(histDef);
}
public static long currentDatabaseTimeMillis(org.eclipse.persistence.sessions.Session session) {
return currentDatabaseTimeMillis(session, null);
}
/**
* PUBLIC:
*/
public static long currentDatabaseTimeMillis(org.eclipse.persistence.sessions.Session session,
Class domainClass) {
Session rootSession = session;
while (rootSession.isUnitOfWork() || rootSession.isClientSession() ||
rootSession instanceof HistoricalSession ||
rootSession.isSessionBroker()) {
if (rootSession.isUnitOfWork()) {
rootSession = ((UnitOfWork)rootSession).getParent();
} else if (rootSession.isClientSession()) {
rootSession = ((ClientSession)rootSession).getParent();
} else if (rootSession instanceof HistoricalSession) {
rootSession = ((HistoricalSession)rootSession).getParent();
} else {
SessionBroker broker = (SessionBroker)rootSession;
rootSession = broker.getSessionForClass(domainClass);
if (rootSession == broker) {
break;
}
}
}
if (timeOffsetsMap.containsKey(rootSession)) {
Long offset = (Long)timeOffsetsMap.get(rootSession);
return System.currentTimeMillis() + offset;
} else {
DatabaseQuery query =
rootSession.getPlatform().getTimestampQuery();
long startTime = System.currentTimeMillis();
java.sql.Timestamp databaseTime =
(java.sql.Timestamp)rootSession.executeQuery(query);
long endTime = System.currentTimeMillis();
long jvmTime = (endTime - startTime) / 2 + startTime;
long offset = databaseTime.getTime() - jvmTime;
timeOffsetsMap.put(rootSession, offset);
return jvmTime + offset;
}
}
/**
* PUBLIC:
* Generates a mirroring historical schema given a
* conventional schema and a session with HistoryPolicies set on
* the descriptors.
*/
public static void generateHistoricalTableDefinitions(TableCreator creator, Session session) {
// First add all table definitions to a hashtable.
Map<String, TableDefinition> tableDefinitions = new HashMap(creator.getTableDefinitions().size());
for (TableDefinition def : creator.getTableDefinitions()) {
tableDefinitions.put(def.getFullName(), def);
}
Set<String> generatedTables = new HashSet<String>();
for (ClassDescriptor descriptor : session.getDescriptors().values()) {
HistoryPolicy policy = descriptor.getHistoryPolicy();
if (policy != null) {
List<String> names = policy.getHistoryTableNames();
for (int i = 0; i < descriptor.getTableNames().size(); i++) {
String name = (String)descriptor.getTableNames().get(i);
String histName = names.get(i);
if (!generatedTables.contains(histName)) {
generatedTables.add(histName);
TableDefinition def = tableDefinitions.get(name);
buildHistoricalTableDefinition(policy, histName, def, creator);
}
}
}
for (DatabaseMapping mapping : descriptor.getMappings()) {
if (mapping.isManyToManyMapping()) {
ManyToManyMapping m2mMapping = (ManyToManyMapping)mapping;
policy = m2mMapping.getHistoryPolicy();
if (policy != null) {
String name = m2mMapping.getRelationTableName();
String histName = policy.getHistoryTableNames().get(0);
if (!generatedTables.contains(histName)) {
generatedTables.add(histName);
TableDefinition def = tableDefinitions.get(name);
buildHistoricalTableDefinition(policy, histName, def, creator);
}
}
} else if (mapping.isDirectCollectionMapping()) {
DirectCollectionMapping dcMapping = (DirectCollectionMapping)mapping;
policy = dcMapping.getHistoryPolicy();
if (policy != null) {
String name = dcMapping.getReferenceTableName();
String histName = policy.getHistoryTableNames().get(0);
if (!generatedTables.contains(histName)) {
generatedTables.add(histName);
TableDefinition def = tableDefinitions.get(name);
buildHistoricalTableDefinition(policy, histName, def, creator);
}
}
}
}
}
}
/**
* PUBLIC:
* Generates HistoryPolicies for a given object model. The policies
* are of the recommended form, with START/END, and the history table name
* being the current table name with a _HIST suffix. Hence Employee would
* become Employee_Hist.
*/
public static void generateHistoryPolicies(Iterator descriptors, DatasourcePlatform platform) {
HistoryPolicy basePolicy = new HistoryPolicy();
basePolicy.addStartFieldName("ROW_START");
basePolicy.addEndFieldName("ROW_END");
HistoryPolicy policy = null;
while (descriptors.hasNext()) {
ClassDescriptor descriptor = (ClassDescriptor)descriptors.next();
policy = (HistoryPolicy)basePolicy.clone();
List<DatabaseTable> tables = descriptor.getTables();
int size = tables.size();
if (size == 0) {
continue;
}
for (int i = 0; i < size; i++) {
DatabaseTable table = tables.get(i);
String name = table.getQualifiedNameDelimited(platform);
String historicalName;
if(table.shouldUseDelimiters()) {
historicalName = name.substring(0, name.length() - 1) + "_HIST" + Helper.getDefaultEndDatabaseDelimiter();
} else {
historicalName = name + "_HIST";
}
policy.addHistoryTableName(name, historicalName);
}
descriptor.setHistoryPolicy(policy);
for (Enumeration mappings = descriptor.getMappings().elements();
mappings.hasMoreElements(); ) {
DatabaseMapping mapping =
(DatabaseMapping)mappings.nextElement();
if (mapping instanceof ManyToManyMapping) {
ManyToManyMapping m2mMapping = (ManyToManyMapping)mapping;
policy = (HistoryPolicy)basePolicy.clone();
policy.addHistoryTableName(m2mMapping.getRelationTableName() +
"_HIST");
m2mMapping.setHistoryPolicy(policy);
} else if (mapping instanceof DirectCollectionMapping) {
DirectCollectionMapping dcMapping =
(DirectCollectionMapping)mapping;
policy = (HistoryPolicy)basePolicy.clone();
policy.addHistoryTableName(dcMapping.getReferenceTableName() +
"_HIST");
dcMapping.setHistoryPolicy(policy);
}
}
}
}
public static void generateHistoryPolicies(org.eclipse.persistence.sessions.Project project) {
generateHistoryPolicies(project.getDescriptors().values().iterator(), project.getDatasourceLogin().getPlatform());
}
public static void generateHistoryPolicies(org.eclipse.persistence.sessions.Session session) {
generateHistoryPolicies(session.getDescriptors().values().iterator(), session.getPlatform());
}
}