![JAR search and dependency download from the Maven repository](/logo.png)
org.devocative.devolcano.MetaHandler Maven / Gradle / Ivy
package org.devocative.devolcano;
import com.thoughtworks.xstream.XStream;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import org.apache.commons.io.FileUtils;
import org.devocative.devolcano.vo.ClassVO;
import org.devocative.devolcano.vo.FieldVO;
import org.devocative.devolcano.xml.metadata.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class MetaHandler {
private static final Logger logger = LoggerFactory.getLogger(MetaHandler.class);
private static final String META_FILE_STR = "/dlava/Metadata.xml";
//TODO find a better way!
private static final List IGNORED_FIELDS = Arrays.asList("creatorUserId", "modifierUserId");
private static final List READ_ONLY_FIELDS = Arrays.asList(
"rowMod", "creatorUser", "creationDate",
"modifierUser", "modificationDate");
private static final List LIST_ONLY_FIELDS = Arrays.asList("version");
private static final XStream X_STREAM;
private static File META_FILE;
private static XMeta X_META;
private static ClassLoader CLASS_LOADER;
private static final GroovyShell GROOVY_SHELL = new GroovyShell();
private static Script FILTER_CLASS_CHECK;
// ------------------------------
static {
X_STREAM = new XStream();
X_STREAM.processAnnotations(XMeta.class);
}
// ------------------------------
public static void init(String baseDir) throws Exception {
logger.info("MetaHandler: Base Dir = {}", baseDir);
META_FILE = new File(baseDir + META_FILE_STR);
if (META_FILE.exists()) {
logger.info("Metadata file: {}", META_FILE.getCanonicalPath());
X_META = (XMeta) X_STREAM.fromXML(META_FILE);
} else {
logger.info("Metadata file not exist!");
X_META = new XMeta();
X_META.setClasses(new ArrayList<>());
}
CLASS_LOADER = Thread.currentThread().getContextClassLoader();
}
public static Map> scan(String pkg, boolean includeSubPackages) {
logger.info("Start Scanning Package: {}", pkg);
Map> result = new HashMap<>();
Collection classes = processPackage(pkg, includeSubPackages);
for (Class aClass : classes) {
ClassVO classVO = new ClassVO(aClass);
logger.info("\tscanning class: {}", aClass.getName());
XMetaClass xMetaClass = X_META.findXMetaClass(aClass.getName());
if (xMetaClass == null) {
xMetaClass = new XMetaClass();
xMetaClass.setFqn(aClass.getName());
xMetaClass.setFields(new ArrayList<>());
X_META.getClasses().add(xMetaClass);
result.put(xMetaClass, null); // New Class Added!
}
if (xMetaClass.getInfo() == null) {
xMetaClass.setInfo(new XMetaInfoClass());
}
List idFields = new ArrayList<>();
List newXMetaFields = scanFields(classVO, xMetaClass, idFields);
if (!newXMetaFields.isEmpty() && !result.containsKey(xMetaClass)) {
result.put(xMetaClass, newXMetaFields);
}
if (xMetaClass.getId() == null) {
xMetaClass.setId(new XMetaId());
}
xMetaClass.getId().setRef(toCSV(idFields));
}
logger.info("Finished Scanning Package: {}", pkg);
return result;
}
public static void write() throws IOException {
META_FILE.getParentFile().mkdirs();
logger.info("Writing to Metadata.xml: {}", META_FILE.getCanonicalPath());
try {
String xml = X_STREAM.toXML(X_META);
xml = xml.replaceAll(" ", "\t");
FileWriter writer = new FileWriter(META_FILE);
writer.write("\n\n");
writer.write("\n\n");
writer.write(xml);
writer.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static XMetaClass findXMetaClass(String fqn) {
return X_META.findXMetaClass(fqn);
}
public static Set processPackage(String packageName, Boolean includeSubPackages) {
if (X_META.getFilterClass() != null) {
FILTER_CLASS_CHECK = GROOVY_SHELL.parse(X_META.getFilterClass());
}
try {
String path = packageName.replace('.', '/');
return findClasses(path, includeSubPackages);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String toCSV(Collection col) {
if (col.size() > 0) {
StringBuilder builder = new StringBuilder();
for (Object o : col) {
builder
.append(o.toString())
.append(",");
}
String s = builder.toString();
return s.substring(0, s.length() - 1);
}
return "";
}
// ------------------------------
private static List scanFields(ClassVO classVO, XMetaClass xMetaClass, List idFields) {
List result = new ArrayList<>();
for (FieldVO fieldVO : classVO.getDeclaredFieldsMap().values()) {
if (!fieldVO.isStatic() && !fieldVO.isFinal()) {
XMetaField xMetaField = xMetaClass.findXMetaField(fieldVO.getName());
if (xMetaField == null) {
xMetaField = new XMetaField();
xMetaField.setName(fieldVO.getName());
if (IGNORED_FIELDS.contains(fieldVO.getName()) || fieldVO.isStatic()) {
xMetaField.getInfo().setIgnore(true);
}
if (READ_ONLY_FIELDS.contains(fieldVO.getName()) || LIST_ONLY_FIELDS.contains(fieldVO.getName())) {
xMetaField.getInfo().setHasForm(false);
}
if (LIST_ONLY_FIELDS.contains(fieldVO.getName())) {
xMetaField.getInfo().setHasFVO(false);
}
if (fieldVO.isOf(Date.class)) {
xMetaField.getInfo().setHasTimePart(true);
}
xMetaClass.getFields().add(xMetaField);
result.add(xMetaField);
}
if (xMetaField.getInfo() == null) {
xMetaField.setInfo(new XMetaInfoField());
}
if (fieldVO.isId()) {
idFields.add(xMetaField);
}
}
}
return result;
}
private static Set findClasses(String dirStr, boolean recursive) throws Exception {
String[] extensions = new String[]{"class"};
List list = new ArrayList<>();
Enumeration resources = CLASS_LOADER.getResources(dirStr);
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
switch (url.getProtocol()) {
case "file":
File dir = new File(url.toURI());
if (dir.isDirectory()) {
logger.info("\tFind Classes Under Directory: {}", dir.getAbsolutePath());
Collection files = FileUtils.listFiles(new File(url.getPath()), extensions, recursive);
for (File f : files) {
String path = f.getAbsolutePath().replace('\\', '/');
int i = path.indexOf(dirStr);
list.add(path.substring(i));
}
} else {
throw new RuntimeException("Invalid Directory: " + dir);
}
break;
case "jar":
String jarPath = url.getPath().substring(5, url.getPath().indexOf("!"));
logger.info("\tFind Classes in JAR = {}", jarPath);
try (JarFile jar = new JarFile(URLDecoder.decode(jarPath, "UTF-8"))) {
Enumeration entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
String name = jarEntry.getName();
if (!jarEntry.isDirectory() && name.startsWith(dirStr) && hasExtension(name, extensions)) {
if (recursive) {
list.add(name);
} else if (!name.substring(dirStr.length() + 1).contains("/")) {
list.add(name);
}
}
}
}
break;
default:
throw new RuntimeException("Unsupported Protocol: " + url.getProtocol());
}
}
Set result = new HashSet<>();
for (String s : list) {
Class> cls = Class.forName(s.substring(0, s.length() - 6).replace('/', '.'), true, CLASS_LOADER);
if (FILTER_CLASS_CHECK != null) {
ClassVO classVO = new ClassVO(cls);
Binding binding = new Binding();
binding.setVariable("targetClass", classVO);
FILTER_CLASS_CHECK.setBinding(binding);
Boolean isValid = (Boolean) FILTER_CLASS_CHECK.run();
if (isValid) {
result.add(cls);
}
} else {
result.add(cls);
}
}
return result;
}
private static boolean hasExtension(String dir, String[] exts) {
if (exts != null) {
for (String ext : exts) {
if (dir.endsWith("." + ext)) {
return true;
}
}
return false;
}
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy