1 2 3 Previous Next 35 Replies Latest reply on Dec 11, 2012 1:52 AM by nickarls Go to original post
      • 30. Re: How do you kill off a completed thread?
        sfcoy

        @TransactionAttribute only works on business methods that are invoked via proxy. In other words the method must be invoked on a method of a business view of a session bean.

         

        Therefore, you can either factor the batch processing code into a separate Stateless Session Bean or invoke yourself through javax.ejb.SessionContex#getBusinessObject(java.lang.Class), where you inject the SessionContext with @Resource:

         

        {code:java}

            ...

         

            @Resource

            private SessionContext sessionContext;

         

            ...

         

            private void ripCustomers() {

                this.logger.info(">>>ripCustomers");

                ... Nasty JDBC code to read some data into a Entity (unpersisited and sent into next call in batch mode)

                CustomerHarvestFromXXXService self = sessionContext.getBusinessObject(CustomerHarvestFromXXXService.class);

                self.processXXXXXCustomerBatch(customersFromXXXInBatch);

                ...

                this.logger.info("<<<ripCustomers");

            }

         

            ...


            @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)

             public void processXXXXCustomerBatch(Collection<SalesPoint> customersFromXXXInBatch) {

                  ...

             }

        {code}

         

        You might be tempted to make each call to processXXXXCustomerBatch @Asynchronous as well, but your database might not be very happy with that...

        • 31. Re: How do you kill off a completed thread?
          tony.herstell1

          Guys I am trying to follow the post.

           

          You say the Bean has to be proxied; on the call that is Async if I understand correctly.

           

          So, I need move the code that needs to be Asynch to a new bean (or pull some code out to the calling bean) such that the "entry" call into the bean is the one that has @Asynchronous on it.

           

          Ill give that a whirl.

          • 32. Re: How do you kill off a completed thread?
            tony.herstell1

            And reading it again; you actually say its the @TransactionAttribute that needs to be proxied (and be the entry method).

            DOH!

             

            So the Aynch method can be living inside the bean still; and be called locally to the bean.

            • 33. Re: How do you kill off a completed thread?
              nickarls

              I actually never used Stephens trick (it looks handy) but the trick is that the @TransactionAttribute is a tip for the EJB container on how to wire up the interceptors for the proxy and those interceptors are only executed if the proxy method is called. That proxy method is called only when the call comes from the outside (e.g. call to an injected proxy or manual execution like the example S.C. mentions)

              • 34. Re: How do you kill off a completed thread?
                tony.herstell1

                Refactored (hopefully as you described):

                 

                Controller is called (from a button click but will be a timer eventually)

                            

                public void getCustomers() {
                        this.logger.info(">>>getCustomers");
                        if ((this.future == null) || this.future.isDone()) {
                            this.future = this.customerHarvestFromXXXService.run();
                            this.postGlobalMessage("request_to_process_accepted", FacesMessage.SEVERITY_INFO);
                        } else {
                            this.postGlobalMessage("still_processing", FacesMessage.SEVERITY_INFO);
                        }
                        this.logger.info("<<<getCustomers");
                    }
                

                 

                this calls a NEW Injected bean which has a "business" routine (has to be public!)

                 

                    /**
                     * This method is asynchronous and does not need a TXN as we call other routines that can take time.
                     * The called routine, that does the batches, does need a new transaction for each batch.
                     * @see https://community.jboss.org/message/782528#782528
                     */
                    @Asynchronous
                    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
                    public Future<String> run() {
                        String status;
                        this.logger.info(">>>Run");
                        logger.info("Transaction: "+ ut);
                        customerHarvestFromXXXXBatchProcessor.clearErrors();
                        try {    
                            logger.info("Transaction: "+ ut);
                            boolean logEachCustomer = false;
                            Collection<SalesPoint> customersFromXXX = new ArrayList<SalesPoint>();
                
                            Connection con = null;
                            String url = xxxx:";
                            String dbName = "xxx";
                            String driver = "oracle.jdbc.OracleDriver";
                            String userName = "xxxxREADONLYxxxx";
                            String password = "xxxxxx";
                            String query = ...
                            ... Some gnarly sql
                             ... set up a local objects and put in batches
                             ... customerHarvestFromXXXXBatchProcessor.processXXXCustomerBatch(customersFromXXXInBatch);
                             ...
                      return new AsyncResult<String>(status);
                    }
                

                 

                 

                this calls a NEW Injected bean which has a "business" routine (has to be public!)

                 

                    // Lets start a new (very clean) transaction for handling each customer batch as we need to store the new "real" customer object
                    // against the Territory (Don't want to do all the customers in 1 Trans as timeout will kick in)
                    // @see https://community.jboss.org/message/782528#782528
                    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
                    public void processXXXXCustomerBatch(Collection<SalesPoint> customersFromXXXXInBatch) {
                        
                        logger.info("Transaction: "+ ut);
                        
                        this.logger.info("Processing Batch...");
                
                        ...
                        this.em.persist(customer);
                        this.em.flush();
                        ...
                

                 

                 

                I believe I have done the refactoring you suggested.

                The "entry" routines to each bean are the ones that get annotated as they need to be Proxied.

                 

                Hope it does what I am hoping for.

                (As I said; a quickstarter for this would be useful as not much of this is documented and full of gotchas)

                      

                A nice "feature" of this new setup is that I can call the getErrors method in the "batch" class and can see them come in instead of having to handle the concurrency Exception that I used to get...

                 

                       try {
                            this.mappingErrorsFromImport = customerHarvestFromXXXBatchProcessor.getErrors(); // TODO Make a copy
                        } catch (EJBTransactionRolledbackException eJBTRE) {
                            this.postGlobalMessage("still_processing", FacesMessage.SEVERITY_INFO);
                            destinationToReturn = "pretty:home";
                        }
                
                • 35. Re: How do you kill off a completed thread?
                  nickarls

                  Well there are a few EJB 3.1 books out there that might be helpful

                   

                  http://www.amazon.com/dp/0596158025/

                  http://www.packtpub.com/ejb-3-1-cookbook/book

                  1 2 3 Previous Next