2

Assuming the following construct of classes:

A Filereader that finds the matching importer for a file and calls the Importer.import method.

This method calls the abstract method importSpecific that is annotated with REQUIRES_NEW.

From the perspective of the container a local call does not open a new Transaction but from the inheritance perspective, i'm not sure.

Does the importSpecific call in ImporterBase.import create a new transaction or not and why is it like this?

Class FileReader:

@Singleton(name = "FileReader")
public class FileReader extends Traceable {

    /*@Inject
      @Any
      public Instance<Importer> importers;*/

    @EJB
    ExampleImporter importer;

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void listenToFileAvailableEvent(@Observes FileAvailable event) throws InterruptedException {        
        for (final String filename : event.getFilenames()) {            
            readFile(filename);
        }
    }

    public void readFile(String filenameWithPath) {
        //[...]-> Extract FileMetadata and find correct importer
        importer.import(dateiMeta);
    }
}

Interface Importer:

@Local
public interface Importer {
    void import(FileMetaData dateiMeta) throws Exception;
    void importSpecific(FileMetaData dateiMeta) throws Exception;
}

Class ImporterBase:

public abstract class ImporterBase implements Importer {
   @Resource
   private SessionContext ctx;

   @Override
   public void import(FileMetaData dateiMeta) throws Exception {           
       try {           
          ctx.getBusinessObject(Importer.class).importSpecific(dateiMeta);//This causes the error
       } catch (Exception ex) {            
           //[...] Log Error
           throw ex;
       }        
   }

   @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
   public abstract void importSpecific(FileMetaData dateiMeta) throws   Exception;

}

Class ExampleImporter:

@Stateless
public class ExampleImporter extends ImporterBase {

    @Override
    public void importSpecific(FileMetaData dateiMeta) throws Exception {
        //Import from file
    }   
}
Jérôme
  • 1,254
  • 2
  • 20
  • 25

1 Answers1

1

No, importSpecific when (and how) is called by your method import never opens a new transaction; because (as you say it) to the container is always a local call...

However, according to this, the annotation @TransactionAttribute can be Inherited... So,

In order to put this kind of configuration to work, you have to:

1) Declare the importSpecific method at your business interface, which is the Importer interface.

2) Denote the Importer interface as your local interface.

3) At your FileReader Singleton, get a proxy of your Importer Bean using @EJB annotation. If you use CDI annotations (like, @Inject), the container will inject CDI Objects and not EJB Proxies! (Be careful with this)

4) Change your ImporterBase code to this:

public abstract class ImporterBase implements Importer {
    @Resource
    private SessionContext ejbCtxt;

    @Override
    public void import(FileMetaData dateiMeta) throws Exception {
        Importer proxy0;    
        try {           
            proxy0 = this.ejbCtxt.getBusinessObject(Importer.class);
            proxy0.importSpecific(dateiMeta);

        } catch (Exception ex) {            
            //[...] Log Error
            throw ex;
        }        
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public abstract void importSpecific(FileMetaData dateiMeta) throws Exception;

}

5) Change your ExampleImporter like this:

@Stateless
@Local(Importer.class)
public class ExampleImporter extends ImportBase {
...
}

If you really need to use CDI Beans instead of EJB proxies at your Singleton Class, you will need to use the @Transactional CDI annotation instead... And your code should be refactored also.

Community
  • 1
  • 1
Carlitos Way
  • 3,279
  • 20
  • 30
  • Thanks for your reply. I tried your solution but i always get a WFLYEJB0051: Could not find view [...]Importer of EJB [...]ExampleImporter. I added the '@Local' annotation on the interface. – Jérôme Feb 08 '17 at 15:06
  • I need to see your code in order to help you more... can you update your question with the modified code? – Carlitos Way Feb 08 '17 at 16:29
  • Sorry for the late answer... I just try your code, but you need to do 2 modifications in order to work: One, annotated the `ExampleImporter` class with: `@Local(Importer.class)` ... Two, at `FileReader` Singleton, declare your EJB as `Importer` not `ExampleImporter` ... Example: `@EJB private Importer importer;` This works.. I just tried it – Carlitos Way Feb 09 '17 at 15:57
  • Thanks for ur reply. I actually have 10 importers so not only the `ExampleImporter`. Therefore i had the `@Inject @Any Instance importers`. How can i manage to get a list or something comparable with direct `@EJB` do i have to write a `@Producer`? A small example would be great! – Jérôme Feb 10 '17 at 09:34
  • Found this [option](http://stackoverflow.com/questions/28380675/find-all-ejbs-implementing-interface) – Jérôme Feb 10 '17 at 10:39