com.javanut.pronghorn.pipe.util.build.FROMValidation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pronghorn-pipes Show documentation
Show all versions of pronghorn-pipes Show documentation
Ring buffer based queuing utility for applications that require high performance and/or a small
footprint. Well suited for embedded and stream based processing.
package com.javanut.pronghorn.pipe.util.build;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import javax.xml.parsers.ParserConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
import com.javanut.pronghorn.pipe.DataInputBlobReader;
import com.javanut.pronghorn.pipe.FieldReferenceOffsetManager;
import com.javanut.pronghorn.pipe.MessageSchema;
import com.javanut.pronghorn.pipe.PipeReader;
import com.javanut.pronghorn.pipe.PipeWriter;
import com.javanut.pronghorn.pipe.RawDataSchema;
import com.javanut.pronghorn.pipe.schema.loader.TemplateHandler;
import com.javanut.pronghorn.pipe.token.TokenBuilder;
import com.javanut.pronghorn.pipe.token.TypeMask;
import com.javanut.pronghorn.util.Appendables;
public class FROMValidation {
public final static Logger logger = LoggerFactory.getLogger(FROMValidation.class);
public static boolean forceCodeGen = false;
private static > boolean testForMatchingFROMs(String templateFile, S schema) {
boolean result = false;
StringBuilder target = new StringBuilder();
try {
FieldReferenceOffsetManager encodedFrom = null;
try {
encodedFrom = MessageSchema.from(schema); //TODO: new projects get null pointer here, fix so they are given correct source.
} catch (NullPointerException npe) {
//continue with no previous FROM
}
result = testForMatchingFROMs(templateFile, encodedFrom, target);
if (!result) {
System.out.println(target);
}
} catch (Exception e) {
e.printStackTrace();
result = false;
}
return result;
}
private static boolean testForMatchingFROMs(String templateFile,
FieldReferenceOffsetManager encodedFrom, Appendable target)
throws ParserConfigurationException, SAXException, IOException {
boolean result = true;
FieldReferenceOffsetManager expectedFrom = TemplateHandler.loadFrom(templateFile);
if (null==expectedFrom) {
logger.error("Unable to find: "+templateFile);
result = false;
} else if (null==encodedFrom || !expectedFrom.equals(encodedFrom)) {
logger.error("Encoded source:"+expectedFrom);
if (null!=encodedFrom) {
logger.error("Template file:"+encodedFrom);
}
logger.error("//replacement source");
String nameOfFROM = templateFile.substring(1+templateFile.lastIndexOf('/') );
FieldReferenceOffsetManager.buildFROMConstructionSource(target, expectedFrom, "FROM", nameOfFROM);
result = false;
}
return result;
}
public static > boolean checkSchema(String templateFile, Class clazz, boolean forceCode) {
try {
FROMValidation.forceCodeGen = forceCode;
return checkSchema(templateFile, clazz);
} finally {
FROMValidation.forceCodeGen = false;
}
}
public static > boolean checkSchema(String templateFile, Class clazz) {
StringBuilder target = new StringBuilder();
S schemaInstance = MessageSchema.findInstance(clazz);
/////////////////////////
/////////////////////////
FieldReferenceOffsetManager expectedFrom = null;
try {
expectedFrom = TemplateHandler.loadFrom(templateFile);
} catch (Exception e2) {
e2.printStackTrace();
}
if (null==expectedFrom) {
logger.error("Unable to find: {}",templateFile);
return false;
}
/////////////////////////
/////////////////////////
boolean result = true;
if (null!=schemaInstance) {
try {
FieldReferenceOffsetManager encodedFrom = null;
encodedFrom = MessageSchema.from(schemaInstance);
if (null==encodedFrom || !expectedFrom.equals(encodedFrom)) {
logger.error("Encoded source:"+expectedFrom);
if (null!=encodedFrom) {
logger.error("Template file:"+encodedFrom);
}
logger.error("//replacement source, encoded from missing or not matching");
result = false;
}
FieldReferenceOffsetManager.buildFROMConstructionSource(
target, expectedFrom,
"FROM", templateFile.substring(1+templateFile.lastIndexOf('/') ));
buildConstructor(target, clazz);//want FROM to be first at the top
//////////////////
//////////////////
if (!result) {
forceCodeGen = true;
}
result &= testForMatchingLocators(clazz, expectedFrom, target);
//////////////////
//////////////////
} catch (Exception e1) {
e1.printStackTrace();
result = false;
}
} else {
result = false;
try {
logger.error("Encoded source: {}",expectedFrom);
logger.error("//replacement source, schema instance missing");
FieldReferenceOffsetManager.buildFROMConstructionSource(
target,
expectedFrom,
"FROM",
templateFile.substring(1+templateFile.lastIndexOf('/') ));
buildConstructor(target, clazz);//want FROM to be first at the top
//////////////////
//////////////////
forceCodeGen = true;
testForMatchingLocators(clazz, expectedFrom, target);
//////////////////
//////////////////
} catch (Exception e1) {
logger.error("unable to build FROM {} {}",e1.getClass().getSimpleName(),e1.getMessage());
}
}
if (!result) {
System.out.println(target);
}
return result;
}
private static > void buildConstructor(Appendable target, Class clazz) {
//show the new constructor
try {
target.append("\n");
target.append("public "+clazz.getSimpleName()+"() { \n");
target.append(" super(FROM);\n");
target.append("}\n");
target.append("\n");
target.append("protected "+clazz.getSimpleName()+"("+FieldReferenceOffsetManager.class.getSimpleName()+" from) { \n");
target.append(" super(from);\n");
target.append("}\n");
target.append("\n");
//show the line needed for adding the instance
target.append("public static final "+clazz.getSimpleName()+" instance = new "+clazz.getSimpleName()+"();\n");
target.append("\n");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static boolean testForMatchingLocators(
Class schemaClass,
FieldReferenceOffsetManager encodedFrom,
Appendable target) throws IOException {
Field[] fields = schemaClass.getFields();
if (MessageSchema.class != schemaClass.getSuperclass()) {
System.out.println("all Schema objects must directly extend "+MessageSchema.class.getCanonicalName());
return false;
}
int[] msgStart = encodedFrom.messageStarts;
//TODO: at some point we want to code generate low level examples...
StringBuilder generatedConstants = new StringBuilder();
StringBuilder generatedSwitch = new StringBuilder();
StringBuilder generatedConsumers = new StringBuilder();
StringBuilder generatedProducersTemp1 = new StringBuilder();
StringBuilder generatedProducersTemp2 = new StringBuilder();
StringBuilder generatedProducers = new StringBuilder();
boolean success1 = generateSchemaBehavior(encodedFrom, fields, msgStart, generatedConstants, generatedSwitch,
generatedConsumers, generatedProducersTemp1, generatedProducersTemp2, generatedProducers,
schemaClass.getSimpleName(), encodedFrom.hasSimpleMessagesOnly);
if (encodedFrom.hasSimpleMessagesOnly) {
success1 = checkForExampleCode(schemaClass, success1, "consume"); //must find at least 1 consume method
success1 = checkForExampleCode(schemaClass, success1, "publish"); //must find at least 1 publish method
}
boolean success = success1;
if (!success || forceCodeGen) {
//to target, do not log.
target.append(generatedConstants);
target.append("\n");
target.append(generatedSwitch);
target.append("\n");
target.append(generatedConsumers);
target.append("\n");
target.append(generatedProducers);
}
return success;
}
private static boolean generateSchemaBehavior(FieldReferenceOffsetManager encodedFrom, Field[] fields,
int[] msgStart, StringBuilder generatedConstants, StringBuilder generatedSwitch,
StringBuilder generatedConsumers, StringBuilder generatedProducersTemp1,
StringBuilder generatedProducersTemp2, StringBuilder generatedProducers, final String schemaClassName,
boolean generateExampleMethods) {
if (generateExampleMethods) {
generatedSwitch.append("public static void consume(Pipe<").append(schemaClassName).append("> input) {\n");
generatedSwitch.append(" while (PipeReader.tryReadFragment(input)) {\n");
generatedSwitch.append(" int msgIdx = PipeReader.getMsgIdx(input);\n");
generatedSwitch.append(" switch(msgIdx) {\n");
}
boolean success = true;
for(int i = 0 ; i=0 && !found) {
String schemaFieldName = fields[j].getName();
if (schemaFieldName.equals(messageConstantName)) {
found = true;
try {
int assignedValue = fields[j].getInt(null);
if (expectedMsgIdx != assignedValue) {
success = false;
//logger.error(("//wrong expected value: "+messageConstantName);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
found = false;
} catch (IllegalAccessException e) {
e.printStackTrace();
found = false;
}
}
}
if (!found) {
success = false;
logger.error("//unable to find: {}",messageConstantName);
}
int fieldLimit;
if (i+1>=msgStart.length) {
fieldLimit = encodedFrom.fieldIdScript.length;
} else {
fieldLimit = msgStart[i+1];
}
for(int fieldIdx = msgStart[i]+1; fieldIdx=0 && !found) {
String schemaFieldName = fields[j].getName();
if (schemaFieldName.equals(messageFieldConstantName)) {
found = true;
try {
int assignedValue = fields[j].getInt(null);
if (fieldLOC != assignedValue) {
success = false;
//logger.error(("//wrong expected value: "+messageFieldConstantName);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
found = false;
} catch (IllegalAccessException e) {
e.printStackTrace();
found = false;
}
}
}
if (!found) {
success = false;
logger.error("//unable to find: {}",messageFieldConstantName);
}
}
}
if (generateExampleMethods) {
appendProduceMethodEnd(generatedProducersTemp1, generatedProducersTemp2, generatedProducers, methodName, messageConstantName, schemaClassName);
appendConsumeMethodEnd(generatedConsumers);
}
}
}
if (generateExampleMethods) {
generatedSwitch.append(" case -1:\n");
generatedSwitch.append(" //requestShutdown();\n");
generatedSwitch.append(" break;\n");
generatedSwitch.append(" }\n");
generatedSwitch.append(" PipeReader.releaseReadLock(input);\n }\n}\n");
}
return success;
}
private static > boolean checkForExampleCode(Class schemaClass, boolean success, String startsWith) {
boolean found = false;
for(Method m :schemaClass.getMethods()) {
if (m.getName().startsWith(startsWith)) {
found = true;
}
}
if (!found) {
success = false;
}
return success;
}
private static > void appendConsumeMethodField(StringBuilder generatedConsumers,
String varName, String constName,
int token, String schemaClassName) {
int type = TokenBuilder.extractType(token);
if (TypeMask.isInt(type)) {
generatedConsumers.append(" int ").append(varName).append(" = PipeReader.readInt(input,").append(constName).append(");\n");
} else if (TypeMask.isLong(type)) {
generatedConsumers.append(" long ").append(varName).append(" = PipeReader.readLong(input,").append(constName).append(");\n");
} else if (TypeMask.isDecimal(type)) {
generatedConsumers.append(" int ").append(varName).append("e = PipeReader.readInt(input,").append(constName).append(");\n");
generatedConsumers.append(" long ").append(varName).append("m = PipeReader.readLong(input,").append(constName).append(");\n");
} else if (TypeMask.isText(type)) {
generatedConsumers.append(" StringBuilder ").append(varName).append(" = PipeReader.readUTF8(input,").append(constName)
.append(",new StringBuilder(PipeReader.readBytesLength(input,")
.append(constName).append(")));\n");
} else if (TypeMask.isByteVector(type)) {
generatedConsumers
.append(" DataInputBlobReader<").append(schemaClassName).append("> ")
.append(varName)
.append(" = PipeReader.inputStream(input, ")
.append(constName)
.append(");\n");
} else {
throw new UnsupportedOperationException("unknown value "+type);
}
}
private static void appendProduceMethodField(StringBuilder argsTemp, StringBuilder bodyTemp, String varName, String constName, int token) {
int type = TokenBuilder.extractType(token);
if (TypeMask.isInt(type)) {
argsTemp.append("int ").append(varName).append(", ");
bodyTemp.append(" PipeWriter.writeInt(output,").append(constName).append(", ").append(varName).append(");\n");
} else if (TypeMask.isLong(type)) {
argsTemp.append("long ").append(varName).append(", ");
bodyTemp.append(" PipeWriter.writeLong(output,").append(constName).append(", ").append(varName).append(");\n");
} else if (TypeMask.isDecimal(type)) {
argsTemp.append("int ").append(varName).append(", ");
argsTemp.append("long ").append(varName).append(", ");
bodyTemp.append(" PipeWriter.writeDecimal(output,").append(constName).append(", ").append(varName).append("e, ").append(varName).append("m);\n");
} else if (TypeMask.isText(type)) {
argsTemp.append("CharSequence ").append(varName).append(", ");
bodyTemp.append(" PipeWriter.writeUTF8(output,").append(constName).append(", ").append(varName).append(");\n");
} else if (TypeMask.isByteVector(type)) {
argsTemp.append("byte[] ").append(varName).append("Backing, ");
argsTemp.append("int ").append(varName).append("Position, ");
argsTemp.append("int ").append(varName).append("Length, ");
bodyTemp.append(" PipeWriter.writeBytes(output,").append(constName).append(", ")
.append(varName).append("Backing, ").append(varName).append("Position, ").append(varName).append("Length")
.append(");\n");
} else {
throw new UnsupportedOperationException("unknown value "+type);
}
}
private static void appendConsumeMethodBegin(StringBuilder generatedConsumers, String methodName, String schemaClassName ) {
generatedConsumers.append("public static void consume").append(methodName).append("(Pipe<").append(schemaClassName).append("> input) {\n");
}
private static void appendConsumeMethodEnd(StringBuilder generatedConsumers) {
generatedConsumers.append("}\n");
}
private static void appendProduceMethodEnd(StringBuilder argsTemp, StringBuilder bodyTemp, StringBuilder generatedProducers,
String methodName, String messageConst, String schemaClassName) {
if (argsTemp.length()>0) {//remove last comma and space if found
argsTemp.setLength(argsTemp.length()-2);
}
generatedProducers.append("public static void publish").append(methodName).append("(Pipe<").append(schemaClassName).append("> output");
if (argsTemp.length()>0) {
generatedProducers.append(", ").append(argsTemp);
}
generatedProducers.append(") {\n");
generatedProducers.append(" PipeWriter.presumeWriteFragment(output, ").append(messageConst).append(");\n");
generatedProducers.append(bodyTemp);
generatedProducers.append(" PipeWriter.publishWrites(output);\n");
generatedProducers.append("}\n");
}
private static void appendSwitchCase(StringBuilder result, String messageConstantName, String name) {
result.append(" case ").append(messageConstantName).append(":\n");
result.append(" consume"+name+"(input);\n");
result.append(" break;\n");
}
private static void appendAssignmentCode(StringBuilder result, String constantName, int value, String comment) {
result.append("public static final int ").append(constantName).append(" = ");
Appendables.appendFixedHexDigits(result, value, 32).append("; //").append(comment).append("\n");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy