use of javassist.CannotCompileException in project compss by bsc-wdc.
the class ITAppEditor method edit.
/**
* Check the access to fields of objects
*/
@Override
public void edit(FieldAccess fa) throws CannotCompileException {
CtField field = null;
try {
field = fa.getField();
if (Modifier.isStatic(field.getModifiers())) {
return;
}
} catch (NotFoundException e) {
throw new CannotCompileException(e);
}
String fieldName = field.getName();
if (DEBUG) {
LOGGER.debug("Keeping track of access to field " + fieldName + " of class " + field.getDeclaringClass().getName());
}
boolean isWriter = fa.isWriter();
// First check the object containing the field
StringBuilder toInclude = new StringBuilder();
toInclude.append(itORVar).append(NEW_OBJECT_ACCESS).append("$0,").append(isWriter).append(");");
// Execute the access on the internal object
String internalObject = itORVar + GET_INTERNAL_OBJECT + "$0)";
String objectClass = fa.getClassName();
toInclude.append("if (").append(internalObject).append(" != null) {");
if (isWriter) {
// store a new value in the field
toInclude.append("((").append(objectClass).append(')').append(internalObject).append(").").append(fieldName).append(" = $1;");
toInclude.append("} else { " + PROCEED + "$$); }");
// Serialize the (internal) object locally after the access
toInclude.append(itORVar).append(SERIALIZE_LOCALLY + "$0);");
} else {
// read the field value
// read
toInclude.append("$_ = ((").append(objectClass).append(')').append(internalObject).append(").").append(fieldName).append(';');
toInclude.append("} else { " + PROCEED + "$$); }");
}
fa.replace(toInclude.toString());
if (DEBUG) {
LOGGER.debug("Replaced regular field access by " + toInclude.toString());
}
}
use of javassist.CannotCompileException in project compss by bsc-wdc.
the class ITAppModifier method modify.
/**
* Modify method
*
* @param appName
* @return
* @throws NotFoundException
* @throws CannotCompileException
* @throws ClassNotFoundException
*/
public Class<?> modify(String appName) throws NotFoundException, CannotCompileException, ClassNotFoundException {
Class<?> annotItf = Class.forName(appName + LoaderConstants.ITF_SUFFIX);
// Methods declared in the annotated interface
Method[] remoteMethods = annotItf.getMethods();
/*
* Use the application editor to include the COMPSs API calls on the application code
*/
CLASS_POOL.importPackage(LoaderConstants.PACKAGE_COMPSS_ROOT);
CLASS_POOL.importPackage(LoaderConstants.PACKAGE_COMPSS_API);
CLASS_POOL.importPackage(LoaderConstants.PACKAGE_COMPSS_API_IMPL);
CLASS_POOL.importPackage(LoaderConstants.PACKAGE_COMPSS_LOADER);
CLASS_POOL.importPackage(LoaderConstants.PACKAGE_COMPSS_LOADER_TOTAL);
CtClass appClass = CLASS_POOL.get(appName);
CtClass itApiClass = CLASS_POOL.get(LoaderConstants.CLASS_COMPSSRUNTIME_API);
CtClass itSRClass = CLASS_POOL.get(LoaderConstants.CLASS_STREAM_REGISTRY);
CtClass itORClass = CLASS_POOL.get(LoaderConstants.CLASS_OBJECT_REGISTRY);
CtClass appIdClass = CLASS_POOL.get(LoaderConstants.CLASS_APP_ID);
String varName = LoaderUtils.randomName(5, LoaderConstants.STR_COMPSS_PREFIX);
String itApiVar = varName + LoaderConstants.STR_COMPSS_API;
String itSRVar = varName + LoaderConstants.STR_COMPSS_STREAM_REGISTRY;
String itORVar = varName + LoaderConstants.STR_COMPSS_OBJECT_REGISTRY;
String itAppIdVar = varName + LoaderConstants.STR_COMPSS_APP_ID;
CtField itApiField = new CtField(itApiClass, itApiVar, appClass);
CtField itSRField = new CtField(itSRClass, itSRVar, appClass);
CtField itORField = new CtField(itORClass, itORVar, appClass);
CtField appIdField = new CtField(appIdClass, itAppIdVar, appClass);
itApiField.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
itSRField.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
itORField.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
appIdField.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
appClass.addField(itApiField);
appClass.addField(itSRField);
appClass.addField(itORField);
appClass.addField(appIdField);
/*
* Create a static constructor to initialize the runtime Create a shutdown hook to stop the runtime before the
* JVM ends
*/
manageStartAndStop(appClass, itApiVar, itSRVar, itORVar);
/*
* Create IT App Editor
*/
// Candidates to be instrumented if they are not
CtMethod[] instrCandidates = appClass.getDeclaredMethods();
// remote
ITAppEditor itAppEditor = new ITAppEditor(remoteMethods, instrCandidates, itApiVar, itSRVar, itORVar, itAppIdVar, appClass);
// itAppEditor.setAppId(itAppIdVar);
// itAppEditor.setAppClass(appClass);
/*
* Create Code Converter
*/
CodeConverter converter = new CodeConverter();
CtClass arrayWatcher = CLASS_POOL.get(LoaderConstants.CLASS_ARRAY_ACCESS_WATCHER);
CodeConverter.DefaultArrayAccessReplacementMethodNames names = new CodeConverter.DefaultArrayAccessReplacementMethodNames();
converter.replaceArrayAccess(arrayWatcher, (CodeConverter.ArrayAccessReplacementMethodNames) names);
/*
* Find the methods declared in the application class that will be instrumented - Main - Constructors - Methods
* that are not in the remote list
*/
if (DEBUG) {
LOGGER.debug("Flags: ToFile: " + WRITE_TO_FILE + " isWS: " + IS_WS_CLASS + " isMainClass: " + IS_MAIN_CLASS);
}
for (CtMethod m : instrCandidates) {
if (LoaderUtils.checkRemote(m, remoteMethods) == null) {
// Not a remote method, we must instrument it
if (DEBUG) {
LOGGER.debug("Instrumenting method " + m.getName());
}
StringBuilder toInsertBefore = new StringBuilder();
StringBuilder toInsertAfter = new StringBuilder();
/*
* Add local variable to method representing the execution id, which will be the current thread id. Used
* for Services, to handle multiple service executions simultaneously with a single runtime For normal
* applications, there will be only one execution id.
*/
m.addLocalVariable(itAppIdVar, appIdClass);
toInsertBefore.append(itAppIdVar).append(" = new Long(Thread.currentThread().getId());");
// TODO remove old code:
// boolean isMainProgram = writeToFile ? LoaderUtils.isOrchestration(m) : LoaderUtils.isMainMethod(m);
boolean isMainProgram = LoaderUtils.isMainMethod(m);
boolean isOrchestration = LoaderUtils.isOrchestration(m);
if (isMainProgram && IS_MAIN_CLASS) {
LOGGER.debug("Inserting calls at the beginning and at the end of main");
if (IS_WS_CLASS) {
//
LOGGER.debug("Inserting calls noMoreTasks at the end of main");
toInsertAfter.insert(0, itApiVar + ".noMoreTasks(" + itAppIdVar + ", true);");
m.insertBefore(toInsertBefore.toString());
// executed only if Orchestration finishes properly
m.insertAfter(toInsertAfter.toString());
} else {
// Main program
LOGGER.debug("Inserting calls noMoreTasks and stopIT at the end of main");
// Set global variable for main as well, will be used in code inserted after to be run no matter
// what
toInsertBefore.append(appName).append('.').append(itAppIdVar).append(" = new Long(Thread.currentThread().getId());");
// toInsertAfter.append("System.exit(0);");
toInsertAfter.insert(0, itApiVar + ".stopIT(true);");
toInsertAfter.insert(0, itApiVar + ".noMoreTasks(" + appName + '.' + itAppIdVar + ", true);");
m.insertBefore(toInsertBefore.toString());
// executed no matter what
m.insertAfter(toInsertAfter.toString(), true);
}
/*
* Instrumenting first the array accesses makes each array access become a call to a black box
* method of class ArrayAccessWatcher, whose parameters include the array. For the second round of
* instrumentation, the synchronization by transition to black box automatically synchronizes the
* arrays accessed. TODO: Change the order of instrumentation, so that we have more control about
* the synchronization, and we can distinguish between a write access and a read access (now it's
* read/write access by default, because it goes into the black box).
*/
m.instrument(converter);
m.instrument(itAppEditor);
} else if (isOrchestration) {
if (IS_WS_CLASS) {
//
LOGGER.debug("Inserting calls noMoreTasks and stopIT at the end of orchestration");
toInsertAfter.insert(0, itApiVar + ".noMoreTasks(" + itAppIdVar + ", true);");
m.insertBefore(toInsertBefore.toString());
// executed only if Orchestration finishes properly
m.insertAfter(toInsertAfter.toString());
} else {
LOGGER.debug("Inserting only before at the beginning of an orchestration");
m.insertBefore(toInsertBefore.toString());
// TODO remove old code m.insertAfter(toInsertAfter.toString());
// executed only if Orchestration finishes properly
}
m.instrument(converter);
m.instrument(itAppEditor);
} else {
LOGGER.debug("Inserting only before");
m.insertBefore(toInsertBefore.toString());
if (IS_WS_CLASS) {
// non-OE operations
if (Modifier.isPrivate(m.getModifiers())) {
m.instrument(converter);
m.instrument(itAppEditor);
}
} else {
// For an application class, instrument all non-remote methods
m.instrument(converter);
m.instrument(itAppEditor);
}
}
}
}
// Instrument constructors
for (CtConstructor c : appClass.getDeclaredConstructors()) {
if (DEBUG) {
LOGGER.debug("Instrumenting constructor " + c.getLongName());
}
c.instrument(converter);
c.instrument(itAppEditor);
}
if (WRITE_TO_FILE) {
// Write the modified class to disk
try {
appClass.writeFile();
} catch (Exception e) {
ErrorManager.fatal("Error writing the instrumented class file");
}
return null;
} else {
/*
* Load the modified class into memory and return it. Generally, once a class is loaded into memory no
* further modifications can be performed on it.
*/
return appClass.toClass();
}
}
use of javassist.CannotCompileException in project compss by bsc-wdc.
the class ITAppEditor method replaceBlackBox.
/**
* Replaces the blackBox calls
*
* @return
*/
private String replaceBlackBox(String methodName, String className, CtMethod method) throws CannotCompileException {
if (DEBUG) {
LOGGER.debug("Inspecting method call to black-box method " + methodName + ", looking for objects");
}
StringBuilder modifiedCall = new StringBuilder();
StringBuilder toSerialize = new StringBuilder();
// Check if the black-box we're going to is one of the array watch methods
boolean isArrayWatch = method.getDeclaringClass().getName().equals(LoaderConstants.CLASS_ARRAY_ACCESS_WATCHER);
// First check the target object
modifiedCall.append(itORVar).append(NEW_OBJECT_ACCESS + "$0);");
toSerialize.append(itORVar).append(SERIALIZE_LOCALLY + "$0);");
/*
* Now add the call. If the target object of the call is a task object, invoke the method on the internal object
* stored by the runtime. Also check the parameters. We need to control the parameters of non-remote and
* non-instrumented methods (black box), since they represent the border to the code where we can't intercept
* anything. If any of these parameters is an object we kept track of, synchronize
*/
String redirectedCallPars = null;
try {
CtClass[] paramTypes = method.getParameterTypes();
if (paramTypes.length > 0) {
int i = 1;
StringBuilder aux1 = new StringBuilder("new Object[] {");
for (CtClass parType : paramTypes) {
if (i > 1) {
aux1.append(',');
/* aux2.append(','); */
}
String parId = "$" + i;
if (parType.isPrimitive()) {
if (parType.equals(CtClass.booleanType)) {
aux1.append("new Boolean(").append(parId).append(')');
} else if (parType.equals(CtClass.charType)) {
aux1.append("new Character(").append(parId).append(')');
} else if (parType.equals(CtClass.byteType)) {
aux1.append("new Byte(").append(parId).append(')');
} else if (parType.equals(CtClass.shortType)) {
aux1.append("new Short(").append(parId).append(')');
} else if (parType.equals(CtClass.intType)) {
aux1.append("new Integer(").append(parId).append(')');
} else if (parType.equals(CtClass.longType)) {
aux1.append("new Long(").append(parId).append(')');
} else if (parType.equals(CtClass.floatType)) {
aux1.append("new Float(").append(parId).append(')');
} else {
// if (parType.equals(CtClass.doubleType))
aux1.append("new Double(").append(parId).append(')');
}
} else if (parType.getName().equals(String.class.getName())) {
// This is a string
if (DEBUG) {
LOGGER.debug("Parameter " + i + " of black-box method " + methodName + " is an String, adding File/object access");
}
if (isArrayWatch && i == 3) {
// Prevent from synchronizing task return objects to be stored in an array position
aux1.append(parId);
} else {
String calledClass = className;
if (calledClass.equals(PrintStream.class.getName()) || calledClass.equals(StringBuilder.class.getName())) {
// If the call is inside a PrintStream or StringBuilder, only synchronize objects files
// already has the name
String internalObject = itORVar + GET_INTERNAL_OBJECT + parId + ')';
modifiedCall.insert(0, itORVar + NEW_OBJECT_ACCESS + parId + ");");
aux1.append(internalObject).append(" == null ? ").append(parId).append(" : ").append("(" + parType.getName() + ")").append(internalObject);
toSerialize.append(itORVar).append(SERIALIZE_LOCALLY).append(parId).append(");");
} else {
String internalObject = itORVar + GET_INTERNAL_OBJECT + parId + ')';
String taskFile = itSRVar + IS_TASK_FILE + parId + ")";
String apiOpenFile = itApiVar + OPEN_FILE + parId + ", " + DATA_DIRECTION + ".INOUT)";
modifiedCall.insert(0, itORVar + NEW_OBJECT_ACCESS + parId + ");");
// Adding check of task files
aux1.append(taskFile).append(" ? ").append(apiOpenFile).append(" : ").append(internalObject).append(" == null ? ").append(parId).append(" : ").append("(" + parType.getName() + ")").append(internalObject);
toSerialize.append(itORVar).append(SERIALIZE_LOCALLY).append(parId).append(");");
}
}
} else {
// Object (also array)
if (DEBUG) {
LOGGER.debug("Parameter " + i + " of black-box method " + methodName + " is an object, adding access");
}
if (isArrayWatch && i == 3) {
// Prevent from synchronizing task return objects to be stored in an array position
aux1.append(parId);
} else {
String internalObject = itORVar + GET_INTERNAL_OBJECT + parId + ')';
modifiedCall.insert(0, itORVar + NEW_OBJECT_ACCESS + parId + ");");
aux1.append(internalObject).append(" == null ? ").append(parId).append(" : ").append("(" + parType.getName() + ")").append(internalObject);
toSerialize.append(itORVar).append(SERIALIZE_LOCALLY).append(parId).append(");");
}
}
i++;
}
aux1.append("}");
redirectedCallPars = aux1.toString();
}
} catch (NotFoundException e) {
throw new CannotCompileException(e);
}
String internalObject = itORVar + GET_INTERNAL_OBJECT + "$0)";
modifiedCall.append("if (").append(internalObject).append(" != null) {").append("$_ = ($r)" + RUN_METHOD_ON_OBJECT).append(internalObject).append(",$class,\"").append(methodName).append("\",").append(redirectedCallPars).append(",$sig);").append("}else { $_ = ($r)" + RUN_METHOD_ON_OBJECT + "$0,$class,\"").append(methodName).append("\",").append(redirectedCallPars).append(",$sig); }");
// Serialize the (internal) objects locally after the call
modifiedCall.append(toSerialize);
// Return all the modified call
return modifiedCall.toString();
}
use of javassist.CannotCompileException in project compss by bsc-wdc.
the class ITAppEditor method replaceAPICall.
/**
* Replaces the API calls
*
* @return
* @throws NotFoundException
*/
private String replaceAPICall(String methodName, CtMethod method) throws CannotCompileException {
boolean isVoid = false;
boolean hasArgs = false;
try {
Class<?> retType = method.getReturnType().getClass();
isVoid = retType.equals(void.class);
hasArgs = (method.getParameterTypes().length != 0);
} catch (NotFoundException e) {
throw new CannotCompileException(e);
}
// Add the COMPSsRuntime API Call with the given appId ALWAYS as FIRST parameter
// Something like: itApiVar.methodName(itAppIdVar, $$);
StringBuilder apiCall = new StringBuilder("");
if (isVoid) {
apiCall.append("$_ = ").append(itApiVar);
} else {
apiCall.append(itApiVar);
}
apiCall.append(".").append(methodName).append("(").append(itAppIdVar);
if (hasArgs) {
apiCall.append(", $$");
} else {
// Nothing to add
}
apiCall.append(");");
return apiCall.toString();
}
use of javassist.CannotCompileException in project motech by motech.
the class InstanceServiceImpl method getRelatedFieldValue.
@Override
public Records<BasicEntityRecord> getRelatedFieldValue(Long entityId, Long instanceId, String fieldName, RelationshipsUpdate filter, QueryParams queryParams) {
try {
// first get the entity
EntityDto entity = getEntity(entityId);
validateCredentials(entity);
List<FieldDto> fields = getEntityFields(entityId);
String entityName = entity.getName();
MotechDataService service = getServiceForEntity(entity);
// then the related entity
FieldDto relatedField = findFieldByName(fields, fieldName);
if (relatedField == null) {
throw new FieldNotFoundException(entity.getClassName(), fieldName);
}
String relatedClass = relatedField.getMetadataValue(Constants.MetadataKeys.RELATED_CLASS);
if (StringUtils.isBlank(relatedClass)) {
throw new IllegalArgumentException("Field " + fieldName + " in entity " + entity.getClassName() + " is not a related field");
}
// these will be used for building the records
EntityDto relatedEntity = getEntity(relatedClass);
List<FieldDto> relatedFields = getEntityFields(relatedEntity.getId());
MotechDataService relatedDataService = getServiceForEntity(relatedEntity);
Collection relatedAsColl = new ArrayList<>();
// If the relationship already exists, fetch instances and use correct type
if (instanceId != null) {
// get the instance of the original entity
Object instance = service.findById(instanceId);
if (instance == null) {
throw new ObjectNotFoundException(entityName, instanceId);
}
// the value of the related field
relatedAsColl = TypeHelper.asCollection(PropertyUtil.getProperty(instance, fieldName));
}
relatedAsColl.addAll(relatedDataService.findByIds(filter.getAddedIds()));
List<Long> updatedInstancesIds = new ArrayList<>();
for (EntityRecord record : filter.getAddedNewRecords()) {
Integer id = (Integer) record.getFieldByName(Constants.Util.ID_FIELD_NAME).getValue();
if (id != null && id > 0) {
updatedInstancesIds.add(id.longValue());
}
}
relatedAsColl.removeIf(new Predicate() {
@Override
public boolean test(Object o) {
Long objectId = (Long) PropertyUtil.safeGetProperty(o, Constants.Util.ID_FIELD_NAME);
return filter.getRemovedIds().contains(objectId) || updatedInstancesIds.contains(objectId);
}
});
for (EntityRecord record : filter.getAddedNewRecords()) {
relatedAsColl.add(newInstanceFromEntityRecord(getEntityClass(relatedEntity), relatedFields, record.getFields(), relatedDataService));
}
// apply pagination ordering (currently in memory)
List filtered = InMemoryQueryFilter.filter(relatedAsColl, queryParams);
// convert the instance to a grid-friendly form
List<BasicEntityRecord> entityRecords = instancesToBasicRecords(filtered, relatedEntity, relatedFields, relatedDataService, EntityType.STANDARD);
// counts for the grid
int recordCount = relatedAsColl.size();
int rowCount = (int) Math.ceil(recordCount / (double) queryParams.getPageSize());
// package as records
return new Records<>(queryParams.getPage(), rowCount, recordCount, entityRecords);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | IllegalArgumentException | ClassNotFoundException | CannotCompileException | InstantiationException | NoSuchFieldException e) {
throw new ObjectReadException(entityId, e);
}
}
Aggregations