package br.com.produban.openbus.camus.schemaregistry;
import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.CRC32;
import org.apache.avro.Schema;
import org.apache.avro.specific.AvroGenerated;
import org.apache.avro.specific.SpecificRecordBase;
import org.apache.log4j.Logger;
import com.linkedin.camus.schemaregistry.SchemaDetails;
import com.linkedin.camus.schemaregistry.SchemaRegistry;
/**
* This is a little dummy registry that just uses a memory-backed schema
* registry to store two dummy Avro schemas. You can use this with
* camus.properties
*/
public class AvroLocalSchemaRegistry implements SchemaRegistry<Schema> {
private final static String SCHEMA_PACKAGE = "kafka.registry.schemaPackage";
private final Map<Integer, Schema> schemasById;
public AvroLocalSchemaRegistry() {
schemasById = new ConcurrentHashMap<Integer, Schema>();
}
public void init(Properties properties) {
// classpath scanning
String packageName = properties.getProperty(SCHEMA_PACKAGE);
System.out.println("Schema Package:" +packageName);
List<Class> classes = scan(packageName);
// Register every Record's Schema
for (Class<?> clazz : classes) {
try {
SpecificRecordBase genericRecord = (SpecificRecordBase) clazz.newInstance();
register(null, genericRecord.getSchema());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
@Override
public String register(String topic, Schema schema) {
/* register to id-Schema Map */
byte[] schemaBytes = schema.toString().getBytes();
// calculo do crc32
CRC32 checksum = new CRC32();
checksum.reset();
checksum.update(schemaBytes, 0, schemaBytes.length);
// crc32 em string
int id = (int) checksum.getValue();
// register Schema
schemasById.put(id, schema);
Logger.getLogger(this.getClass()).info("\t\t\tRegister Schema : ID = " + id );
Logger.getLogger(this.getClass()).info("\t\t\tRegister Schema : " + schema.toString());
return String.valueOf(id);
}
@Override
public Schema getSchemaByID(String topic, String id) {
return schemasById.get(Integer.parseInt(id));
}
@Override
public SchemaDetails<Schema> getLatestSchemaByTopic(String topic) {
// Schema is not mapped by topic on this implementation
return null;
}
public List<Class> scan(String packageName){
Logger.getLogger(this.getClass()).info("Scan : PackageName " + packageName);
List<Class> classList = new ArrayList<Class>();
// Thread classpath scanning
String classpath = System.getProperty("java.class.path");
String[] cpEntries = classpath.split(File.pathSeparator);
// convert package to path string
packageName = packageName.replace(".", "/");
// jar lookup in every classpath entry
for (String cpEntry : cpEntries) {
// only .jar files
if (!cpEntry.contains("/lib/") && cpEntry.endsWith(".jar") && !cpEntry.contains("*") && !(new File(cpEntry).isDirectory())) {
Logger.getLogger(this.getClass()).info("\tScanning entry : " + cpEntry);
try {
// look for every entry inside .jar file
JarURLConnection jarURLConnection = (JarURLConnection) new URL("jar:file:" + cpEntry + "!/").openConnection();
JarFile jarFile = jarURLConnection.getJarFile();
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
String path = entries.nextElement().getName();
// filter: classes inside a specific package, excluding inner classes
if (path.endsWith(".class") && path.startsWith(packageName) && !path.contains("$")) {
String className = path.replace("/", ".").substring(0, path.length() - 6);
// filter: AvroGenerated classes only
Class clazz = Class.forName(className);
if (clazz.isAnnotationPresent(AvroGenerated.class)) {
classList.add(clazz);
Logger.getLogger(this.getClass()).info("\t\tAvro Generated Schema found : " + className);
}
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
return classList;
}
}