/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package reportgen.cores.ejb;
import reportgen.cores.ejb.annotations.DefineQueryProperty;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.persistence.Entity;
import reportgen.prototype.context.group.ContextGroup;
import reportgen.prototype.entity.QEntity;
import reportgen.cores.ejb.set.QEntitySet;
import reportgen.cores.ejb.annotations.DefineQueryEntity;
/**
* проверка
* QueryGeneratorProperty\(title=MSGT_([^ ]+), embedded=true\)(.*?\n)*.*?QueryGeneratorProperty\(title=MSGT_\1\)
* QueryGeneratorProperty\(title=MSGT_([^ ]+)\)(.*?\n)*.*?QueryGeneratorProperty\(title=MSGT_\1, embedded=true\)
* QueryGeneratorProperty\(title=MSGT_([^ ]+), embedded=true\)(.*?\n)*.*?(?!QueryGeneratorProperty\(title=MSGT_\1\))
*
* @author axe
*/
public abstract class QueryEntitySet implements QEntitySet {
private static Map<Class, Set<LinkedReportEntity>> linkedClasses =
new HashMap<Class, Set<LinkedReportEntity>>();
private static Set<Class> reportSet = new HashSet<Class>();
private static Map<String, Class> classLoaderMap = new HashMap<String, Class>();
/**
* Возвращает список всех доступных для отчета сущностей
* @return
*/
@Override
public QEntity[] getAvailableEntities(ContextGroup coreContextGroup) {
QEntity res[] = new QEntity[reportSet.size()];
int i=0;
for(Class keyClass : reportSet) {
res[i++] = new QueryEntity(keyClass, coreContextGroup);
}
return res;
}
/**
* Возвращает список всех сущностей ссылающихся на указанную сущность
* @param cls
* @return
*/
LinkedReportEntity[] getLinkedClasses(Class cls) {
Set<LinkedReportEntity> lc = linkedClasses.get(cls);
if(lc == null || lc.size() == 0) {
return null;
}
LinkedReportEntity[] ren = new LinkedReportEntity[lc.size()];
lc.toArray(ren);
return ren;
}
protected static void setAvailiableClasses(Set<Class> classes) {
reportSet.addAll(classes);
for(Class cls: classes) {
checkIsValidFields(cls);
checkIsValidMethods(cls);
classLoaderMap.put(cls.getSimpleName(), cls);
//find all linked classes
Set<LinkedReportEntity> assoc = new HashSet<LinkedReportEntity>();
Iterator<Class> sit2 = reportSet.iterator();
while(sit2.hasNext()) {
Class classi = sit2.next();
if(classi == cls) {
continue;
}
Field f[] = classi.getDeclaredFields();
for(int k=0; k<f.length; k++) {
if(f[k].getType().equals(cls)) {
LinkedReportEntity classAssoc = new
LinkedReportEntity(classi, f[k].getName());
assoc.add(classAssoc);
break;
}
}
}
linkedClasses.put(cls, assoc);
}
}
/**
* проверка валидности метода
* @param cls
*/
private static void checkIsValidMethods(Class cls) {
Method methods[] = cls.getMethods();
for(Method m : methods) {
String title = m.getName();
Annotation ann = m.getAnnotation(DefineQueryProperty.class);
boolean returnEntity = m.getReturnType().isAnnotationPresent(Entity.class);
if(ann != null) {
DefineQueryProperty qp = (DefineQueryProperty) ann;
if(!qp.embedded() && returnEntity) {
throw new RuntimeException("Класс " + cls.getName() + " аннотирует метод " + m.getName()
+ " возвращающий невстроенный " + m.getReturnType().getName());
} else if(returnEntity
&& !m.getReturnType().isAnnotationPresent(DefineQueryEntity.class)) {
throw new RuntimeException("Класс " + cls.getName() + " аннотирует метод " + m.getName()
+ " возвращающий недокументированный " + m.getReturnType().getName());
} else if(returnEntity
&& !reportSet.contains(m.getReturnType())) {
throw new RuntimeException("Класс " + cls.getName() + " аннотирует метод " + m.getName()
+ " возвращающий не зарегистрированный " + m.getReturnType().getName());
} else if(isFieldPresent(cls, title)) {
throw new RuntimeException("Класс " + cls.getName()
+ " аннотирует лишний метод " + title);
}
} /*else if(!returnEntity
&& !isReturnCollection(m)) {
if(!m.getName().equals("toString")
&& !m.getName().equals("getDetails")
&& !m.getName().equals("getDirectoryDetails")
&& !m.getName().equals("hashcode")
&& !m.getName().equals("equals")
&& !m.getName().equals("wait")
&& !m.getName().equals("getClass")
&& !m.getName().equals("notify")
&& !m.getName().equals("notifyAll")
&& m.getName().startsWith("get")) {
System.out.println("Класс " + cls.getName() + " НЕ аннотирует метод "
+ m.getName() + " возвращающий " + m.getReturnType().getName());
}
}*/
}
}
private static boolean isFieldPresent(Class cls, String method) {
String field = null;
if(method.startsWith("get")) {
field = method.substring(2);
} else if(method.startsWith("get")) {
field = method.substring(3);
}
if(field == null) {
return false;
}
field = field.substring(0, 1).toLowerCase() + field.substring(1);
boolean exist = false;
try {
cls.getField(field);
exist = true;
} catch (NoSuchFieldException ex) {
// not exist
}
return exist;
}
/**
* проверяет метод, что он возвращает коллекцию
* @param m
* @return
*/
private static boolean isReturnCollection(Method m){
Class<?> returnType = m.getReturnType();
return Collection.class.isAssignableFrom(returnType);
}
private static void checkIsValidFields(Class cls) {
HashSet<Class> embedded = new HashSet<Class>();
Field fields[] = cls.getFields();
for(Field f : fields) {
if (!Modifier.isStatic(f.getModifiers())){
continue;
}
Annotation ann = f.getAnnotation(DefineQueryProperty.class);
boolean isEntity = f.getType().isAnnotationPresent(Entity.class);
Class type = f.getType();
if(ann == null) {
if(!Modifier.isStatic(f.getModifiers())) {
System.out.println("Класс " + cls.getName() + " НЕ аннотирует поле " + f.getName()
+ " типа " + type.getName());
}
} else {
if(isEntity && !reportSet.contains(type)) {
throw new RuntimeException("Класс " + cls.getName() + " аннотирует поле " + f.getName()
+ " не зарегистрированного типа " +type.getName());
}
DefineQueryProperty qp = (DefineQueryProperty) ann;
if(qp.embedded()) {
if(!isEntity) {
throw new RuntimeException("Класс " + cls.getName()
+ " аннотирует поле 'не сущность' типа " + type.getName() + " как встроенное");
}
if(embedded.contains(type)) {
throw new RuntimeException("Класс " + cls.getName()
+ " повторно аннотирует поле типа " + type.getName() + " как встроенное");
} else {
embedded.add(type);
}
}
}
}
}
@Override
public Class getClassFromName(String simpleName) {
return classLoaderMap.get(simpleName);
}
}