/*
* Copyright 2010 Impetus Infotech.
*
* Licensed 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 com.impetus.kundera.metadata;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.CascadeType;
import javax.persistence.FetchType;
import com.impetus.kundera.ejb.event.CallbackMethod;
import com.impetus.kundera.loader.DBType;
/**
* The Class EntityMetadata.
*
* @author animesh.kumar
*/
public final class EntityMetadata {
/** type. */
private Type type;
/** class corresponding to this meta. */
private Class<?> entityClazz;
/** ColumnFamily. */
private String columnFamilyName;
/** keyspace. */
private String keyspaceName;
/** field that keeps row identifier. */
private Field idProperty;
/** Column that keeps row identifier. */
private Column idColumn;
/** The read identifier method. */
private Method readIdentifierMethod;
/** The write identifier method. */
private Method writeIdentifierMethod;
/** columnMeta map. */
private Map<String, Column> columnsMap = new HashMap<String, Column>();
/** supercolumn map. */
private Map<String, SuperColumn> superColumnsMap = new HashMap<String, SuperColumn>();
/** document index boost, lucene specific. */
private float indexBoost = 1.0f;
/** The index name. */
private String indexName;
/** The is indexable. */
private boolean isIndexable = true; // default is indexable
/** The index prperties. */
private List<PropertyIndex> indexPrperties = new ArrayList<PropertyIndex>();
// entity listeners map
// key=>ListenerAnnotations, like @PrePersist, @PreUpdate etc.;
// value=>EntityLisntener Class and method
/** The callback methods map. */
private Map<Class<?>, List<? extends CallbackMethod>> callbackMethodsMap = new HashMap<Class<?>, List<? extends CallbackMethod>>();
/** Relationship map, key=>property name, value=>relation. */
private Map<String, Relation> relationsMap = new HashMap<String, Relation>();
/** Cacheable?. */
private boolean cacheable = false; // default is to not set second-level
// cache
private DBType dbType;
/**
* The Enum ForeignKey.
*/
public static enum ForeignKey {
ONE_TO_ONE, ONE_TO_MANY, MANY_TO_ONE, MANY_TO_MANY
};
/**
* Instantiates a new metadata.
*
* @param entityClazz
* the entity clazz
*/
public EntityMetadata(Class<?> entityClazz) {
this.entityClazz = entityClazz;
}
/**
* Gets the type.
*
* @return the type
*/
public Type getType() {
return type;
}
/**
* Sets the type.
*
* @param type
* the new type
*/
public void setType(Type type) {
this.type = type;
}
/**
* Gets the entity clazz.
*
* @return the entity clazz
*/
public Class<?> getEntityClazz() {
return entityClazz;
}
/**
* Gets the column family name.
*
* @return the column family name
*/
public String getColumnFamilyName() {
return columnFamilyName;
}
/**
* Sets the column family name.
*
* @param columnFamilyName
* the new column family name
*/
public void setColumnFamilyName(String columnFamilyName) {
this.columnFamilyName = columnFamilyName;
}
/**
* Gets the keyspace name.
*
* @return the keyspace name
*/
public String getKeyspaceName() {
return keyspaceName;
}
/**
* Sets the keyspace name.
*
* @param keyspaceName
* the new keyspace name
*/
public void setKeyspaceName(String keyspaceName) {
this.keyspaceName = keyspaceName;
}
/**
* Gets the id property.
*
* @return the id property
*/
public Field getIdProperty() {
return idProperty;
}
/**
* Sets the id property.
*
* @param idProperty
* the new id property
*/
public void setIdProperty(Field idProperty) {
this.idProperty = idProperty;
}
/**
* @return the idColumn
*/
public Column getIdColumn() {
return idColumn;
}
/**
* @param idColumn the idColumn to set
*/
public void setIdColumn(Column idColumn) {
this.idColumn = idColumn;
}
/**
* Gets the read identifier method.
*
* @return the readIdentifierMethod
*/
public Method getReadIdentifierMethod() {
return readIdentifierMethod;
}
/**
* Sets the read identifier method.
*
* @param readIdentifierMethod
* the readIdentifierMethod to set
*/
public void setReadIdentifierMethod(Method readIdentifierMethod) {
this.readIdentifierMethod = readIdentifierMethod;
}
/**
* Gets the write identifier method.
*
* @return the writeIdentifierMethod
*/
public Method getWriteIdentifierMethod() {
return writeIdentifierMethod;
}
/**
* Sets the write identifier method.
*
* @param writeIdentifierMethod
* the writeIdentifierMethod to set
*/
public void setWriteIdentifierMethod(Method writeIdentifierMethod) {
this.writeIdentifierMethod = writeIdentifierMethod;
}
/**
* Gets the columns map.
*
* @return the columns map
*/
public Map<String, Column> getColumnsMap() {
return columnsMap;
}
/**
* Gets the super columns map.
*
* @return the super columns map
*/
public Map<String, SuperColumn> getSuperColumnsMap() {
return superColumnsMap;
}
/**
* Gets the column.
*
* @param key
* the key
*
* @return the column
*/
public Column getColumn(String key) {
return columnsMap.get(key);
}
/**
* Gets the super column.
*
* @param key
* the key
*
* @return the super column
*/
public SuperColumn getSuperColumn(String key) {
return superColumnsMap.get(key);
}
/**
* Gets the columns as list.
*
* @return the columns as list
*/
public List<Column> getColumnsAsList() {
return new ArrayList<Column>(columnsMap.values());
}
/**
* Gets the super columns as list.
*
* @return the super columns as list
*/
public List<SuperColumn> getSuperColumnsAsList() {
return new ArrayList<SuperColumn>(superColumnsMap.values());
}
/**
* Gets the column field names.
*
* @return the column field names
*/
public List<String> getColumnFieldNames() {
return new ArrayList<String>(columnsMap.keySet());
}
/**
* Gets the super column field names.
*
* @return the super column field names
*/
public List<String> getSuperColumnFieldNames() {
return new ArrayList<String>(superColumnsMap.keySet());
}
/**
* Adds the column.
*
* @param key
* the key
* @param column
* the column
*/
public void addColumn(String key, Column column) {
columnsMap.put(key, column);
}
/**
* Adds the super column.
*
* @param key
* the key
* @param superColumn
* the super column
*/
public void addSuperColumn(String key, SuperColumn superColumn) {
superColumnsMap.put(key, superColumn);
}
/**
* Adds the index property.
*
* @param index
* the index
*/
public void addIndexProperty(PropertyIndex index) {
indexPrperties.add(index);
}
/**
* Adds the relation.
*
* @param property
* the property
* @param relation
* the relation
*/
public void addRelation(String property, Relation relation) {
relationsMap.put(property, relation);
}
/**
* Gets the relation.
*
* @param property
* the property
* @return the relation
*/
public Relation getRelation(String property) {
return relationsMap.get(property);
}
/**
* Gets the relations.
*
* @return the relations
*/
public List<Relation> getRelations() {
return new ArrayList<Relation>(relationsMap.values());
}
/**
* Gets the index properties.
*
* @return the index properties
*/
public List<PropertyIndex> getIndexProperties() {
return indexPrperties;
}
/**
* Gets the index boost.
*
* @return the index boost
*/
public float getIndexBoost() {
return indexBoost;
}
/**
* Sets the index boost.
*
* @param indexBoost
* the new index boost
*/
public void setIndexBoost(float indexBoost) {
this.indexBoost = indexBoost;
}
/**
* Gets the index name.
*
* @return the index name
*/
public String getIndexName() {
return indexName;
}
/**
* Sets the index name.
*
* @param indexName
* the new index name
*/
public void setIndexName(String indexName) {
this.indexName = indexName;
}
/**
* Checks if is indexable.
*
* @return true, if is indexable
*/
public boolean isIndexable() {
return isIndexable;
}
/**
* Sets the indexable.
*
* @param isIndexable
* the new indexable
*/
public void setIndexable(boolean isIndexable) {
this.isIndexable = isIndexable;
}
/**
* Sets the callback methods map.
*
* @param callbackMethodsMap
* the callback methods map
*/
public void setCallbackMethodsMap(
Map<Class<?>, List<? extends CallbackMethod>> callbackMethodsMap) {
this.callbackMethodsMap = callbackMethodsMap;
}
/**
* Gets the callback methods map.
*
* @return the callback methods map
*/
public Map<Class<?>, List<? extends CallbackMethod>> getCallbackMethodsMap() {
return callbackMethodsMap;
}
/**
* Gets the callback methods.
*
* @param event
* the event
*
* @return the callback methods
*/
public List<? extends CallbackMethod> getCallbackMethods(Class<?> event) {
return this.callbackMethodsMap.get(event);
}
/**
* Checks if is cacheable.
*
* @return the cacheable
*/
public boolean isCacheable() {
return cacheable;
}
/**
* Sets the cacheable.
*
* @param cacheable
* the cacheable to set
*/
public void setCacheable(boolean cacheable) {
this.cacheable = cacheable;
}
/* @see java.lang.Object#toString() */
@Override
public String toString() {
int start = 0;
StringBuilder builder = new StringBuilder();
builder.append(entityClazz.getName() + " (\n");
// builder.append("EntityMetadata [\n");
// builder.append("\tentity:" + entityClazz.getName() + ",\n");
builder.append("\tType: " + type + ",\n");
builder.append("\tColumnFamily: " + columnFamilyName + ", \n");
builder.append("\tKeyspace: " + keyspaceName + ",\n");
builder.append("\tId: " + idProperty.getName() + ",\n");
builder.append("\tReadIdMethod: " + readIdentifierMethod.getName()
+ ",\n");
builder.append("\tWriteIdMethod: " + writeIdentifierMethod.getName()
+ ",\n");
builder.append("\tCacheable: " + cacheable + ",\n");
if (!columnsMap.isEmpty()) {
builder.append("\tColumns (");
for (Column col : columnsMap.values()) {
if (start++ != 0) {
builder.append(", ");
}
builder.append(col.getName());
}
builder.append("),\n");
}
if (!superColumnsMap.isEmpty()) {
builder.append("\tSuperColumns (\n");
for (SuperColumn col : superColumnsMap.values()) {
builder.append("\t\t" + col.getName() + "(");
start = 0;
for (Column c : col.getColumns()) {
if (start++ != 0) {
builder.append(", ");
}
builder.append(c.getName());
}
builder.append(")\n");
}
builder.append("\t),\n");
}
if (!indexPrperties.isEmpty()) {
// builder.append("\tIndexName: " + indexName + ",\n");
// builder.append("\tIndexBoost: " + indexBoost + ",\n");
builder.append("\tIndexes (");
start = 0;
for (PropertyIndex index : indexPrperties) {
if (start++ != 0) {
builder.append(", ");
}
builder.append(index.getName());
}
builder.append("),\n");
}
if (!callbackMethodsMap.isEmpty()) {
builder.append("\tListeners (\n");
for (Map.Entry<Class<?>, List<? extends CallbackMethod>> entry : callbackMethodsMap
.entrySet()) {
String key = entry.getKey().getSimpleName();
for (CallbackMethod cbm : entry.getValue()) {
builder.append("\t\t" + key + ": " + cbm + "\n");
}
}
builder.append("\t)\n");
}
if (!relationsMap.isEmpty()) {
builder.append("\tRelation (\n");
for (Relation rel : relationsMap.values()) {
builder.append("\t\t" + rel.getTargetEntity().getName() + "#"
+ rel.getProperty().getName());
builder.append(" (" + rel.getCascades());
builder.append(", " + rel.getType());
builder.append(", " + rel.fetchType);
builder.append(")\n");
}
builder.append("\t)\n");
}
builder.append(")");
return builder.toString();
}
/**
* Represents Thrift Column.
*
* @author animesh.kumar
*/
public final class Column {
/** name of the column. */
private String name;
/** field. */
private Field field;
/**
* Instantiates a new column.
*
* @param name
* the name
* @param field
* the field
*/
public Column(String name, Field field) {
this.name = name;
this.field = field;
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Gets the field.
*
* @return the field
*/
public Field getField() {
return field;
}
}
/**
* Represents Thrift SuperColumn.
*
* @author animesh.kumar
*/
public final class SuperColumn {
/** The name. */
private String name;
/** The columns. */
private List<Column> columns;
/**
* Instantiates a new super column.
*
* @param name
* the name
*/
public SuperColumn(String name) {
this.name = name;
columns = new ArrayList<Column>();
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Gets the columns.
*
* @return the columns
*/
public List<Column> getColumns() {
return columns;
}
/**
* Adds the column.
*
* @param name
* the name
* @param field
* the field
*/
public void addColumn(String name, Field field) {
columns.add(new Column(name, field));
}
}
/**
* Contains Index information of a field.
*
* @author animesh.kumar
*/
public final class PropertyIndex {
/** The name. */
private String name;
/** The property. */
private Field property;
/** The boost. */
private float boost = 1.0f;
/**
* The Constructor.
*
* @param property
* the property
*/
public PropertyIndex(Field property) {
this.property = property;
this.name = property.getName();
}
/**
* Instantiates a new property index.
*
* @param property
* the property
* @param name
* the name
*/
public PropertyIndex(Field property, String name) {
this.property = property;
this.name = name;
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Gets the property.
*
* @return the property
*/
public Field getProperty() {
return property;
}
/**
* Gets the boost.
*
* @return the boost
*/
public float getBoost() {
return boost;
}
/**
* Sets the boost.
*
* @param boost
* the new boost
*/
public void setBoost(float boost) {
this.boost = boost;
}
}
/**
* Specifies the type of the metadata.
*/
public static enum Type {
/** Denotes that the Entity is related to a ColumnFamily. */
COLUMN_FAMILY {
public boolean isColumnFamilyMetadata() {
return true;
}
public boolean isSuperColumnFamilyMetadata() {
return false;
}
public boolean isDocumentMetadata() {
return false;
}
},
/** Denotes that the Entity is related to a SuperColumnFamily. */
SUPER_COLUMN_FAMILY {
public boolean isColumnFamilyMetadata() {
return false;
}
public boolean isSuperColumnFamilyMetadata() {
return true;
}
public boolean isDocumentMetadata() {
return false;
}
},
/** Denotes that the Entity is related to a document based data-store. */
DOCUMENT {
public boolean isColumnFamilyMetadata() {
return false;
}
public boolean isSuperColumnFamilyMetadata() {
return false;
}
public boolean isDocumentMetadata() {
return true;
}
};
/**
* Checks if is column family metadata.
*
* @return true, if is column family metadata
*/
public abstract boolean isColumnFamilyMetadata();
/**
* Checks if is super column family metadata.
*
* @return true, if is super column family metadata
*/
public abstract boolean isSuperColumnFamilyMetadata();
/**
* Checks if is Document metadata.
* @return true, if is Document metadata
*/
public abstract boolean isDocumentMetadata();
}
/**
* Class to hold class-method instances for EntityListeners.
*
* @author animesh.kumar
*/
public final class ExternalCallbackMethod implements CallbackMethod {
/** The clazz. */
private Class<?> clazz;
/** The method. */
private Method method;
/**
* Instantiates a new external callback method.
*
* @param clazz
* the clazz
* @param method
* the method
*/
public ExternalCallbackMethod(Class<?> clazz, Method method) {
this.clazz = clazz;
this.method = method;
}
/*
* @see
* com.impetus.kundera.ejb.event.CallbackMethod#invoke(java.lang.Object)
*/
public void invoke(Object entity) throws IllegalArgumentException,
IllegalAccessException, InvocationTargetException,
InstantiationException {
if (!method.isAccessible())
method.setAccessible(true);
method.invoke(clazz.newInstance(), new Object[] { entity });
}
/* @see java.lang.Object#toString() */
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(clazz.getName() + "." + method.getName());
return builder.toString();
}
}
/**
* The Class InternalCallbackMethod.
*
* @author animesh.kumar
*/
public final class InternalCallbackMethod implements CallbackMethod {
/** The method. */
private Method method;
/**
* Instantiates a new internal callback method.
*
* @param method
* the method
*/
public InternalCallbackMethod(Method method) {
this.method = method;
}
/*
* @see
* com.impetus.kundera.ejb.event.CallbackMethod#invoke(java.lang.Object)
*/
public void invoke(Object entity) throws IllegalArgumentException,
IllegalAccessException, InvocationTargetException,
InstantiationException {
if (!method.isAccessible())
method.setAccessible(true);
method.invoke(entity, new Object[] {});
}
/* @see java.lang.Object#toString() */
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(entityClazz.getName() + "." + method.getName());
return builder.toString();
}
}
/**
* The Class Relation.
*/
public final class Relation {
/** The property. */
private Field property;
/** The target entity. */
private Class<?> targetEntity;
/** The property type. */
private Class<?> propertyType;
/** The fetch type. */
private FetchType fetchType;
/** The cascades. */
private List<CascadeType> cascades;
/** The optional. */
private boolean optional;
/** The mapped by. */
private String mappedBy;
/** The type. */
private ForeignKey type;
/**
* Instantiates a new relation.
*
* @param property
* the property
* @param targetEntity
* the target entity
* @param propertyType
* the property type
* @param fetchType
* the fetch type
* @param cascades
* the cascades
* @param optional
* the optional
* @param mappedBy
* the mapped by
* @param type
* the type
*/
public Relation(Field property, Class<?> targetEntity,
Class<?> propertyType, FetchType fetchType,
List<CascadeType> cascades, boolean optional, String mappedBy,
ForeignKey type) {
super();
this.property = property;
this.targetEntity = targetEntity;
this.propertyType = propertyType;
this.fetchType = fetchType;
this.cascades = cascades;
this.optional = optional;
this.mappedBy = mappedBy;
this.type = type;
}
/**
* Gets the property.
*
* @return the property
*/
public Field getProperty() {
return property;
}
/**
* Gets the target entity.
*
* @return the targetEntity
*/
public Class<?> getTargetEntity() {
return targetEntity;
}
/**
* Gets the property type.
*
* @return the propertyType
*/
public Class<?> getPropertyType() {
return propertyType;
}
/**
* Gets the fetch type.
*
* @return the fetchType
*/
public FetchType getFetchType() {
return fetchType;
}
/**
* Gets the cascades.
*
* @return the cascades
*/
public List<CascadeType> getCascades() {
return cascades;
}
/**
* Checks if is optional.
*
* @return the optional
*/
public boolean isOptional() {
return optional;
}
/**
* Gets the mapped by.
*
* @return the mappedBy
*/
public String getMappedBy() {
return mappedBy;
}
/**
* Gets the type.
*
* @return the type
*/
public ForeignKey getType() {
return type;
}
/**
* Checks if is unary.
*
* @return true, if is unary
*/
public boolean isUnary() {
return type.equals(ForeignKey.ONE_TO_ONE)
|| type.equals(ForeignKey.MANY_TO_ONE);
}
/**
* Checks if is collection.
*
* @return true, if is collection
*/
public boolean isCollection() {
return type.equals(ForeignKey.ONE_TO_MANY)
|| type.equals(ForeignKey.MANY_TO_MANY);
}
}
public DBType getDBType(){
return dbType;
}
public void setDBType(DBType type) {
this.dbType = type;
}
}