class ActiveLdap::Adapter::Jndi

def add(dn, entries, options={})

def add(dn, entries, options={})
  super do |_dn, _entries|
    info = {:dn => _dn, :attributes => _entries}
    execute(:add, info, _dn, parse_entries(_entries))
  end
end

def bind_as_anonymous(options={})

def bind_as_anonymous(options={})
  super do
    execute(:bind_as_anonymous, :name => "bind: anonymous")
    true
  end
end

def connect(options={})

def connect(options={})
  super do |host, port, method|
    uri = construct_uri(host, port, method == :ssl)
    with_start_tls = method == :start_tls
    follow_referrals = follow_referrals?(options)
    info = {
      :uri => uri,
      :with_start_tls => with_start_tls,
      :follow_referrals => follow_referrals,
    }
    [
      log("connect", info) {
        JndiConnection.new(host,
                           port,
                           method,
                           @timeout,
                           follow_referrals)
      },
      uri,
      with_start_tls,
    ]
  end
end

def connecting?

def connecting?
  super and @connection.bound?
end

def delete(targets, options={})

def delete(targets, options={})
  super do |target|
    execute(:delete, {:dn => target}, target)
  end
end

def ensure_method(method)

def ensure_method(method)
  method ||= "plain"
  normalized_method = method.to_s.downcase.to_sym
  return METHOD[normalized_method] if METHOD.has_key?(normalized_method)
  available_methods = METHOD.keys.collect {|m| m.inspect}.join(", ")
  format = _("%s is not one of the available connect methods: %s")
  raise ConfigurationError, format % [method.inspect, available_methods]
end

def ensure_mod_type(type)

def ensure_mod_type(type)
  case type
  when :replace, :add
    type
  when :delete
    :remove
  else
    raise ArgumentError, _("unknown type: %s") % type
  end
end

def ensure_scope(scope)

def ensure_scope(scope)
  scope_map = {
    :base => JndiConnection::Scope::OBJECT,
    :one => JndiConnection::Scope::ONE_LEVEL,
    :sub => JndiConnection::Scope::SUBTREE,
  }
  value = scope_map[scope || :sub]
  if value.nil?
    available_scopes = scope_map.keys.inspect
    format = _("%s is not one of the available LDAP scope: %s")
    raise ArgumentError, format % [scope.inspect, available_scopes]
  end
  value
end

def execute(method, info=nil, *args, &block)

def execute(method, info=nil, *args, &block)
  name = (info || {}).delete(:name) || method
  log(name, info) {@connection.send(method, *args, &block)}
rescue JndiConnection::CommunicationException, JndiConnection::ServiceUnavailableException => e
  disconnect! if connecting?
  raise ActiveLdap::ConnectionError.new(e.getMessage())
rescue JndiConnection::NamingException
  if /\[LDAP: error code (\d+) - ([^\]]+)\]/ =~ $!.to_s
    message = $2
    klass = LdapError::ERRORS[Integer($1)]
    klass ||= ActiveLdap::LdapError
    raise klass, message
  elsif /LDAP response read timed out/ =~ $!.to_s
    disconnect! if connecting?
    raise Timeout::Error.new($!.to_s)
  end
  raise
end

def modify(dn, entries, options={})

def modify(dn, entries, options={})
  super do |_dn, _entries|
    info = {:dn => _dn, :attributes => _entries}
    execute(:modify, info, _dn, parse_entries(_entries))
  end
end

def modify_rdn(dn, new_rdn, delete_old_rdn, new_superior, options={})

def modify_rdn(dn, new_rdn, delete_old_rdn, new_superior, options={})
  super do |_dn, _new_rdn, _delete_old_rdn, _new_superior|
    info = {
      :name => "modify: RDN",
      :dn => _dn,
      :new_rdn => _new_rdn,
      :new_superior => _new_superior,
      :delete_old_rdn => _delete_old_rdn
    }
    _new_rdn = "#{_new_rdn},#{_new_superior}" if _new_superior
    execute(:modify_rdn, info, _dn, _new_rdn, _delete_old_rdn)
  end
end

def parse_entries(entries)

def parse_entries(entries)
  result = []
  entries.each do |type, key, attributes|
    mod_type = ensure_mod_type(type)
    binary = schema.attribute(key).binary?
    attributes.each do |name, values|
      real_binary = binary
      if values.any? {|value| Ldif::Attribute.binary_value?(value)}
        real_binary = true
      end
      result << JndiConnection::ModifyRecord.new(mod_type, name,
                                                 values, real_binary)
    end
  end
  result
end

def sasl_bind(bind_dn, options={})

def sasl_bind(bind_dn, options={})
  super do |_bind_dn, mechanism, quiet|
    info = {
      :name => "bind: SASL",
      :dn => _bind_dn,
      :mechanism => mechanism
    }
    execute(:sasl_bind, info, _bind_dn, mechanism, quiet)
    true
  end
end

def scope_name(scope)

def scope_name(scope)
  {
    JndiConnection::Scope::OBJECT => :base,
    JndiConnection::Scope::ONE_LEVEL => :one,
    JndiConnection::Scope::SUBTREE => :sub,
  }[scope]
end

def search(options={}, &block)

def search(options={}, &block)
  super(options) do |search_options|
    scope = search_options[:scope]
    info = search_options.merge(scope: scope_name(scope))
    execute(:search, info, search_options, &block)
  end
end

def simple_bind(bind_dn, options={})

def simple_bind(bind_dn, options={})
  super do |_bind_dn, password|
    info = {:name => "bind", :dn => _bind_dn}
    execute(:simple_bind, info, _bind_dn, password)
    true
  end
end

def unbind(options={})

def unbind(options={})
  super do
    execute(:unbind)
  end
end