Ananth created APEXCORE-452:
-------------------------------

             Summary: Class Not found errors encountered for Apps with JSR 303 
annotations
                 Key: APEXCORE-452
                 URL: https://issues.apache.org/jira/browse/APEXCORE-452
             Project: Apache Apex Core
          Issue Type: Bug
    Affects Versions: 3.3.0
         Environment: Cent OS 6.6 + CDH 5.7 + Apex 3.3.0 + malhar 3.3.1 
            Reporter: Ananth


Apps that have Validation annotations seem to be being evaluated by the bval 
jar inside the engine instead of the application supplied validators. This is 
causing ClassNotFoundErrors. 

An App that is using Apex + Spring 4.1.9 + Spring Data + Hibernate + JPA was 
used to reproduce this issue

There are annotations in the Spring JPA layer that is causing the launching of 
an app to crash consistently. 

The workaround seems to be adding jars that do not interfere with the Apex 
engine jars. In the application above, javax.persistence.Persistence was the 
cause for a ClassNotFoundError. Adding a jar like javaee-api-7.0 jar made this 
class available for the app to be launched properly but cause aspects like 
metrics+ logging completely lost from within the engine. The javaee-api jar was 
interfering with the interface definitions of the Apex Engine libraries. The 
workaround that worked was trying to push in hibernate-jpa-api jar which also 
provided the missing classes. 

Here is a possible explanation that might be causing this : 

Suspect that there is an issue with the classloader ( note that this is a guess 
only based on observations). The code works fine in a unit test end to end 
using the local mode.

    - This happens only for apps that have other JSR 303 based annotations ( 
Hibernate + Spring + JPA annotations in the code as was my case)
    - Apex engine uses the Apache BVal in spite of other validation jars being 
present in the application jars list
    - In this process, the Apex engine is trying to use its classloader to 
locate the jars that are expected to be part of the current class being loaded 
( import statements) while being launched.
    - At this juncture, it fails with a class not found error/exception. 

The stack trace that was thrown for the hibernate based app was : 

    An error occurred trying to launch the application. Server message: 
java.lang.NoClassDefFoundError: javax/persistence/Persistence at 
org.apache.bval.jsr303.resolver.JPATraversableResolver.isReachable(JPATraversableResolver.java:34)
 at 
org.apache.bval.jsr303.resolver.DefaultTraversableResolver.isReachable(DefaultTraversableResolver.java:60)
 at 
org.apache.bval.jsr303.resolver.CachingTraversableResolver.isReachable(CachingTraversableResolver.java:82)
 at 
org.apache.bval.jsr303.ConstraintValidation.isReachable(ConstraintValidation.java:241)
 at 
org.apache.bval.jsr303.ConstraintValidation.validate(ConstraintValidation.java:166)
 at 
org.apache.bval.jsr303.ConstraintValidation.validate(ConstraintValidation.java:141)
 at 
org.apache.bval.util.ValidationHelper.validateProperty(ValidationHelper.java:233)
 at 
org.apache.bval.util.ValidationHelper.validateBean(ValidationHelper.java:216) 
at 
org.apache.bval.jsr303.ClassValidator.validateBeanNet(ClassValidator.java:393) 
at org.apache.bval.jsr303.ClassValidator.validate(ClassValidator.java:149) at 
com.datatorrent.stram.plan.logical.LogicalPlan.validate(LogicalPlan.java:1672) 
at com.datatorrent.stram.StramClient.<init>(StramClient.java:161) at 
com.datatorrent.stram.client.StramAppLauncher.launchApp(StramAppLauncher.java:509)
 at com.datatorrent.stram.cli.DTCli$LaunchCommand.execute(DTCli.java:2050) at 
com.datatorrent.stram.cli.DTCli.launchAppPackage(DTCli.java:3456) at 
com.datatorrent.stram.cli.DTCli.access$7100(DTCli.java:106) at 
com.datatorrent.stram.cli.DTCli$LaunchCommand.execute(DTCli.java:1895) at 
com.datatorrent.stram.cli.DTCli$3.run(DTCli.java:1449) Fatal error encountered 



It may be noted that the Application client driver class ( That extends the 
streaming application ) loads the application context of Spring from within the 
populateDAG() method. The operator code also injected a few Spring beans. Code 
snippet below : (GlobalConfigRepository and  
AppConfigRepository are Spring Data based repository definitions)


@ApplicationAnnotation  
public class CassandraEventDetailsStreamingApp implements StreamingApplication {

    GlobalConfigRepository globalConfigRepository;

    AppConfigRepository appConfigRepository;


    @Override
    public void populateDAG(DAG dag, Configuration configuration) {
        injectContext();
        EventDetailsIngestionTopicKafkaOperator kafkaOperator = 
getOperatorForEventDetailsStream();
        EventDetailsFormatterOperator formatterOperator = 
getFormatterOperator();
        EventDetailsCassandraOutputoperator cassandraOutputoperator = 
getCassandraWriter();
        dag.addOperator("kafkaIngestor",kafkaOperator);
        dag.addOperator("eventDetailsFormatter",formatterOperator);
        dag.addOperator("eventDetailsCassandraWriter",cassandraOutputoperator);
        dag.addStream("eventsFromAPI", kafkaOperator.eventDetailsAsJSONString, 
formatterOperator.kafkaStreamInput);
        dag.addStream("eventDetailsCassandraWrites", 
formatterOperator.writeToCassandra,
                cassandraOutputoperator.transformedJSON);
    }

    /**
     * Injects all of the required context
     */
    private void injectContext() {
        globalConfigRepository = (GlobalConfigRepository) 
CassandraEventDetailsAppContext.getCassandraEventDetailsAppContext().
                
getIOCContext().getBean(DWHAppBeanNames.GLOBAL_CONFIG_REPOSITORY_BEAN_NAME);
        appConfigRepository = (AppConfigRepository) 
CassandraEventDetailsAppContext.getCassandraEventDetailsAppContext().
                
getIOCContext().getBean(DWHAppBeanNames.APPCONFIG_REPOSITORY_BEAN_NAME);
    }

..... ( Code snipped ) ..........



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to