/*
* Copyright (c) 2014 the original author or authors
*
* Licensed 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 io.werval.modules.jpa;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import io.werval.api.exceptions.WervalException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* JPA Context.
*
* That is the object the plugin adds to the Context's MetaData when an interaction Context exist,
* as a ThreadLocal otherwise.
*/
public class JPAContext
{
private static final Logger LOG = LoggerFactory.getLogger( JPAContext.class );
/* package */ static final String METADATA_CONTEXT_KEY = JPAContext.class.getName();
private final Map<String, EntityManager> ems = new HashMap<>( 5 );
public Map<String, EntityManager> entityManagers()
{
return ems;
}
/* package */ void closeFailFast()
{
Set<String> puNames = ems.keySet();
for( String persistenceUnitName : puNames )
{
close( ems.get( persistenceUnitName ), persistenceUnitName );
puNames.remove( persistenceUnitName );
}
}
/* package */ void closeFailSafe()
{
List<Exception> errors = new ArrayList<>();
Set<String> puNames = ems.keySet();
for( String persistenceUnitName : puNames )
{
try
{
close( ems.get( persistenceUnitName ), persistenceUnitName );
}
catch( Exception ex )
{
errors.add( ex );
}
finally
{
puNames.remove( persistenceUnitName );
}
}
if( !errors.isEmpty() )
{
WervalException ex = new WervalException( "Errors occured while closing all EntityManagers" );
errors.forEach( err -> ex.addSuppressed( err ) );
throw ex;
}
}
private void close( EntityManager em, String persistenceUnitName )
{
if( em.isOpen() )
{
try
{
if( em.isJoinedToTransaction() )
{
EntityTransaction tx = em.getTransaction();
if( tx.isActive() )
{
if( !tx.getRollbackOnly() )
{
LOG.warn(
"Dangling transaction detected for '{}' persistence unit, it will be rollbacked! - {}",
persistenceUnitName, tx
);
}
try
{
tx.rollback();
}
catch( Exception ex )
{
LOG.error( "Error rollbacking dangling transaction: {}", ex.getMessage(), ex );
}
}
}
}
finally
{
em.close();
}
}
}
}