Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added dynamic model feature. #404

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion activejdbc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>activejdbc</artifactId>
<packaging>jar</packaging>
<version>1.4.11-SNAPSHOT</version>
<name>JavaLite - ActiveJDBC ORM Framework</name>


Expand Down Expand Up @@ -328,5 +327,10 @@
<version>2.4.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.18.2-GA</version>
</dependency>
</dependencies>
</project>
209 changes: 202 additions & 7 deletions activejdbc/src/main/java/org/javalite/activejdbc/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
*/
package org.javalite.activejdbc;

import org.h2.util.StringUtils;
import org.javalite.activejdbc.annotations.Cached;
import org.javalite.activejdbc.annotations.DbName;
import org.javalite.activejdbc.annotations.IdGenerator;
import org.javalite.activejdbc.annotations.IdName;
import org.javalite.activejdbc.annotations.Table;
import org.javalite.activejdbc.annotations.VersionColumn;
import org.javalite.activejdbc.cache.CacheManager;
import org.javalite.activejdbc.dialects.*;
import org.slf4j.Logger;
Expand All @@ -26,6 +33,20 @@
import java.io.InputStreamReader;
import java.net.URL;
import java.util.*;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtNewConstructor;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ConstPool;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.StringMemberValue;

import org.javalite.common.Collections;
import org.javalite.common.Convert;

