<commit_before>/* DO NOT EDIT: File is auto-generated */
package <%= to_package(data_module.sync.qualified_sync_context_impl_name) %>;

/**

 Base class to extend to customize the synchronization process.

<code>
<pre>
@ApplicationScoped
@Transactional
@Typed( <%= data_module.service_by_name(:SynchronizationContext).ejb.qualified_service_name %>.class )
public class <%= data_module.sync.sync_context_impl_name.gsub(/^Abstract/,'') %>
  extends <%= data_module.sync.sync_context_impl_name %>
{
<%
data_module.repository.data_module_by_name(data_module.repository.sync.master_data_module).sync.entities_to_synchronize.collect do |e|
  e.sync.references_requiring_manual_sync.each do |a|
-%>
  @Override
  protected void remove<%= a.entity.qualified_name.gsub('.','') %>RelatedTo<%= a.referenced_entity.qualified_name.gsub('.','') %>Via<%= a.name %>(...) {...}
<%
  end
end
-%>
}
</pre>
</code>
 */
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings( { "NP_LOAD_OF_KNOWN_NULL_VALUE", "DLS_DEAD_LOCAL_STORE", "CLI_CONSTANT_LIST_INDEX", "ACEM_ABSTRACT_CLASS_EMPTY_METHODS" } )
@java.lang.SuppressWarnings( { "unchecked", "UnusedParameters", "PMD.AddEmptyString", "PMD.UnusedLocalVariable", "PMD.LocalVariableNamingConventions" } )
public abstract class <%= data_module.sync.sync_context_impl_name %>
  implements <%= data_module.service_by_name(:SynchronizationContext).ejb.qualified_service_name %>
{
  private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger( <%= data_module.sync.sync_context_impl_name %>.class.getName() );

  @javax.persistence.PersistenceContext( unitName = <%= data_module.repository.jpa.qualified_unit_descriptor_name %>.NAME )
  private javax.persistence.EntityManager _entityManager;
<% data_module.sync.entities_to_synchronize.each do |entity| -%>
  @javax.inject.Inject
  private <%= entity.dao.jpa.qualified_dao_service_name %> _<%= Reality::Naming.camelize(entity.data_module.name) %><%= entity.name %>Repository;
<% end -%>

  /**
   * Hook that can be overriden to perform actions before any sync takes place.
   * Be very careful not to do anything that may cause sync to fail.
   */
  @java.lang.Override
  public void preSync( @javax.annotation.Nonnull final iris.syncrecord.server.service.SynchronizationRecorder recorder )
  {
  }

  /**
   * Hook that can be overriden to perform actions once sync has completed.
   * Be very very careful not to do anything that may cause sync to fail.
   */
  @java.lang.Override
  public void postSync( @javax.annotation.Nonnull final iris.syncrecord.server.service.SynchronizationRecorder recorder )
  {
  }

  @java.lang.Override
  public void syncComplete()
  {
<% if data_module.repository.mssql? -%>
    purgeSyncQueryPlans();
<% end -%>
  }
<% if data_module.repository.mssql? -%>

  private void purgeSyncQueryPlans()
  {
    // Remove query plans from plan cache as they usually long running and
    // unoptimized and thus will dominate the "recent expensive queries list"
    // even through we have no plans to optimize them
    _entityManager.
      createNativeQuery( "EXEC <%= data_module.sql.quoted_schema %>.[spRemoveCachedMasterQueryPlans]" ).
      executeUpdate();
  }
<% end -%>

<%
            data_module.sync.entities_to_synchronize.collect do |e|
              # Assume that the synchronization process will correctly handle
              # deletion of referenced entities and thus no special handling required
              e.sync.references_requiring_manual_sync.each do |a|
                if a.referenced_entity.sync.support_remove?
-%>
  protected abstract void remove<%= a.entity.qualified_name.gsub('.','') %>RelatedTo<%= a.referenced_entity.qualified_name.gsub('.','') %>Via<%= a.name %>( @javax.annotation.Nonnull final <%= e.jpa.qualified_name %> <%= Reality::Naming.camelize(e.jpa.name) %> );

<%
                end
              end
              e.sync.managed_references_requiring_manual_sync.each do |a|
                if a.referenced_entity.sync.support_remove?
-%>
  protected void removeUnmanaged<%= a.entity.qualified_name.gsub('.','') %>RelatedTo<%= a.referenced_entity.qualified_name.gsub('.','') %>Via<%= a.name %>( @javax.annotation.Nonnull final <%= e.jpa.qualified_name %> <%= Reality::Naming.camelize(e.jpa.name) %> )
  {
  }

<%
                end
              end
            end
-%>
<% data_module.sync.entities_to_synchronize.each do |entity|
     fn = "#{entity.data_module.name}#{entity.name}"
     recursive_attributes = entity.attributes.select{|a| a.sync? }.select{|a| a.reference? && a.referenced_entity.qualified_name == entity.qualified_name}.collect{|a| entity.sync.master_entity.attribute_by_name(a.name)}

     entity.attributes.select{|a| a.sync? &&a.sync.custom_transform? }.each do |attribute|
-%>

  <%= nullability_annotation(attribute.nullable?) %>
  protected <%= attribute.jpa.java_type(:boundary) %> transform<%= fn %><%= attribute.name %>( <%= nullability_annotation(attribute.nullable?) %> final <%= attribute.jpa.java_type(:boundary) %> value )
  {
<% if attribute.sync.custom_transform? || !attribute.reference? -%>
    return value;
<% else -%>
<% if attribute.nullable? -%>
    if ( null == value )
    {
      return null;
    }
    else
    {
<% end -%>
      return (Integer) _entityManager.
        createNativeQuery( "<%= j_escape_string( "SELECT #{ entity.sync.master_entity.attribute_by_name( attribute.primary_key? ? attribute.entity.name : attribute.name ).sql.quoted_column_name } FROM #{ entity.sync.master_entity.sql.qualified_table_name } WHERE #{ data_module.sql.dialect.quote('MasterID') } = ?1" ) %>" ).
        setParameter( 1, value ).
        getSingleResult();
<% if attribute.nullable? -%>
    }
<% end -%>
<% end -%>
  }
<% end -%>
<% if !entity.primary_key.generated_value? && entity.primary_key.attribute_type == :text
  s = data_module.service_by_name(:SynchronizationContext)
  m = s.method_by_name("Generate#{entity.data_module.name}#{entity.name}Key")
  -%>
  @javax.annotation.Nonnull
  protected <%= m.return_value.ejb.java_type(:boundary) %> generate<%= entity.data_module.name %><%= entity.name %>Key(<%= m.parameters.collect{|p| "#{annotated_type(p, :ejb)} #{Reality::Naming.camelize(p.name)}" }.join(', ') %>)
  {
    return java.util.UUID.randomUUID().toString();
  }

<% end -%>
<%
  common_criteria = "M.#{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.false_sql} AND M.#{entity.sync.master_entity.attribute_by_name(:MappingSource).sql.quoted_column_name} = ?"
  criteria = "#{common_criteria} AND M.#{entity.sync.master_entity.attribute_by_name(:DeletedAt).sql.quoted_column_name} IS NULL"
  remove_criteria = "#{common_criteria} AND M.#{entity.sync.master_entity.attribute_by_name(:DeletedAt).sql.quoted_column_name} IS NOT NULL"
  create_criteria = ''

  ref_index = 0
  attr_select = (entity.sync.master_entity.attributes.select{|a| (a.primary_key? || entity.attribute_by_name?(a.name)) && !%w(DeletedAt MappingId).include?(a.name.to_s) }.collect do |a|
    if a.primary_key?
      "M.#{entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name}"
    elsif a.reference? && a.referenced_entity.data_module.sync.master_data_module? && a.name.to_s != 'MappingSource'
      ref_index += 1
      if a.referenced_entity.abstract?
        index = -1
        "COALESCE(#{a.referenced_entity.concrete_subtypes.collect do |subtype| "R#{ref_index}#{index += 1}.#{subtype.attribute_by_name(subtype.root_entity.name).sql.quoted_column_name}" end.join(', ')}) AS #{entity.attribute_by_name(a.name).sql.quoted_column_name}"
      else
        "R#{ref_index}.#{a.referenced_entity.attribute_by_name(a.referenced_entity.root_entity.name).sql.quoted_column_name} AS #{entity.attribute_by_name(a.name).sql.quoted_column_name}"
      end
    else
      "M.#{a.sql.quoted_column_name}"
    end
  end + ["M.#{entity.sync.master_entity.attribute_by_name(:Id).sql.quoted_column_name} AS #{entity.sql.dialect.quote(:MasterId)}",
         "M.#{entity.sync.master_entity.attribute_by_name(:MappingId).sql.quoted_column_name}"]).join(', ')

  joins = ''
  ref_index = 0
  entity.sync.master_entity.attributes.select{|a| a.reference? && a.referenced_entity.data_module.sync.master_data_module? && a.name.to_s != 'MappingSource'}.collect do |a|
    ref_index += 1
    if a.referenced_entity.abstract?
      ids = []
      a.referenced_entity.concrete_subtypes.each_with_index do |subtype, index|
        joins += "      \" #{ j_escape_string("LEFT JOIN #{subtype.sql.qualified_table_name} R#{ref_index}#{index} ON R#{ref_index}#{index}.#{subtype.primary_key.sql.quoted_column_name} = M.#{a.sql.quoted_column_name} AND R#{ref_index}#{index}.#{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.true_sql}") } \" +\n"
        ids << "R#{ref_index}.#{a.referenced_entity.primary_key.sql.quoted_column_name}"
      end
      if a.nullable?
        create_criteria += " AND (M.#{a.sql.quoted_column_name} IS NULL OR COALESCE(#{ids.join(', ')}) IS NOT NULL)"
      end
    else
      joins += "      \" #{ j_escape_string("#{a.nullable? ? 'LEFT ' : ''}JOIN #{a.referenced_entity.sql.qualified_table_name} R#{ref_index} ON R#{ref_index}.#{a.referenced_entity.primary_key.sql.quoted_column_name} = M.#{a.sql.quoted_column_name} AND R#{ref_index}.#{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.true_sql}") } \" +\n"
      if a.nullable?
        create_criteria += " AND (M.#{a.sql.quoted_column_name} IS NULL OR R#{ref_index}.#{a.referenced_entity.primary_key.sql.quoted_column_name} IS NOT NULL)"
      end
    end
  end

  cte = ''
  order_by = ''
  table = entity.sync.master_entity.sql.qualified_table_name
  if recursive_attributes.size == 1
    base_attr_select = entity.sync.master_entity.attributes.collect do |a|
      "M.#{a.sql.quoted_column_name}"
    end.join(', ')

    table = "#{fn}List"
    order_by = 'ORDER BY M.Level ASC'
    cte = <<-CTE
      "WITH #{fn}List(#{base_attr_select.gsub('M.','')}, [Level]) AS ( \" +
      "  SELECT #{base_attr_select}, 0 \" +
      "  FROM #{entity.sync.master_entity.sql.qualified_table_name} M " +
      "  WHERE M.#{recursive_attributes[0].sql.quoted_column_name} IS NULL " +
      "  UNION ALL " +
      "  SELECT #{base_attr_select}, L.[Level] + 1 " +
      "  FROM #{entity.sync.master_entity.sql.qualified_table_name} M " +
      "  JOIN #{fn}List L ON L.[Id] = M.#{recursive_attributes[0].sql.quoted_column_name} " +
      "  WHERE M.#{recursive_attributes[0].sql.quoted_column_name} IS NOT NULL " +
      " ) " +
    CTE
  end

-%>
  @java.lang.Override
  @javax.annotation.Nonnull
  public java.util.List<Object[]> query<%= entity.data_module.name %><%= entity.name %>Updates( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    final String sql = getSqlToRetrieve<%= entity.data_module.name %><%= entity.name %>ListToUpdate( mappingSourceCode );
    final javax.persistence.Query query = _entityManager.createNativeQuery( sql );
    query.setParameter( 1, mappingSourceCode );
    return query.getResultList();
  }

<% if entity.sync.support_remove? -%>
  @java.lang.Override
  @javax.annotation.Nonnull
  public java.util.List<Object[]> query<%= entity.data_module.name %><%= entity.name %>Removals( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    final String sql = getSqlToRetrieve<%= entity.data_module.name %><%= entity.name %>ListToRemove( mappingSourceCode );
    final javax.persistence.Query query = _entityManager.createNativeQuery( sql );
    query.setParameter( 1, mappingSourceCode );
    return query.getResultList();
  }

<% end -%>
  @java.lang.Override
  public boolean createOrUpdate<%= entity.data_module.name %><%= entity.name %>( @javax.annotation.Nonnull final String mappingSourceCode, @javax.annotation.Nonnull final java.lang.Object[] record )
  {
<% attr = entity.sync.master_entity.attributes.select{|a| a.name != :DeletedAt && (a.primary_key? || entity.attribute_by_name?(a.name)) }.collect{|a| a.primary_key? ? entity.primary_key : entity.attribute_by_name(a.name)} + [entity.attribute_by_name(:MasterId)] -%>
<% attr.each_with_index do |a, i| -%>
<% if a.enumeration? && a.enumeration.textual_values? -%>
    final <%= a.jpa.java_type(:boundary) %> v_<%= a.name %> = <%= a.nullable? ? "null == record[ #{i} ] ? null : " : ''  %><%= a.jpa.java_type(:boundary) %>.valueOf( (java.lang.String) record[ <%= i %> ] );
<% elsif a.enumeration? -%>
    final <%= a.jpa.java_type(:boundary) %> v_<%= a.name %> = <%= a.nullable? ? "null == record[ #{i} ] ? null : " : '' %><%= a.jpa.java_type(:boundary) %>.values()[ (java.lang.Integer) record[ <%= i %> ] ];
<% else -%>
    final <%= a.jpa.non_primitive_java_type(:boundary) %> v_<%= a.name %> = (<%= a.jpa.non_primitive_java_type(:boundary) %>) record[ <%= i %> ];
<% end -%>
<% end -%>
<% attr.select{|a|a.reference?}.each do |a| -%>
    <%= a.jpa.non_primitive_java_type %> v_<%= a.name %>_ref = null;
<% if a.nullable? -%>
    if ( null == v_<%= a.name %> )
    {
      v_<%= a.name %>_ref = null;
    }
    else
    {
<% end -%>
<% if a.referenced_entity.abstract? -%>
      <%= a.jpa.java_type %> <%= a.name %>_ref = null;
<% a.referenced_entity.concrete_subtypes.each do |subtype| -%>
      if( null == <%= a.name %>_ref )
      {
        <%= a.name %>_ref = _<%= Reality::Naming.camelize(entity.data_module.name) %><%= subtype.name %>Repository.findBy<%= subtype.primary_key.name %>( v_<%= a.name %> );
      }
<% end -%>
      if( null == <%= a.name %>_ref )
      {
        throw new IllegalStateException( "Unable to locate <%= a.referenced_entity.qualified_name %> referenced by <%= a.qualified_name %> with value " + v_<%= a.name %> );
      }
      v_<%= a.name %>_ref = <%= a.name %>_ref;
<% else -%>
      v_<%= a.name %>_ref = _<%= Reality::Naming.camelize(a.referenced_entity.data_module.name) %><%= a.referenced_entity.name %>Repository.getBy<%= a.referenced_entity.primary_key.name %>( v_<%= a.name %> );
<% end -%>
<% if a.nullable? -%>
    }
<% end -%>
<% end -%>

    final String v_MappingId = (String) record[ <%= attr.size %> ];

    final <%= entity.jpa.qualified_name %> entity;
    if( null == v_<%= entity.primary_key.name %> )
    {
<% attr.select{|a|a.immutable? && !a.generated_value?}.each do |a| %>
      final <%= a.jpa.java_type %> v_<%= a.name %>_ctor;
<% if a.sync? && a.sync.custom_transform? -%>
      v_<%= a.name %>_ctor = transform<%= entity.data_module.name %><%= entity.name %><%= a.name %>( v_<%= a.name %> );
<% elsif a.reference? -%>
      v_<%= a.name %>_ctor = v_<%= a.name %>_ref;
<% else -%>
      v_<%= a.name %>_ctor = <% if a.primary_key? -%>generate<%= entity.qualified_name.to_s.gsub('.','') %>Key( <%= attr.select{|a| !a.primary_key?}.collect{|a| "v_#{a.name}"}.join(', ') %> )<% else -%>v_<%= a.name %><% end -%>;
<% end -%>
<% end -%>
      entity = new <%= entity.jpa.qualified_name %>(<%= attr.select{|a|a.immutable? && !a.generated_value?}.collect{|a| "v_#{a.name}_ctor"}.join(', ') %>);
    }
    else
    {
<% if entity.sync.update_via_sync? -%>
      entity = _<%= Reality::Naming.camelize(entity.data_module.name) %><%= entity.name %>Repository.getBy<%= entity.primary_key.name %>( v_<%= entity.primary_key.name %> );
<% else -%>
      throw new java.lang.IllegalStateException( "Attempted to update <%= entity.qualified_name %> entity that has no mutable fields" );
<% end -%>
    }
<% attr.select{|a|!a.immutable?}.each do |a| -%>
    {
<% if a.sync? && a.sync.custom_transform? -%>
      final <%= a.jpa.java_type(:boundary) %> v = transform<%= entity.data_module.name %><%= entity.name %><%= a.name %>( v_<%= a.name %> );
      entity.set<%= a.name %>( v );
<% elsif a.reference? -%>
      entity.set<%= a.name %>( v_<%= a.name %>_ref );
<% else -%>
      entity.set<%= a.name %>( v_<%= a.name %> );
<% end -%>
    }
<% end -%>
    if( null == v_<%= entity.primary_key.name %> )
    {
      _<%= Reality::Naming.camelize(entity.data_module.name) %><%= entity.name %>Repository.persist( entity );
      _entityManager.
        createNativeQuery( "<%= j_escape_string("UPDATE #{ entity.sync.master_entity.sql.qualified_table_name } SET #{ entity.sync.master_entity.attribute_by_name( entity.root_entity.name ).sql.quoted_column_name } = ?, #{ data_module.sql.dialect.quote('MasterSynchronized') } = ? WHERE #{ data_module.sql.dialect.quote('MappingId') } = ? AND #{ data_module.sql.dialect.quote('MappingSource') } = ? AND #{ data_module.sql.dialect.quote('MasterSynchronized') } = #{entity.sql.dialect.false_sql}") %>" ).
        setParameter( 1, entity.<%= getter_for(entity.primary_key) %> ).
        setParameter( 2, Boolean.TRUE ).
        setParameter( 3, v_MappingId ).
        setParameter( 4, mappingSourceCode ).
        executeUpdate();
      on<%= entity.qualified_name.gsub('.','') %>Created( entity );
      return true;
    }
    else
    {
<% if entity.sync.update_via_sync? -%>
      _entityManager.flush();
      _entityManager.
        createNativeQuery( "<%= j_escape_string("UPDATE #{ entity.sync.master_entity.sql.qualified_table_name } SET #{ data_module.sql.dialect.quote('MasterSynchronized') } = ? WHERE #{ data_module.sql.dialect.quote('MappingId') } = ? AND #{ data_module.sql.dialect.quote('MappingSource') } = ?") %>" ).
        setParameter( 1, Boolean.TRUE ).
        setParameter( 2, v_MappingId ).
        setParameter( 3, mappingSourceCode ).
        executeUpdate();
      return false;
<% else -%>
      throw new java.lang.IllegalStateException( "Attempted to update <%= entity.qualified_name %> entity that has no mutable fields" );
<% end -%>
    }
  }

  protected void on<%= entity.qualified_name.gsub('.','') %>Created( @javax.annotation.Nonnull final <%= entity.jpa.qualified_name %> entity )
  {
  }

<% if entity.sync.support_remove? -%>
  @java.lang.Override
  @java.lang.SuppressWarnings( "deprecation" )
  public boolean remove<%= entity.data_module.name %><%= entity.name %>( final int mappingId, @javax.annotation.Nullable final <%= entity.primary_key.jpa.java_type(:boundary) %> id )
  {
    boolean deleted = false;
    if( null != id )
    {
      final <%= entity.jpa.qualified_name %> entity = _<%= Reality::Naming.camelize(entity.data_module.name) %><%= entity.name %>Repository.findBy<%= entity.primary_key.name %>( id );
      if( null != entity )
      {
        deleted = true;
<% if entity.transaction_time? -%>
        entity.setDeletedAt( new java.util.Date() );
<% unless entity.jpa.attributes_to_delink.empty? -%>
        entity.delinkDuringPreRemove();
<% end -%>
<% end -%>
<% entity.sync.references_requiring_manual_sync.each do |a| -%>
        remove<%= a.entity.qualified_name.gsub('.','') %>RelatedTo<%= a.referenced_entity.qualified_name.gsub('.','') %>Via<%= a.name %>( entity );
<% end -%>
<% entity.sync.managed_references_requiring_manual_sync.each do |a| -%>
        removeUnmanaged<%= a.entity.qualified_name.gsub('.','') %>RelatedTo<%= a.referenced_entity.qualified_name.gsub('.','') %>Via<%= a.name %>( entity );
<% end -%>
<% if entity.transaction_time? -%>
<% entity.sync.references_not_requiring_manual_sync.select{|a| a.entity.qualified_name == entity.qualified_name }.each do |a| -%>
        {
          final java.util.List<<%= a.entity.jpa.qualified_name %>> incomingReferences = _<%= Reality::Naming.camelize(a.entity.data_module.name) %><%= a.entity.name %>Repository.findAllBy<%= a.name %>( entity );
          for ( final <%= a.entity.jpa.qualified_name %> other : incomingReferences )
          {
<% if a.nullable? -%>
            other.set<%= a.name %>( null );
<% else -%>
            /*
             * We need to throw a specific runtime exception that causes a rollback. This should be caught by callee and
             * result in the changes to be added to a list of deferred changes. After synchronizng all entities for a type
             * then we should iterate over the deferred changes list until either no entities are synchronized or that there
             * is no more elements in deferred changes list. This serves as a brute force mechanism via which entity
             * changes can be applied assuming that there is at least one valid order in which changes can be applied.
             */
            throw new <%= data_module.exception_by_name(:BadSyncSequence).ee.qualified_name %>( "Failed to synchronize <%= entity.qualified_name %> with <%= entity.primary_key.name %> " + id + " as non-nullable references exist from <%= a.entity.qualified_name %>.<%= a.name %>" );
<% end -%>
          }
        }
<% end -%>
<% end -%>
<% if entity.transaction_time? -%>
        _entityManager.flush();
<% else -%>
        _<%= Reality::Naming.camelize(entity.data_module.name) %><%= entity.name %>Repository.remove( entity );
<% end -%>
      }
    }
    _entityManager.
      createNativeQuery( "<%= j_escape_string("UPDATE #{ entity.sync.master_entity.sql.qualified_table_name } SET #{ data_module.sql.dialect.quote('MasterSynchronized') } = ? WHERE #{ data_module.sql.dialect.quote('Id') } = ?") %>" ).
      setParameter( 1, Boolean.TRUE ).
      setParameter( 2, mappingId ).
      executeUpdate();
    return deleted;
  }

  @java.lang.SuppressWarnings( "unchecked" )
  @java.lang.Override
  public int mark<%= entity.data_module.name %><%= entity.name %>RemovalsPreSync( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    final String sql =
      "<%= j_escape_string("UPDATE #{data_module.repository.pgsql? ? "" : "TOP (500)"} #{entity.sync.master_entity.sql.qualified_table_name}") %>" +
      "<%= j_escape_string(" SET #{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.true_sql}") %>" +
<%  if data_module.repository.pgsql? -%>
      "<%= j_escape_string(" WHERE #{entity.sync.master_entity.attribute_by_name(:Id).sql.quoted_column_name} IN") %> " +
      "<%= j_escape_string(" ( SELECT #{entity.sync.master_entity.attribute_by_name(:Id).sql.quoted_column_name}") %> " +
      "<%= j_escape_string("   FROM #{entity.sync.master_entity.sql.qualified_table_name}") %> " +
      "<%= j_escape_string("   WHERE #{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.false_sql}") %> AND" +
      "<%= j_escape_string("     #{entity.sync.master_entity.attribute_by_name(:DeletedAt).sql.quoted_column_name} IS NOT NULL") %> AND" +
      "<%= j_escape_string("     #{entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name } IS NULL") %> AND" +
      "<%= j_escape_string("     #{data_module.sql.dialect.quote(:MappingSource)} = ?") %>" +
      "<%= j_escape_string("     LIMIT 500 )") %>";
<%  else -%>
      "<%= j_escape_string(" WHERE #{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.false_sql}") %> AND" +
      "<%= j_escape_string("   #{entity.sync.master_entity.attribute_by_name(:DeletedAt).sql.quoted_column_name} IS NOT NULL") %> AND" +
      "<%= j_escape_string("   #{entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name } IS NULL") %> AND" +
      "<%= j_escape_string("   #{data_module.sql.dialect.quote(:MappingSource)} = ?") %>";
<%  end -%>

    final javax.persistence.Query query = _entityManager.createNativeQuery( sql );
    query.setParameter( 1, mappingSourceCode );
    return query.executeUpdate();
  }
<% end -%>
<% if entity.sync.enable_bulk_sync? -%>

  @java.lang.Override
  public int bulkCreate<%= fn %>( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    final String insertSql = getSqlToDirectlyInsert<%= fn %>( mappingSourceCode );
    final javax.persistence.Query insertQuery = _entityManager.createNativeQuery( insertSql );
    insertQuery.setParameter( 1, mappingSourceCode );
    final int insertionCount = insertQuery.executeUpdate();

    final String updateSql;
    if ( insertionCount > 0 )
    {
      updateSql = getSqlToMarkInserted<%=fn%>AsSynchronized( mappingSourceCode );
      final javax.persistence.Query updateQuery =_entityManager.createNativeQuery( updateSql );
      updateQuery.setParameter( 1, mappingSourceCode );
      final int updateCount = updateQuery.executeUpdate();

      if ( updateCount != insertionCount )
      {
        LOG.severe( "Bulk addition of <%= fn %> failed, " + insertionCount + " vs " + updateCount + "\nSql for insert: \n" + insertSql + "\nSql for update: \n" + updateSql );
        throw new IllegalStateException( "Mismatch between inserted count and update count for <%= fn %>" );
      }
    }

    return insertionCount;
  }

  @javax.annotation.Nonnull
  @java.lang.Override
  public String getSqlToDirectlyInsert<%= fn %>( @javax.annotation.Nonnull final String mappingSourceCode )
  {
<% bulk_attrs = entity.attributes.select{|a| a.sql? && a.jpa? && (a.sync? || %w(CreatedAt).include?(a.name.to_s)) }
   bulk_attrs_insert = j_escape_string(bulk_attrs.collect{|a| a.primary_key? ? entity.sql.dialect.quote(:MasterId) : a.sql.quoted_column_name}.join(', '))
  -%>
    return
      "INSERT INTO <%= j_escape_string(entity.sql.qualified_table_name) %>(<%= bulk_attrs_insert -%>)\n" +
      "SELECT <%= bulk_attrs_insert %> FROM ( " +
      getSqlToRetrieve<%= fn %>ListToUpdate( mappingSourceCode ) + " AND \n" +
      "<%= j_escape_string("M.#{entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name} IS NULL") -%>) X\n";
  }

  @javax.annotation.Nonnull
  @java.lang.Override
  public String getSqlToMarkInserted<%= fn %>AsSynchronized( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    return
      "UPDATE <%= j_escape_string("#{data_module.repository.pgsql? ? table + " " : ""}") -%>M\n" +
      "SET\n" +
      "  <%= j_escape_string("#{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.true_sql}") -%>, " +
      "  <%= j_escape_string("#{entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name} = C.#{entity.primary_key.sql.quoted_column_name}") %>\n" +
<%  if data_module.repository.pgsql? -%>
      "FROM <%= j_escape_string("#{entity.sql.qualified_table_name} C") %> \n" +
      " WHERE C.<%= j_escape_string("#{entity.attribute_by_name(:MasterId).sql.quoted_column_name} = M.#{entity.sync.master_entity.primary_key.sql.quoted_column_name}") -%> AND " +
<%  else -%>
      "FROM <%= j_escape_string( table ) %> M \n" +
      " JOIN <%= j_escape_string("#{entity.sql.qualified_table_name} C ON C.#{entity.attribute_by_name(:MasterId).sql.quoted_column_name} = M.#{entity.sync.master_entity.primary_key.sql.quoted_column_name}") %> AND " +
<%  end -%>
      "M.<%= j_escape_string("#{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.false_sql}") -%> AND " +
      "M.<%= j_escape_string("#{entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name} IS NULL") -%>\n";
  }

<% if entity.sync.update_via_sync? -%>
  @javax.annotation.Nonnull
  @java.lang.Override
  public String getSqlToDirectlyUpdate<%= fn %>( @javax.annotation.Nonnull final String mappingSourceCode )
  {
<%   attr_set = entity.sync.attributes_to_update.collect {|a| a.sql.quoted_column_name } -%>
    return
      "UPDATE O\n" +
      "SET\n" +
      "  <%= j_escape_string(attr_set.collect{|a| "#{a} = M.#{a}"}.join(', ')) -%>\n" +
      "FROM <%= j_escape_string( entity.sql.qualified_table_name ) %> O \n" +
      "JOIN ( \n" +
      getSqlToRetrieve<%= fn %>ListToUpdate( mappingSourceCode ) + "\n" +
      ") M ON M.<%= j_escape_string(entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name) %> = O.<%= j_escape_string(entity.primary_key.sql.quoted_column_name) %>";
  }

  @javax.annotation.Nonnull
  @java.lang.Override
  public String getSqlToMarkUpdated<%= fn %>AsSynchronized( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    return
      "UPDATE O\n" +
      "SET\n" +
      "  <%= j_escape_string("#{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.true_sql}") -%>\n" +
      "FROM <%= j_escape_string( table ) %> O \n" +
      "JOIN ( \n" +
      getSqlToRetrieve<%= fn %>ListToUpdate( mappingSourceCode ) + "\n" +
      ") M ON M.<%= j_escape_string(entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name) %> = O.<%= j_escape_string(entity.primary_key.sql.quoted_column_name) %>";
  }

<% end -%>
<% if entity.sync.support_remove? -%>
  @javax.annotation.Nonnull
  @java.lang.Override
  public String getSqlToDirectlyDelete<%= fn %>( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    return
<% if entity.transaction_time? -%>
      "UPDATE O\n" +
      "SET\n" +
      "  <%= j_escape_string(entity.attribute_by_name(:DeletedAt).sql.quoted_column_name) %> = GETDATE()\n" +
<% else -%>
      "DELETE O\n" +
<% end -%>
      "FROM <%= j_escape_string( entity.sql.qualified_table_name ) %> O \n" +
      "JOIN ( \n" +
      getSqlToRetrieve<%= fn %>ListToRemove( mappingSourceCode ) + "\n" +
      ") M ON M.<%= j_escape_string(entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name) %> = O.<%= j_escape_string(entity.primary_key.sql.quoted_column_name) %>";
  }

  @javax.annotation.Nonnull
  @java.lang.Override
  public String getSqlToMarkDeleted<%= fn %>AsSynchronized( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    return
      "UPDATE O\n" +
      "SET\n" +
      "  <%= j_escape_string("#{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.true_sql}") -%>\n" +
      "FROM <%= j_escape_string( table ) %> O \n" +
      "JOIN ( \n" +
      getSqlToRetrieve<%= fn %>ListToRemove( mappingSourceCode ) + "\n" +
      ") M ON M.<%= j_escape_string(entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name) %> = O.<%= j_escape_string(entity.primary_key.sql.quoted_column_name) %>";
  }
<% end -%>
<% end -%>

  @javax.annotation.Nonnull
  protected String getSqlToRetrieve<%= fn %>ListToUpdate( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    return
<% if recursive_attributes.size <= 1 -%>
<%= cte -%>
      "SELECT <%= j_escape_string( attr_select ) -%> " +
      "FROM <%= j_escape_string( table ) %> M " +
<%= joins -%>
      "WHERE <%= j_escape_string( criteria ) %><%= j_escape_string( create_criteria ) %> " +
      "<%= j_escape_string( order_by ) %>";
<% else -%>
    /*
<%= cte -%>
      "SELECT <%= attr_select -%> " +
      "FROM <%= table %> M " +
<%= joins -%>
      "WHERE <%= criteria %><%= create_criteria %> " +
      "<%= order_by %>";
     */
    throw new IllegalStateException( "Override getSqlToRetrieve<%= fn %>ListToUpdate() due to multiple recursive attributes." );
<% end -%>
  }

<% if entity.sync.support_remove? -%>
  @javax.annotation.Nonnull
  protected String getSqlToRetrieve<%= fn %>ListToRemove( @javax.annotation.Nonnull final String mappingSourceCode )
  {
<% if recursive_attributes.size <= 1 -%><commit_msg>Make sure valid code is generated when multiple recursive attribtues defined<commit_after>/* DO NOT EDIT: File is auto-generated */
package <%= to_package(data_module.sync.qualified_sync_context_impl_name) %>;

/**

 Base class to extend to customize the synchronization process.

<code>
<pre>
@ApplicationScoped
@Transactional
@Typed( <%= data_module.service_by_name(:SynchronizationContext).ejb.qualified_service_name %>.class )
public class <%= data_module.sync.sync_context_impl_name.gsub(/^Abstract/,'') %>
  extends <%= data_module.sync.sync_context_impl_name %>
{
<%
data_module.repository.data_module_by_name(data_module.repository.sync.master_data_module).sync.entities_to_synchronize.collect do |e|
  e.sync.references_requiring_manual_sync.each do |a|
-%>
  @Override
  protected void remove<%= a.entity.qualified_name.gsub('.','') %>RelatedTo<%= a.referenced_entity.qualified_name.gsub('.','') %>Via<%= a.name %>(...) {...}
<%
  end
end
-%>
}
</pre>
</code>
 */
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings( { "NP_LOAD_OF_KNOWN_NULL_VALUE", "DLS_DEAD_LOCAL_STORE", "CLI_CONSTANT_LIST_INDEX", "ACEM_ABSTRACT_CLASS_EMPTY_METHODS" } )
@java.lang.SuppressWarnings( { "unchecked", "UnusedParameters", "PMD.AddEmptyString", "PMD.UnusedLocalVariable", "PMD.LocalVariableNamingConventions" } )
public abstract class <%= data_module.sync.sync_context_impl_name %>
  implements <%= data_module.service_by_name(:SynchronizationContext).ejb.qualified_service_name %>
{
  private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger( <%= data_module.sync.sync_context_impl_name %>.class.getName() );

  @javax.persistence.PersistenceContext( unitName = <%= data_module.repository.jpa.qualified_unit_descriptor_name %>.NAME )
  private javax.persistence.EntityManager _entityManager;
<% data_module.sync.entities_to_synchronize.each do |entity| -%>
  @javax.inject.Inject
  private <%= entity.dao.jpa.qualified_dao_service_name %> _<%= Reality::Naming.camelize(entity.data_module.name) %><%= entity.name %>Repository;
<% end -%>

  /**
   * Hook that can be overriden to perform actions before any sync takes place.
   * Be very careful not to do anything that may cause sync to fail.
   */
  @java.lang.Override
  public void preSync( @javax.annotation.Nonnull final iris.syncrecord.server.service.SynchronizationRecorder recorder )
  {
  }

  /**
   * Hook that can be overriden to perform actions once sync has completed.
   * Be very very careful not to do anything that may cause sync to fail.
   */
  @java.lang.Override
  public void postSync( @javax.annotation.Nonnull final iris.syncrecord.server.service.SynchronizationRecorder recorder )
  {
  }

  @java.lang.Override
  public void syncComplete()
  {
<% if data_module.repository.mssql? -%>
    purgeSyncQueryPlans();
<% end -%>
  }
<% if data_module.repository.mssql? -%>

  private void purgeSyncQueryPlans()
  {
    // Remove query plans from plan cache as they usually long running and
    // unoptimized and thus will dominate the "recent expensive queries list"
    // even through we have no plans to optimize them
    _entityManager.
      createNativeQuery( "EXEC <%= data_module.sql.quoted_schema %>.[spRemoveCachedMasterQueryPlans]" ).
      executeUpdate();
  }
<% end -%>

<%
            data_module.sync.entities_to_synchronize.collect do |e|
              # Assume that the synchronization process will correctly handle
              # deletion of referenced entities and thus no special handling required
              e.sync.references_requiring_manual_sync.each do |a|
                if a.referenced_entity.sync.support_remove?
-%>
  protected abstract void remove<%= a.entity.qualified_name.gsub('.','') %>RelatedTo<%= a.referenced_entity.qualified_name.gsub('.','') %>Via<%= a.name %>( @javax.annotation.Nonnull final <%= e.jpa.qualified_name %> <%= Reality::Naming.camelize(e.jpa.name) %> );

<%
                end
              end
              e.sync.managed_references_requiring_manual_sync.each do |a|
                if a.referenced_entity.sync.support_remove?
-%>
  protected void removeUnmanaged<%= a.entity.qualified_name.gsub('.','') %>RelatedTo<%= a.referenced_entity.qualified_name.gsub('.','') %>Via<%= a.name %>( @javax.annotation.Nonnull final <%= e.jpa.qualified_name %> <%= Reality::Naming.camelize(e.jpa.name) %> )
  {
  }

<%
                end
              end
            end
-%>
<% data_module.sync.entities_to_synchronize.each do |entity|
     fn = "#{entity.data_module.name}#{entity.name}"
     recursive_attributes = entity.attributes.select{|a| a.sync? }.select{|a| a.reference? && a.referenced_entity.qualified_name == entity.qualified_name}.collect{|a| entity.sync.master_entity.attribute_by_name(a.name)}

     entity.attributes.select{|a| a.sync? &&a.sync.custom_transform? }.each do |attribute|
-%>

  <%= nullability_annotation(attribute.nullable?) %>
  protected <%= attribute.jpa.java_type(:boundary) %> transform<%= fn %><%= attribute.name %>( <%= nullability_annotation(attribute.nullable?) %> final <%= attribute.jpa.java_type(:boundary) %> value )
  {
<% if attribute.sync.custom_transform? || !attribute.reference? -%>
    return value;
<% else -%>
<% if attribute.nullable? -%>
    if ( null == value )
    {
      return null;
    }
    else
    {
<% end -%>
      return (Integer) _entityManager.
        createNativeQuery( "<%= j_escape_string( "SELECT #{ entity.sync.master_entity.attribute_by_name( attribute.primary_key? ? attribute.entity.name : attribute.name ).sql.quoted_column_name } FROM #{ entity.sync.master_entity.sql.qualified_table_name } WHERE #{ data_module.sql.dialect.quote('MasterID') } = ?1" ) %>" ).
        setParameter( 1, value ).
        getSingleResult();
<% if attribute.nullable? -%>
    }
<% end -%>
<% end -%>
  }
<% end -%>
<% if !entity.primary_key.generated_value? && entity.primary_key.attribute_type == :text
  s = data_module.service_by_name(:SynchronizationContext)
  m = s.method_by_name("Generate#{entity.data_module.name}#{entity.name}Key")
  -%>
  @javax.annotation.Nonnull
  protected <%= m.return_value.ejb.java_type(:boundary) %> generate<%= entity.data_module.name %><%= entity.name %>Key(<%= m.parameters.collect{|p| "#{annotated_type(p, :ejb)} #{Reality::Naming.camelize(p.name)}" }.join(', ') %>)
  {
    return java.util.UUID.randomUUID().toString();
  }

<% end -%>
<%
  common_criteria = "M.#{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.false_sql} AND M.#{entity.sync.master_entity.attribute_by_name(:MappingSource).sql.quoted_column_name} = ?"
  criteria = "#{common_criteria} AND M.#{entity.sync.master_entity.attribute_by_name(:DeletedAt).sql.quoted_column_name} IS NULL"
  remove_criteria = "#{common_criteria} AND M.#{entity.sync.master_entity.attribute_by_name(:DeletedAt).sql.quoted_column_name} IS NOT NULL"
  create_criteria = ''

  ref_index = 0
  attr_select = (entity.sync.master_entity.attributes.select{|a| (a.primary_key? || entity.attribute_by_name?(a.name)) && !%w(DeletedAt MappingId).include?(a.name.to_s) }.collect do |a|
    if a.primary_key?
      "M.#{entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name}"
    elsif a.reference? && a.referenced_entity.data_module.sync.master_data_module? && a.name.to_s != 'MappingSource'
      ref_index += 1
      if a.referenced_entity.abstract?
        index = -1
        "COALESCE(#{a.referenced_entity.concrete_subtypes.collect do |subtype| "R#{ref_index}#{index += 1}.#{subtype.attribute_by_name(subtype.root_entity.name).sql.quoted_column_name}" end.join(', ')}) AS #{entity.attribute_by_name(a.name).sql.quoted_column_name}"
      else
        "R#{ref_index}.#{a.referenced_entity.attribute_by_name(a.referenced_entity.root_entity.name).sql.quoted_column_name} AS #{entity.attribute_by_name(a.name).sql.quoted_column_name}"
      end
    else
      "M.#{a.sql.quoted_column_name}"
    end
  end + ["M.#{entity.sync.master_entity.attribute_by_name(:Id).sql.quoted_column_name} AS #{entity.sql.dialect.quote(:MasterId)}",
         "M.#{entity.sync.master_entity.attribute_by_name(:MappingId).sql.quoted_column_name}"]).join(', ')

  joins = ''
  ref_index = 0
  entity.sync.master_entity.attributes.select{|a| a.reference? && a.referenced_entity.data_module.sync.master_data_module? && a.name.to_s != 'MappingSource'}.collect do |a|
    ref_index += 1
    if a.referenced_entity.abstract?
      ids = []
      a.referenced_entity.concrete_subtypes.each_with_index do |subtype, index|
        joins += "      \" #{ j_escape_string("LEFT JOIN #{subtype.sql.qualified_table_name} R#{ref_index}#{index} ON R#{ref_index}#{index}.#{subtype.primary_key.sql.quoted_column_name} = M.#{a.sql.quoted_column_name} AND R#{ref_index}#{index}.#{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.true_sql}") } \" +\n"
        ids << "R#{ref_index}.#{a.referenced_entity.primary_key.sql.quoted_column_name}"
      end
      if a.nullable?
        create_criteria += " AND (M.#{a.sql.quoted_column_name} IS NULL OR COALESCE(#{ids.join(', ')}) IS NOT NULL)"
      end
    else
      joins += "      \" #{ j_escape_string("#{a.nullable? ? 'LEFT ' : ''}JOIN #{a.referenced_entity.sql.qualified_table_name} R#{ref_index} ON R#{ref_index}.#{a.referenced_entity.primary_key.sql.quoted_column_name} = M.#{a.sql.quoted_column_name} AND R#{ref_index}.#{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.true_sql}") } \" +\n"
      if a.nullable?
        create_criteria += " AND (M.#{a.sql.quoted_column_name} IS NULL OR R#{ref_index}.#{a.referenced_entity.primary_key.sql.quoted_column_name} IS NOT NULL)"
      end
    end
  end

  cte = ''
  order_by = ''
  table = entity.sync.master_entity.sql.qualified_table_name
  if recursive_attributes.size == 1
    base_attr_select = entity.sync.master_entity.attributes.collect do |a|
      "M.#{a.sql.quoted_column_name}"
    end.join(', ')

    table = "#{fn}List"
    order_by = 'ORDER BY M.Level ASC'
    cte = <<-CTE
      "WITH #{fn}List(#{base_attr_select.gsub('M.','')}, [Level]) AS ( \" +
      "  SELECT #{base_attr_select}, 0 \" +
      "  FROM #{entity.sync.master_entity.sql.qualified_table_name} M " +
      "  WHERE M.#{recursive_attributes[0].sql.quoted_column_name} IS NULL " +
      "  UNION ALL " +
      "  SELECT #{base_attr_select}, L.[Level] + 1 " +
      "  FROM #{entity.sync.master_entity.sql.qualified_table_name} M " +
      "  JOIN #{fn}List L ON L.[Id] = M.#{recursive_attributes[0].sql.quoted_column_name} " +
      "  WHERE M.#{recursive_attributes[0].sql.quoted_column_name} IS NOT NULL " +
      " ) " +
    CTE
  end

-%>
  @java.lang.Override
  @javax.annotation.Nonnull
  public java.util.List<Object[]> query<%= entity.data_module.name %><%= entity.name %>Updates( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    final String sql = getSqlToRetrieve<%= entity.data_module.name %><%= entity.name %>ListToUpdate( mappingSourceCode );
    final javax.persistence.Query query = _entityManager.createNativeQuery( sql );
    query.setParameter( 1, mappingSourceCode );
    return query.getResultList();
  }

<% if entity.sync.support_remove? -%>
  @java.lang.Override
  @javax.annotation.Nonnull
  public java.util.List<Object[]> query<%= entity.data_module.name %><%= entity.name %>Removals( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    final String sql = getSqlToRetrieve<%= entity.data_module.name %><%= entity.name %>ListToRemove( mappingSourceCode );
    final javax.persistence.Query query = _entityManager.createNativeQuery( sql );
    query.setParameter( 1, mappingSourceCode );
    return query.getResultList();
  }

<% end -%>
  @java.lang.Override
  public boolean createOrUpdate<%= entity.data_module.name %><%= entity.name %>( @javax.annotation.Nonnull final String mappingSourceCode, @javax.annotation.Nonnull final java.lang.Object[] record )
  {
<% attr = entity.sync.master_entity.attributes.select{|a| a.name != :DeletedAt && (a.primary_key? || entity.attribute_by_name?(a.name)) }.collect{|a| a.primary_key? ? entity.primary_key : entity.attribute_by_name(a.name)} + [entity.attribute_by_name(:MasterId)] -%>
<% attr.each_with_index do |a, i| -%>
<% if a.enumeration? && a.enumeration.textual_values? -%>
    final <%= a.jpa.java_type(:boundary) %> v_<%= a.name %> = <%= a.nullable? ? "null == record[ #{i} ] ? null : " : ''  %><%= a.jpa.java_type(:boundary) %>.valueOf( (java.lang.String) record[ <%= i %> ] );
<% elsif a.enumeration? -%>
    final <%= a.jpa.java_type(:boundary) %> v_<%= a.name %> = <%= a.nullable? ? "null == record[ #{i} ] ? null : " : '' %><%= a.jpa.java_type(:boundary) %>.values()[ (java.lang.Integer) record[ <%= i %> ] ];
<% else -%>
    final <%= a.jpa.non_primitive_java_type(:boundary) %> v_<%= a.name %> = (<%= a.jpa.non_primitive_java_type(:boundary) %>) record[ <%= i %> ];
<% end -%>
<% end -%>
<% attr.select{|a|a.reference?}.each do |a| -%>
    <%= a.jpa.non_primitive_java_type %> v_<%= a.name %>_ref = null;
<% if a.nullable? -%>
    if ( null == v_<%= a.name %> )
    {
      v_<%= a.name %>_ref = null;
    }
    else
    {
<% end -%>
<% if a.referenced_entity.abstract? -%>
      <%= a.jpa.java_type %> <%= a.name %>_ref = null;
<% a.referenced_entity.concrete_subtypes.each do |subtype| -%>
      if( null == <%= a.name %>_ref )
      {
        <%= a.name %>_ref = _<%= Reality::Naming.camelize(entity.data_module.name) %><%= subtype.name %>Repository.findBy<%= subtype.primary_key.name %>( v_<%= a.name %> );
      }
<% end -%>
      if( null == <%= a.name %>_ref )
      {
        throw new IllegalStateException( "Unable to locate <%= a.referenced_entity.qualified_name %> referenced by <%= a.qualified_name %> with value " + v_<%= a.name %> );
      }
      v_<%= a.name %>_ref = <%= a.name %>_ref;
<% else -%>
      v_<%= a.name %>_ref = _<%= Reality::Naming.camelize(a.referenced_entity.data_module.name) %><%= a.referenced_entity.name %>Repository.getBy<%= a.referenced_entity.primary_key.name %>( v_<%= a.name %> );
<% end -%>
<% if a.nullable? -%>
    }
<% end -%>
<% end -%>

    final String v_MappingId = (String) record[ <%= attr.size %> ];

    final <%= entity.jpa.qualified_name %> entity;
    if( null == v_<%= entity.primary_key.name %> )
    {
<% attr.select{|a|a.immutable? && !a.generated_value?}.each do |a| %>
      final <%= a.jpa.java_type %> v_<%= a.name %>_ctor;
<% if a.sync? && a.sync.custom_transform? -%>
      v_<%= a.name %>_ctor = transform<%= entity.data_module.name %><%= entity.name %><%= a.name %>( v_<%= a.name %> );
<% elsif a.reference? -%>
      v_<%= a.name %>_ctor = v_<%= a.name %>_ref;
<% else -%>
      v_<%= a.name %>_ctor = <% if a.primary_key? -%>generate<%= entity.qualified_name.to_s.gsub('.','') %>Key( <%= attr.select{|a| !a.primary_key?}.collect{|a| "v_#{a.name}"}.join(', ') %> )<% else -%>v_<%= a.name %><% end -%>;
<% end -%>
<% end -%>
      entity = new <%= entity.jpa.qualified_name %>(<%= attr.select{|a|a.immutable? && !a.generated_value?}.collect{|a| "v_#{a.name}_ctor"}.join(', ') %>);
    }
    else
    {
<% if entity.sync.update_via_sync? -%>
      entity = _<%= Reality::Naming.camelize(entity.data_module.name) %><%= entity.name %>Repository.getBy<%= entity.primary_key.name %>( v_<%= entity.primary_key.name %> );
<% else -%>
      throw new java.lang.IllegalStateException( "Attempted to update <%= entity.qualified_name %> entity that has no mutable fields" );
<% end -%>
    }
<% attr.select{|a|!a.immutable?}.each do |a| -%>
    {
<% if a.sync? && a.sync.custom_transform? -%>
      final <%= a.jpa.java_type(:boundary) %> v = transform<%= entity.data_module.name %><%= entity.name %><%= a.name %>( v_<%= a.name %> );
      entity.set<%= a.name %>( v );
<% elsif a.reference? -%>
      entity.set<%= a.name %>( v_<%= a.name %>_ref );
<% else -%>
      entity.set<%= a.name %>( v_<%= a.name %> );
<% end -%>
    }
<% end -%>
    if( null == v_<%= entity.primary_key.name %> )
    {
      _<%= Reality::Naming.camelize(entity.data_module.name) %><%= entity.name %>Repository.persist( entity );
      _entityManager.
        createNativeQuery( "<%= j_escape_string("UPDATE #{ entity.sync.master_entity.sql.qualified_table_name } SET #{ entity.sync.master_entity.attribute_by_name( entity.root_entity.name ).sql.quoted_column_name } = ?, #{ data_module.sql.dialect.quote('MasterSynchronized') } = ? WHERE #{ data_module.sql.dialect.quote('MappingId') } = ? AND #{ data_module.sql.dialect.quote('MappingSource') } = ? AND #{ data_module.sql.dialect.quote('MasterSynchronized') } = #{entity.sql.dialect.false_sql}") %>" ).
        setParameter( 1, entity.<%= getter_for(entity.primary_key) %> ).
        setParameter( 2, Boolean.TRUE ).
        setParameter( 3, v_MappingId ).
        setParameter( 4, mappingSourceCode ).
        executeUpdate();
      on<%= entity.qualified_name.gsub('.','') %>Created( entity );
      return true;
    }
    else
    {
<% if entity.sync.update_via_sync? -%>
      _entityManager.flush();
      _entityManager.
        createNativeQuery( "<%= j_escape_string("UPDATE #{ entity.sync.master_entity.sql.qualified_table_name } SET #{ data_module.sql.dialect.quote('MasterSynchronized') } = ? WHERE #{ data_module.sql.dialect.quote('MappingId') } = ? AND #{ data_module.sql.dialect.quote('MappingSource') } = ?") %>" ).
        setParameter( 1, Boolean.TRUE ).
        setParameter( 2, v_MappingId ).
        setParameter( 3, mappingSourceCode ).
        executeUpdate();
      return false;
<% else -%>
      throw new java.lang.IllegalStateException( "Attempted to update <%= entity.qualified_name %> entity that has no mutable fields" );
<% end -%>
    }
  }

  protected void on<%= entity.qualified_name.gsub('.','') %>Created( @javax.annotation.Nonnull final <%= entity.jpa.qualified_name %> entity )
  {
  }

<% if entity.sync.support_remove? -%>
  @java.lang.Override
  @java.lang.SuppressWarnings( "deprecation" )
  public boolean remove<%= entity.data_module.name %><%= entity.name %>( final int mappingId, @javax.annotation.Nullable final <%= entity.primary_key.jpa.java_type(:boundary) %> id )
  {
    boolean deleted = false;
    if( null != id )
    {
      final <%= entity.jpa.qualified_name %> entity = _<%= Reality::Naming.camelize(entity.data_module.name) %><%= entity.name %>Repository.findBy<%= entity.primary_key.name %>( id );
      if( null != entity )
      {
        deleted = true;
<% if entity.transaction_time? -%>
        entity.setDeletedAt( new java.util.Date() );
<% unless entity.jpa.attributes_to_delink.empty? -%>
        entity.delinkDuringPreRemove();
<% end -%>
<% end -%>
<% entity.sync.references_requiring_manual_sync.each do |a| -%>
        remove<%= a.entity.qualified_name.gsub('.','') %>RelatedTo<%= a.referenced_entity.qualified_name.gsub('.','') %>Via<%= a.name %>( entity );
<% end -%>
<% entity.sync.managed_references_requiring_manual_sync.each do |a| -%>
        removeUnmanaged<%= a.entity.qualified_name.gsub('.','') %>RelatedTo<%= a.referenced_entity.qualified_name.gsub('.','') %>Via<%= a.name %>( entity );
<% end -%>
<% if entity.transaction_time? -%>
<% entity.sync.references_not_requiring_manual_sync.select{|a| a.entity.qualified_name == entity.qualified_name }.each do |a| -%>
        {
          final java.util.List<<%= a.entity.jpa.qualified_name %>> incomingReferences = _<%= Reality::Naming.camelize(a.entity.data_module.name) %><%= a.entity.name %>Repository.findAllBy<%= a.name %>( entity );
          for ( final <%= a.entity.jpa.qualified_name %> other : incomingReferences )
          {
<% if a.nullable? -%>
            other.set<%= a.name %>( null );
<% else -%>
            /*
             * We need to throw a specific runtime exception that causes a rollback. This should be caught by callee and
             * result in the changes to be added to a list of deferred changes. After synchronizng all entities for a type
             * then we should iterate over the deferred changes list until either no entities are synchronized or that there
             * is no more elements in deferred changes list. This serves as a brute force mechanism via which entity
             * changes can be applied assuming that there is at least one valid order in which changes can be applied.
             */
            throw new <%= data_module.exception_by_name(:BadSyncSequence).ee.qualified_name %>( "Failed to synchronize <%= entity.qualified_name %> with <%= entity.primary_key.name %> " + id + " as non-nullable references exist from <%= a.entity.qualified_name %>.<%= a.name %>" );
<% end -%>
          }
        }
<% end -%>
<% end -%>
<% if entity.transaction_time? -%>
        _entityManager.flush();
<% else -%>
        _<%= Reality::Naming.camelize(entity.data_module.name) %><%= entity.name %>Repository.remove( entity );
<% end -%>
      }
    }
    _entityManager.
      createNativeQuery( "<%= j_escape_string("UPDATE #{ entity.sync.master_entity.sql.qualified_table_name } SET #{ data_module.sql.dialect.quote('MasterSynchronized') } = ? WHERE #{ data_module.sql.dialect.quote('Id') } = ?") %>" ).
      setParameter( 1, Boolean.TRUE ).
      setParameter( 2, mappingId ).
      executeUpdate();
    return deleted;
  }

  @java.lang.SuppressWarnings( "unchecked" )
  @java.lang.Override
  public int mark<%= entity.data_module.name %><%= entity.name %>RemovalsPreSync( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    final String sql =
      "<%= j_escape_string("UPDATE #{data_module.repository.pgsql? ? "" : "TOP (500)"} #{entity.sync.master_entity.sql.qualified_table_name}") %>" +
      "<%= j_escape_string(" SET #{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.true_sql}") %>" +
<%  if data_module.repository.pgsql? -%>
      "<%= j_escape_string(" WHERE #{entity.sync.master_entity.attribute_by_name(:Id).sql.quoted_column_name} IN") %> " +
      "<%= j_escape_string(" ( SELECT #{entity.sync.master_entity.attribute_by_name(:Id).sql.quoted_column_name}") %> " +
      "<%= j_escape_string("   FROM #{entity.sync.master_entity.sql.qualified_table_name}") %> " +
      "<%= j_escape_string("   WHERE #{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.false_sql}") %> AND" +
      "<%= j_escape_string("     #{entity.sync.master_entity.attribute_by_name(:DeletedAt).sql.quoted_column_name} IS NOT NULL") %> AND" +
      "<%= j_escape_string("     #{entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name } IS NULL") %> AND" +
      "<%= j_escape_string("     #{data_module.sql.dialect.quote(:MappingSource)} = ?") %>" +
      "<%= j_escape_string("     LIMIT 500 )") %>";
<%  else -%>
      "<%= j_escape_string(" WHERE #{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.false_sql}") %> AND" +
      "<%= j_escape_string("   #{entity.sync.master_entity.attribute_by_name(:DeletedAt).sql.quoted_column_name} IS NOT NULL") %> AND" +
      "<%= j_escape_string("   #{entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name } IS NULL") %> AND" +
      "<%= j_escape_string("   #{data_module.sql.dialect.quote(:MappingSource)} = ?") %>";
<%  end -%>

    final javax.persistence.Query query = _entityManager.createNativeQuery( sql );
    query.setParameter( 1, mappingSourceCode );
    return query.executeUpdate();
  }
<% end -%>
<% if entity.sync.enable_bulk_sync? -%>

  @java.lang.Override
  public int bulkCreate<%= fn %>( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    final String insertSql = getSqlToDirectlyInsert<%= fn %>( mappingSourceCode );
    final javax.persistence.Query insertQuery = _entityManager.createNativeQuery( insertSql );
    insertQuery.setParameter( 1, mappingSourceCode );
    final int insertionCount = insertQuery.executeUpdate();

    final String updateSql;
    if ( insertionCount > 0 )
    {
      updateSql = getSqlToMarkInserted<%=fn%>AsSynchronized( mappingSourceCode );
      final javax.persistence.Query updateQuery =_entityManager.createNativeQuery( updateSql );
      updateQuery.setParameter( 1, mappingSourceCode );
      final int updateCount = updateQuery.executeUpdate();

      if ( updateCount != insertionCount )
      {
        LOG.severe( "Bulk addition of <%= fn %> failed, " + insertionCount + " vs " + updateCount + "\nSql for insert: \n" + insertSql + "\nSql for update: \n" + updateSql );
        throw new IllegalStateException( "Mismatch between inserted count and update count for <%= fn %>" );
      }
    }

    return insertionCount;
  }

  @javax.annotation.Nonnull
  @java.lang.Override
  public String getSqlToDirectlyInsert<%= fn %>( @javax.annotation.Nonnull final String mappingSourceCode )
  {
<% bulk_attrs = entity.attributes.select{|a| a.sql? && a.jpa? && (a.sync? || %w(CreatedAt).include?(a.name.to_s)) }
   bulk_attrs_insert = j_escape_string(bulk_attrs.collect{|a| a.primary_key? ? entity.sql.dialect.quote(:MasterId) : a.sql.quoted_column_name}.join(', '))
  -%>
    return
      "INSERT INTO <%= j_escape_string(entity.sql.qualified_table_name) %>(<%= bulk_attrs_insert -%>)\n" +
      "SELECT <%= bulk_attrs_insert %> FROM ( " +
      getSqlToRetrieve<%= fn %>ListToUpdate( mappingSourceCode ) + " AND \n" +
      "<%= j_escape_string("M.#{entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name} IS NULL") -%>) X\n";
  }

  @javax.annotation.Nonnull
  @java.lang.Override
  public String getSqlToMarkInserted<%= fn %>AsSynchronized( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    return
      "UPDATE <%= j_escape_string("#{data_module.repository.pgsql? ? table + " " : ""}") -%>M\n" +
      "SET\n" +
      "  <%= j_escape_string("#{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.true_sql}") -%>, " +
      "  <%= j_escape_string("#{entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name} = C.#{entity.primary_key.sql.quoted_column_name}") %>\n" +
<%  if data_module.repository.pgsql? -%>
      "FROM <%= j_escape_string("#{entity.sql.qualified_table_name} C") %> \n" +
      " WHERE C.<%= j_escape_string("#{entity.attribute_by_name(:MasterId).sql.quoted_column_name} = M.#{entity.sync.master_entity.primary_key.sql.quoted_column_name}") -%> AND " +
<%  else -%>
      "FROM <%= j_escape_string( table ) %> M \n" +
      " JOIN <%= j_escape_string("#{entity.sql.qualified_table_name} C ON C.#{entity.attribute_by_name(:MasterId).sql.quoted_column_name} = M.#{entity.sync.master_entity.primary_key.sql.quoted_column_name}") %> AND " +
<%  end -%>
      "M.<%= j_escape_string("#{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.false_sql}") -%> AND " +
      "M.<%= j_escape_string("#{entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name} IS NULL") -%>\n";
  }

<% if entity.sync.update_via_sync? -%>
  @javax.annotation.Nonnull
  @java.lang.Override
  public String getSqlToDirectlyUpdate<%= fn %>( @javax.annotation.Nonnull final String mappingSourceCode )
  {
<%   attr_set = entity.sync.attributes_to_update.collect {|a| a.sql.quoted_column_name } -%>
    return
      "UPDATE O\n" +
      "SET\n" +
      "  <%= j_escape_string(attr_set.collect{|a| "#{a} = M.#{a}"}.join(', ')) -%>\n" +
      "FROM <%= j_escape_string( entity.sql.qualified_table_name ) %> O \n" +
      "JOIN ( \n" +
      getSqlToRetrieve<%= fn %>ListToUpdate( mappingSourceCode ) + "\n" +
      ") M ON M.<%= j_escape_string(entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name) %> = O.<%= j_escape_string(entity.primary_key.sql.quoted_column_name) %>";
  }

  @javax.annotation.Nonnull
  @java.lang.Override
  public String getSqlToMarkUpdated<%= fn %>AsSynchronized( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    return
      "UPDATE O\n" +
      "SET\n" +
      "  <%= j_escape_string("#{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.true_sql}") -%>\n" +
      "FROM <%= j_escape_string( table ) %> O \n" +
      "JOIN ( \n" +
      getSqlToRetrieve<%= fn %>ListToUpdate( mappingSourceCode ) + "\n" +
      ") M ON M.<%= j_escape_string(entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name) %> = O.<%= j_escape_string(entity.primary_key.sql.quoted_column_name) %>";
  }

<% end -%>
<% if entity.sync.support_remove? -%>
  @javax.annotation.Nonnull
  @java.lang.Override
  public String getSqlToDirectlyDelete<%= fn %>( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    return
<% if entity.transaction_time? -%>
      "UPDATE O\n" +
      "SET\n" +
      "  <%= j_escape_string(entity.attribute_by_name(:DeletedAt).sql.quoted_column_name) %> = GETDATE()\n" +
<% else -%>
      "DELETE O\n" +
<% end -%>
      "FROM <%= j_escape_string( entity.sql.qualified_table_name ) %> O \n" +
      "JOIN ( \n" +
      getSqlToRetrieve<%= fn %>ListToRemove( mappingSourceCode ) + "\n" +
      ") M ON M.<%= j_escape_string(entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name) %> = O.<%= j_escape_string(entity.primary_key.sql.quoted_column_name) %>";
  }

  @javax.annotation.Nonnull
  @java.lang.Override
  public String getSqlToMarkDeleted<%= fn %>AsSynchronized( @javax.annotation.Nonnull final String mappingSourceCode )
  {
    return
      "UPDATE O\n" +
      "SET\n" +
      "  <%= j_escape_string("#{entity.sync.master_entity.attribute_by_name(:MasterSynchronized).sql.quoted_column_name} = #{entity.sql.dialect.true_sql}") -%>\n" +
      "FROM <%= j_escape_string( table ) %> O \n" +
      "JOIN ( \n" +
      getSqlToRetrieve<%= fn %>ListToRemove( mappingSourceCode ) + "\n" +
      ") M ON M.<%= j_escape_string(entity.sync.master_entity.attribute_by_name(entity.root_entity.name).sql.quoted_column_name) %> = O.<%= j_escape_string(entity.primary_key.sql.quoted_column_name) %>";
  }
<% end -%>
<% end -%>

  @javax.annotation.Nonnull
  protected String getSqlToRetrieve<%= fn %>ListToUpdate( @javax.annotation.Nonnull final String mappingSourceCode )
  {
<% if recursive_attributes.size <= 1 -%>
    return
<%= cte -%>
      "SELECT <%= j_escape_string( attr_select ) -%> " +
      "FROM <%= j_escape_string( table ) %> M " +
<%= joins -%>
      "WHERE <%= j_escape_string( criteria ) %><%= j_escape_string( create_criteria ) %> " +
      "<%= j_escape_string( order_by ) %>";
<% else -%>
    /*
<%= cte -%>
      "SELECT <%= attr_select -%> " +
      "FROM <%= table %> M " +
<%= joins -%>
      "WHERE <%= criteria %><%= create_criteria %> " +
      "<%= order_by %>";
     */
    throw new IllegalStateException( "Override getSqlToRetrieve<%= fn %>ListToUpdate() due to multiple recursive attributes." );
<% end -%>
  }

<% if entity.sync.support_remove? -%>
  @javax.annotation.Nonnull
  protected String getSqlToRetrieve<%= fn %>ListToRemove( @javax.annotation.Nonnull final String mappingSourceCode )
  {
<% if recursive_attributes.size <= 1 -%>
{'fraction_non_alphanumeric': 0.17204438006399134, 'fraction_numerical': 0.0011779500485506438, 'mean_word_length': 3.893060207181245, 'pattern_counts': {'":': 0, '<': 703, '<?xml version=': 0, '>': 693, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2490363', 'n_tokens_mistral': 22658, 'n_tokens_neox': 21446, 'n_words': 3470}