
jodd.db.oom.DbOomManager Maven / Gradle / Ivy
// Copyright (c) 2003-present, Jodd Team (http://jodd.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
package jodd.db.oom;
import jodd.db.oom.naming.ColumnNamingStrategy;
import jodd.db.oom.naming.TableNamingStrategy;
import jodd.util.StringUtil;
import jodd.log.Logger;
import jodd.log.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
/**
* DbOom manager. Contains various global settings, DB-OOM (database - object-oriented)
* mapping definitions, naming conventions etc.
*
* Important: configure settings before entity registration!
*
* Mapping definitions are used only by a result set mapper (such as {@link jodd.db.oom.mapper.ResultSetMapper}
* to lookup for an entity from table name. Table names are read from result-set meta data, for example.
* Moreover, it is not needed to use mappings at all: in that case just provide entity types during result set to
* objects conversion.
*
* @see jodd.db.DbManager
*/
public class DbOomManager {
private static final Logger log = LoggerFactory.getLogger(DbOomManager.class);
// ---------------------------------------------------------------- singleton
private static DbOomManager dbOomManager = new DbOomManager();
/**
* Returns DbOom manager instance.
*/
public static DbOomManager getInstance() {
return dbOomManager;
}
/**
* Sets new DbOom manager.
*/
public static void setInstance(DbOomManager oomManager) {
dbOomManager = oomManager;
}
/**
* Resets DbOom Manager to defaults.
* It's done by simply creating a new instance
* of DbOom manager.
*/
public static void resetAll() {
dbOomManager = new DbOomManager();
}
// ---------------------------------------------------------------- naming
protected String schemaName;
protected TableNamingStrategy tableNames = new TableNamingStrategy();
protected ColumnNamingStrategy columnNames = new ColumnNamingStrategy();
/**
* Returns current table name strategy.
*/
public TableNamingStrategy getTableNames() {
return tableNames;
}
/**
* Sets new table name strategy.
*/
public void setTableNames(TableNamingStrategy tableNames) {
this.tableNames = tableNames;
}
/**
* Returns current column name strategy.
*/
public ColumnNamingStrategy getColumnNames() {
return columnNames;
}
/**
* Sets new column name strategy,
*/
public void setColumnNames(ColumnNamingStrategy columnNames) {
this.columnNames = columnNames;
}
// ---------------------------------------------------------------- registration
protected String[] primitiveEntitiesPrefixes = new String[] {
"java.lang.",
"jodd.mutable.",
int.class.getName(),
long.class.getName(),
float.class.getName(),
double.class.getName(),
short.class.getName(),
boolean.class.getName(),
byte.class.getName()};
public String[] getPrimitiveEntitiesPrefixes() {
return primitiveEntitiesPrefixes;
}
/**
* Specifies array of class name prefixes that will be mapped directly to column.
*/
public void setPrimitiveEntitiesPrefixes(String... primitiveEntitiesPrefixes) {
this.primitiveEntitiesPrefixes = primitiveEntitiesPrefixes;
}
protected Map descriptorsMap = new HashMap<>();
protected Map entityNamesMap = new HashMap<>();
protected Map tableNamesMap = new NamedValuesHashMap<>();
/**
* Lookups {@link DbEntityDescriptor} for some type and registers the type if is new.
*
* Returns null
for core classes from java
run-time packages!
* Some types are not entities, i.e. domain objects. Instead, primitive entities
* are simply mapped to one column.
*/
public DbEntityDescriptor lookupType(Class type) {
String typeName = type.getName();
if (StringUtil.startsWithOne(typeName, primitiveEntitiesPrefixes) != -1) {
return null;
}
DbEntityDescriptor ded = descriptorsMap.get(type);
if (ded == null) {
ded = registerType(type);
}
return ded;
}
/**
* Returns true
if type is registered withing manager.
*/
public boolean isRegistered(Class type) {
return descriptorsMap.containsKey(type);
}
/**
* Lookups for {@link jodd.db.oom.DbEntityDescriptor} that was registered with this manager.
* Returns null
if name not found.
*/
public DbEntityDescriptor lookupName(String typeName) {
return entityNamesMap.get(typeName);
}
/**
* Lookups for {@link jodd.db.oom.DbEntityDescriptor} that was registered with this manager.
* Returns null
if table name not found. Lookup is case-insensitive.
*/
public DbEntityDescriptor lookupTableName(String tableName) {
return tableNamesMap.get(tableName);
}
/**
* Registers just type and entity names. Enough for most usages.
*/
public DbEntityDescriptor registerType(Class type) {
DbEntityDescriptor ded = createDbEntityDescriptor(type);
DbEntityDescriptor existing = descriptorsMap.put(type, ded);
if (log.isDebugEnabled()) {
log.debug("Register " + type.getName() + " as " + ded.getTableName());
}
if (existing != null) {
if (ded.getType() == type) {
return ded;
}
throw new DbOomException("Type already registered: " + existing.getType());
}
existing = entityNamesMap.put(ded.getEntityName(), ded);
if (existing != null) {
throw new DbOomException("Name '" + ded.getEntityName() + "' already mapped to an entity: " + existing.getType());
}
return ded;
}
/**
* Registers entity. {@link #registerType(Class) Registers types} and table names.
*/
public DbEntityDescriptor registerEntity(Class type) {
DbEntityDescriptor ded = registerType(type);
DbEntityDescriptor existing = tableNamesMap.put(ded.getTableName(), ded);
if (existing != null) {
if (ded.getType() == type) {
return ded;
}
throw new DbOomException("Entity registration failed! Table '" + ded.getTableName() + "' already mapped to an entity: " + existing.getType());
}
return ded;
}
/**
* Registers entity. Existing entity will be removed if exist, so no exception will be thrown.
*/
public DbEntityDescriptor registerEntity(Class type, boolean force) {
if (force) {
removeEntity(type);
}
return registerEntity(type);
}
/**
* Removes entity and returns removed descriptor.
*/
public DbEntityDescriptor removeEntity(Class type) {
DbEntityDescriptor ded = descriptorsMap.remove(type);
if (ded == null) {
ded = createDbEntityDescriptor(type);
}
entityNamesMap.remove(ded.getEntityName());
tableNamesMap.remove(ded.getTableName());
return ded;
}
/**
* Creates {@link DbEntityDescriptor}.
*/
protected DbEntityDescriptor createDbEntityDescriptor(Class type) {
return new DbEntityDescriptor<>(type, schemaName, tableNames, columnNames);
}
// ---------------------------------------------------------------- stats
/**
* Returns total number of registered entity names.
*/
public int getTotalNames() {
return entityNamesMap.size();
}
/**
* Returns total number of registered table names.
*/
public int getTotalTableNames() {
return tableNamesMap.size();
}
/**
* Returns total number of registered types.
*/
public int getTotalTypes() {
return descriptorsMap.size();
}
/**
* Resets the manager and clears descriptors maps.
* The configuration is not changed, just table-related
* data is cleared. To reset all, call {@link #resetAll()}.
*/
public void reset() {
descriptorsMap.clear();
entityNamesMap.clear();
tableNamesMap.clear();
}
// ---------------------------------------------------------------- table separators
protected String columnAliasSeparator = "$";
/**
* Returns value for separator for column aliases that divides table reference and column name.
*/
public String getColumnAliasSeparator() {
return columnAliasSeparator;
}
/**
* Specifies separator for column aliases that divides table reference and column name.
* Separator should contains of characters that are not used in table names, such as:
* '$' or '__'.
*/
public void setColumnAliasSeparator(String separator) {
this.columnAliasSeparator = separator;
}
// ---------------------------------------------------------------- hint resolver
protected JoinHintResolver hintResolver = new JoinHintResolver();
public JoinHintResolver getHintResolver() {
return hintResolver;
}
/**
* Specifies hint resolver.
*/
public void setHintResolver(JoinHintResolver hintResolver) {
this.hintResolver = hintResolver;
}
// ---------------------------------------------------------------- default column alias type
protected ColumnAliasType defaultColumnAliasType;
public ColumnAliasType getDefaultColumnAliasType() {
return defaultColumnAliasType;
}
/**
* Specifies default column alias type.
*/
public void setDefaultColumnAliasType(ColumnAliasType defaultColumnAliasType) {
this.defaultColumnAliasType = defaultColumnAliasType;
}
// ---------------------------------------------------------------- result set mapper
protected boolean cacheEntitiesInResultSet;
public boolean isCacheEntitiesInResultSet() {
return cacheEntitiesInResultSet;
}
/**
* Defines if entities have to be cached in result set.
* When cached, more memory is consumed during the existence of
* {@link jodd.db.oom.mapper.ResultSetMapper}.
*/
public void setCacheEntitiesInResultSet(boolean cacheEntitiesInResultSet) {
this.cacheEntitiesInResultSet = cacheEntitiesInResultSet;
}
// ---------------------------------------------------------------- db list
protected boolean entityAwareMode;
/**
* Returns true
if entity-aware mode is enabled.
*/
public boolean isEntityAwareMode() {
return entityAwareMode;
}
/**
* Defines entity-aware mode, when resulting collections does not have duplicates.
* It make sense to enable it only if {@link #setCacheEntitiesInResultSet(boolean) cache} is set.
* Therefore, enabling smart mode will also enable caching.
*/
public void setEntityAwareMode(boolean entityAwareMode) {
if (entityAwareMode) {
this.cacheEntitiesInResultSet = true;
}
this.entityAwareMode = entityAwareMode;
}
// ---------------------------------------------------------------- create entity
/**
* Creates new entity instances.
*/
public E createEntityInstance(Class type) {
try {
return type.newInstance();
} catch (Exception ex) {
throw new DbOomException(ex);
}
}
}