Search in sources :

Example 51 with CannotCompileException

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());
    }
}
Also used : CtField(javassist.CtField) NotFoundException(javassist.NotFoundException) CannotCompileException(javassist.CannotCompileException)

Example 52 with CannotCompileException

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();
    }
}
Also used : CodeConverter(javassist.CodeConverter) CtMethod(javassist.CtMethod) Method(java.lang.reflect.Method) CannotCompileException(javassist.CannotCompileException) NotFoundException(javassist.NotFoundException) CtConstructor(javassist.CtConstructor) CtClass(javassist.CtClass) CtField(javassist.CtField) CtMethod(javassist.CtMethod)

Example 53 with CannotCompileException

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();
}
Also used : CtClass(javassist.CtClass) PrintStream(java.io.PrintStream) NotFoundException(javassist.NotFoundException) CannotCompileException(javassist.CannotCompileException)

Example 54 with CannotCompileException

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();
}
Also used : NotFoundException(javassist.NotFoundException) CannotCompileException(javassist.CannotCompileException)

Example 55 with CannotCompileException

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);
    }
}
Also used : ArrayList(java.util.ArrayList) BasicEntityRecord(org.motechproject.mds.web.domain.BasicEntityRecord) CannotCompileException(javassist.CannotCompileException) MotechDataService(org.motechproject.mds.service.MotechDataService) Predicate(java.util.function.Predicate) EntityDto(org.motechproject.mds.dto.EntityDto) ArrayList(java.util.ArrayList) List(java.util.List) Records(org.motechproject.mds.web.domain.Records) FieldDto(org.motechproject.mds.dto.FieldDto) FieldNotFoundException(org.motechproject.mds.exception.field.FieldNotFoundException) ObjectReadException(org.motechproject.mds.exception.object.ObjectReadException) InvocationTargetException(java.lang.reflect.InvocationTargetException) EntityRecord(org.motechproject.mds.web.domain.EntityRecord) BasicEntityRecord(org.motechproject.mds.web.domain.BasicEntityRecord) ObjectNotFoundException(org.motechproject.mds.exception.object.ObjectNotFoundException) Collection(java.util.Collection)

Aggregations

CannotCompileException (javassist.CannotCompileException)65 CtClass (javassist.CtClass)45 NotFoundException (javassist.NotFoundException)42 CtMethod (javassist.CtMethod)30 IOException (java.io.IOException)22 ClassPool (javassist.ClassPool)22 CtField (javassist.CtField)15 CtConstructor (javassist.CtConstructor)10 FileNotFoundException (java.io.FileNotFoundException)8 File (java.io.File)6 Method (java.lang.reflect.Method)5 ArrayList (java.util.ArrayList)5 EnhancementException (org.hibernate.bytecode.enhance.spi.EnhancementException)5 FileFilter (java.io.FileFilter)4 BadBytecode (javassist.bytecode.BadBytecode)3 Bytecode (javassist.bytecode.Bytecode)3 CodeAttribute (javassist.bytecode.CodeAttribute)3 CodeIterator (javassist.bytecode.CodeIterator)3 CompileError (javassist.compiler.CompileError)3 Javac (javassist.compiler.Javac)3