/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.camel.component.jpa;

import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import org.apache.camel.Exchange;
import org.apache.camel.ExtendedExchange;
import org.springframework.orm.jpa.SharedEntityManagerCreator;

/**
 * Helper for JPA.
 */
public final class JpaHelper {

    private JpaHelper() {
    }

    /**
     * Gets or creates an {@link javax.persistence.EntityManager} to use.
     *
     * @param  exchange                 the current exchange, or <tt>null</tt> if no exchange
     * @param  entityManagerFactory     the entity manager factory (mandatory)
     * @param  usePassedInEntityManager whether to use an existing {@link javax.persistence.EntityManager} which has
     *                                  been stored on the exchange in the header with key
     *                                  {@link org.apache.camel.component.jpa.JpaConstants#ENTITY_MANAGER}
     * @param  useSharedEntityManager   whether to use SharedEntityManagerCreator if not already passed in
     * @return                          the entity manager (is never null)
     */
    public static EntityManager getTargetEntityManager(
            Exchange exchange, EntityManagerFactory entityManagerFactory,
            boolean usePassedInEntityManager, boolean useSharedEntityManager, boolean allowRecreate) {
        EntityManager em = null;

        // favor using entity manager provided as a header from the end user
        if (exchange != null && usePassedInEntityManager) {
            em = exchange.getIn().getHeader(JpaConstants.ENTITY_MANAGER, EntityManager.class);
        }

        // then try reuse any entity manager which has been previously created and stored on the exchange
        if (em == null && exchange != null) {
            em = getEntityManagerMap(exchange).get(getKey(entityManagerFactory));
        }

        if (em == null && useSharedEntityManager) {
            em = SharedEntityManagerCreator.createSharedEntityManager(entityManagerFactory);
        }

        if (em == null) {
            em = createEntityManager(exchange, entityManagerFactory);
        }

        if (allowRecreate && em == null || !em.isOpen()) {
            em = createEntityManager(exchange, entityManagerFactory);
        }

        return em;
    }

    private static EntityManager createEntityManager(Exchange exchange, EntityManagerFactory entityManagerFactory) {
        EntityManager em;
        em = entityManagerFactory.createEntityManager();
        if (exchange != null) {
            // we want to reuse the EM so store as property and make sure we close it when done with the exchange
            Map<String, EntityManager> entityManagers = getEntityManagerMap(exchange);
            entityManagers.put(getKey(entityManagerFactory), em);
            exchange.adapt(ExtendedExchange.class).addOnCompletion(new JpaCloseEntityManagerOnCompletion(em));
        }
        return em;
    }

    @SuppressWarnings("unchecked")
    private static Map<String, EntityManager> getEntityManagerMap(Exchange exchange) {
        Map<String, EntityManager> entityManagers = exchange.getProperty(JpaConstants.ENTITY_MANAGER, Map.class);
        if (entityManagers == null) {
            entityManagers = new HashMap<>();
            exchange.setProperty(JpaConstants.ENTITY_MANAGER, entityManagers);
        }
        return entityManagers;
    }

    private static String getKey(EntityManagerFactory entityManagerFactory) {
        return String.valueOf(entityManagerFactory.hashCode());
    }
}

@@ -841,57 +841,8 @@
 a;%0A%0A
-import java.util.HashMap;%0Aimport java.util.Map;%0A%0A
 impo
@@ -2607,36 +2607,16 @@
 m = 
-getEntityManagerMap(
 exchange
 ).ge
@@ -2615,22 +2615,51 @@
 ange
-)
 .get
-(getKey(e
+Property(JpaConstants.ENTITY_MANAGER, E
 ntit
@@ -2666,24 +2666,22 @@
 yManager
-Factory)
+.class
 );%0A     
@@ -2884,386 +2884,43 @@
     
-em =
+//
  create
-EntityManager(exchange, entityManagerFactory);%0A        %7D%0A%0A        if (allowRecreate && em == null %7C%7C !em.isOpen()) %7B%0A            em = createEntityManager(exchange, entityManagerFactory);%0A        %7D%0A%0A        return em;%0A    %7D%0A%0A    private static EntityManager createEntityManager(Exchange exchange, EntityManagerFactory entityManagerFactory) %7B%0A        EntityManager em;%0A
+ a new entity manager%0A    
     
@@ -2972,32 +2972,36 @@
 ager();%0A        
+    
 if (exchange != 
@@ -3000,32 +3000,36 @@
 ange != null) %7B%0A
+    
             // w
@@ -3142,149 +3142,71 @@
     
-Map%3CString, EntityManager%3E entityManagers = getEntityManagerMap(exchange);%0A            entityManagers.put(getKey(entityManagerFactory)
+    exchange.setProperty(JpaConstants.ENTITY_MANAGER
 , em);%0A
+    
     
@@ -3312,32 +3312,36 @@
 n(em));%0A        
+    
 %7D%0A        return
@@ -3338,259 +3338,171 @@
     
-return em;%0A    %7D%0A%0A    @SuppressWarnings(%22unchecked%22)%0A    private static Map%3CString, EntityManager%3E getE
+%7D%0A%0A        if (allowRecreate && em == null %7C%7C !em.isOpen()) %7B%0A            // create a new e
 ntity
-M
+ m
 anager
-Map(Exchange exchange) %7B%0A        Map%3CString, EntityManager%3E entityManagers = exchange.getProperty(JpaConstants.ENTITY_MANAGER, Map.class
+%0A            em = entityManagerFactory.createEntityManager(
 );%0A 
@@ -3512,28 +3512,26 @@
     
+    
 if (e
-ntityM
+xch
 an
-a
 ge
-rs =
+ !
 = nu
@@ -3552,42 +3552,118 @@
     
-entityManagers = new HashMap%3C%3E();%0A
+    // we want to reuse the EM so store as property and make sure we close it when done with the exchange%0A    
     
@@ -3721,29 +3721,17 @@
 NAGER, e
-ntityManagers
+m
 );%0A     
@@ -3733,26 +3733,24 @@
         
-%7D%0A
         
 return e
@@ -3745,184 +3745,155 @@
     
-return entityM
+exchange.adapt(ExtendedExch
 an
-a
 ge
-rs;%0A    %7D%0A%0A    private static String getKey(EntityManagerFactory entityManagerFactory) %7B%0A        return String.valueOf(entityManagerFactory.hashCode())
+.class).addOnCompletion(new JpaCloseEntityManagerOnCompletion(em));%0A            %7D%0A        %7D%0A%0A        return em
 ;%0A    %7D%0A
 %7D%0A
@@ -3890,10 +3890,11 @@
 ;%0A    %7D%0A
+%0A
 %7D%0A

Revert "CAMEL-16470 - fix for reuse EntityManager"