import static org.javalite.common.Util.*;
Expand All @@ -35,14 +56,107 @@
*/
public class Configuration {

//key is a DB name, value is a list of model names
private Map<String, List<String>> modelsMap = new HashMap<String, List<String>>();
public static class ModelAttributes {
private String tableName;
private String idColumn;
private String idGeneratorCode;
private String versionColumn;
private String dbName = DB.DEFAULT_NAME;
private Boolean cached;

public ModelAttributes() {

}



public ModelAttributes(String dbName, String tableName, Boolean cached,
String idColumn, String idGeneratorCode, String versionColumn) {
this.dbName = dbName;
this.tableName = tableName;
this.cached = cached;
this.idColumn = idColumn;
this.idGeneratorCode = idGeneratorCode;
this.versionColumn = versionColumn;
}

public ModelAttributes(String dbName) {
this.dbName = dbName;
}


public ModelAttributes(String dbName, String tableName) {
this.dbName = dbName;
this.tableName = tableName;
}

public ModelAttributes(String dbName, String tableName, Boolean cached) {
this.dbName = dbName;
this.tableName = tableName;
this.cached = cached;
}

public ModelAttributes(String dbName, String tableName, Boolean cached,
String idColumn) {
this.dbName = dbName;
this.tableName = tableName;
this.cached = cached;
this.idColumn = idColumn;
}

public String getTableName() {
return tableName;
}
public String getIdColumn() {
return idColumn;
}
public String getIdGeneratorCode() {
return idGeneratorCode;
}
public String getVersionColumn() {
return versionColumn;
}
public String getDbName() {
return dbName;
}
public Boolean getCached() {
return cached;
}


}
//key is a DB name, value is a list of model names
private Map<String, Collection<String>> modelsMap = new HashMap<String, Collection<String>>();
private Set<String> modelNameSet = new HashSet<String>();
private Properties properties = new Properties();
private static CacheManager cacheManager;
private final static Logger logger = LoggerFactory.getLogger(Configuration.class);


private Map<String, Dialect> dialects = new CaseInsensitiveMap<Dialect>();


public void addModel(String modelName) {
addModel(modelName,new ModelAttributes());
}

public void addModel(String modelName,ModelAttributes modelAttributes) {
modelNameSet.add(modelName);
addModelToDB(modelName,modelAttributes.dbName);
loadModelClass(modelName, modelAttributes);
}

private void addModelToDB(String modelName,String dbName) {
Collection<String> dbModels = null;
if(!modelsMap.containsKey(dbName)) {
dbModels = new HashSet<String>();
modelsMap.put(dbName,dbModels);
} else {
dbModels = modelsMap.get(dbName);
}

dbModels.add(modelName);
}

protected Configuration(){
try {
Enumeration<URL> resources = getClass().getClassLoader().getResources("activejdbc_models.properties");
Expand All @@ -63,7 +177,7 @@ protected Configuration(){
String modelName = parts[0];
String dbName = parts[1];

List<String> modelNames = modelsMap.get(dbName);
Collection<String> modelNames = modelsMap.get(dbName);
if (modelNames == null) {
modelNames = new ArrayList<String>();
modelsMap.put(dbName, modelNames);
Expand Down Expand Up @@ -96,15 +210,15 @@ protected Configuration(){
try{
Class cmc = Class.forName(cacheManagerClass);
cacheManager = (CacheManager)cmc.newInstance();
}catch(Exception e){
} catch(Exception e) {
throw new InitException("failed to initialize a CacheManager. Please, ensure that the property " +
"'cache.manager' points to correct class which extends 'org.javalite.activejdbc.cache.CacheManager' class and provides a default constructor.", e);
}

}
}

List<String> getModelNames(String dbName) throws IOException {
Collection<String> getModelNames(String dbName) throws IOException {
return modelsMap.get(dbName);
}

Expand Down Expand Up @@ -148,8 +262,89 @@ else if(mm.getDbType().equalsIgnoreCase("SQLite")){
return dialect;
}


public CacheManager getCacheManager(){
return cacheManager;
}

private static Class<? extends Model> loadModelClass(String className,Configuration.ModelAttributes attribs) {
try {
return (Class<? extends Model>) Class.forName(className);
} catch (ClassNotFoundException ignore) {
}


// Create the class.
try {
ClassPool pool = ClassPool.getDefault();

// Create the class.
CtClass subClass = pool.makeClass(className);

//***set annotations
ConstPool constPool = subClass.getClassFile().getConstPool();
AnnotationsAttribute attr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
subClass.getClassFile().addAttribute(attr);
Annotation anno = null;

//db name annotation
if(!StringUtils.isNullOrEmpty(attribs.dbName)) {
anno = new Annotation(constPool, pool.get(DbName.class.getName()));
anno.addMemberValue("value", new StringMemberValue(attribs.dbName, constPool));
attr.setAnnotation(anno);
}

//table name annotation
if(!StringUtils.isNullOrEmpty(attribs.tableName)) {
anno = new Annotation(constPool, pool.get(Table.class.getName()));
anno.addMemberValue("value", new StringMemberValue(attribs.tableName, constPool));
attr.setAnnotation(anno);
}

//id column annotation
if(!StringUtils.isNullOrEmpty(attribs.idColumn)) {
anno = new Annotation(constPool, pool.get(IdName.class.getName()));
anno.addMemberValue("value", new StringMemberValue(attribs.idColumn, constPool));
attr.setAnnotation(anno);
}

//id generator code annotation
if(!StringUtils.isNullOrEmpty(attribs.idGeneratorCode)) {
anno = new Annotation(constPool, pool.get(IdGenerator.class.getName()));
anno.addMemberValue("value", new StringMemberValue(attribs.idGeneratorCode, constPool));
attr.setAnnotation(anno);
}

//version column annotation
if(!StringUtils.isNullOrEmpty(attribs.versionColumn)) {
anno = new Annotation(constPool, pool.get(VersionColumn.class.getName()));
anno.addMemberValue("value", new StringMemberValue(attribs.versionColumn, constPool));
attr.setAnnotation(anno);
}

//cached annotation
if(attribs.cached != null && attribs.cached == true) {
anno = new Annotation(constPool, pool.get(Cached.class.getName()));
attr.setAnnotation(anno);
}


//set super class
final CtClass superClass = pool.get(Model.class.getName());
subClass.setSuperclass(superClass);
subClass.setModifiers( Modifier.PUBLIC );

CtConstructor constr = CtNewConstructor.defaultConstructor(subClass);
constr.setModifiers(Modifier.PUBLIC);
subClass.addConstructor(constr);


return subClass.toClass();
} catch (CannotCompileException ex) {
throw new RuntimeException(ex);
} catch (NotFoundException ex) {
throw new RuntimeException(ex);
}
}

}
25 changes: 25 additions & 0 deletions activejdbc/src/main/java/org/javalite/activejdbc/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilderFactory;

import java.io.*;
import java.math.BigDecimal;
import java.sql.Clob;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.util.*;

import org.javalite.activejdbc.conversion.BlankToNullConverter;
import org.javalite.activejdbc.conversion.ZeroToNullConverter;
import org.javalite.activejdbc.dialects.Dialect;
Expand Down Expand Up @@ -1726,6 +1728,29 @@ public <C extends Model> LazyList<C> getAll(Class<C> clazz) {
return get(tableName, null);
}

/**
* This methods supports one to many, many to many relationships as well as polymorphic associations.
* <p/>
* In case of one to many, the <code>className</code> must be a class of a child model, and it will return a
* collection of all children.
* <p/>
* In case of many to many, the <code>className</code> must be a class of a another related model, and it will return a
* collection of all related models.
* <p/>
* In case of polymorphic, the <code>className</code> must be a class of a polymorphically related model, and it will return a
* collection of all related models.
*
*
* @param className class of a child model for one to many, or class of another model, in case of many to many or class of child in case of
* polymorphic
*
* @return list of children in case of one to many, or list of other models, in case many to many.
* @throws ClassNotFoundException
*/

public <C extends Model> LazyList<C> getAll(String className) throws ClassNotFoundException {
return getAll((Class<C>) Class.forName(className));
}

/**
* Provides a list of child models in one to many, many to many and polymorphic associations, but in addition also allows to filter this list
Expand Down
Loading