It's still not completely clear what you're asking, but it sounds like
you're searching to retrieve a subscriber entry, and you want to join
that with the associated bundle, subscription, and profile entries.
Further, it sounds like you've got an attribute (let's assume the
attribute is cardNumber; card_number isn't a valid LDAP attribute name
since underscores aren't allowed) in the subscriber entry whose value
matches the subscriberNumber attribute in the bundle, subscription, and
profile entries.
If that's the case, then it should be a pretty simple matter. You
shouldn't use a nested join for this because even though you want to
join with three different kinds of entries, you want to join each of
them using information contained the subscriber entry. A nested join is
primarily useful in the case where you have to join with other joined
entries instead of joining with the original search result entry.
Here's some code to get you started. Since you didn't provide me with
all the details about the structure of the entries you're working with,
you'll have to edit it as laid out in the comments.
// Create a search request to retrieve subscriber entries.
//
// NOTE: If this search will match a large number of entries,
// then you should probably use something like the simple
// paged results control to retrieve matching entries in
// batches rather than trying to have them all returned in
// a single search. Or at least use a search result
// listener so that the client doesn't have to hold all of
// the matching entries in memory simultaneously.
SearchRequest searchRequest = new SearchRequest(
"ospobject=subscriber,dc=alcatel,dc=com", SearchScope.SUB,
Filter.createPresenceFilter("cardNumber"),
"name", "credit", "cardNumber");
// Create a join rule that will match entries that have a
// subscriberNumber value that is the same as the cardNumber
// value from each entry that matches the search request.
JoinRule joinRule = JoinRule.createEqualityJoin("cardNumber",
"subscriberNumber", false);
// Define the join base DN, which is where we will search for
// the entries to be joined. In this case, we want to join with
// three different types of entries, and those entries exist in
// different subtrees. However, each of those subtrees is below
// "dc=alcatel,dc=com", so we'll use that as the common search
// base DN for the join processing.
JoinBaseDN joinBaseDN =
JoinBaseDN.createUseCustomBaseDN("dc=alcatel,dc=com");
// Next, define a filter that will match only bundle,
// subscription, and profile entries. This may not be needed in
// all cases, but it will be if there are other kinds of entries
// that might have a subscriberNumber attribute that you don't
// want to include in the join. I don't know what the real
// object class names you're using for bundle, subscriber, and
// profile entries, so you should replace what I've used here
// with the appropriate names.
Filter additionalJoinFilter = Filter.createORFilter(
Filter.createEqualityFilter("objectClass", "bundleOC"),
Filter.createEqualityFilter("objectClass", "subscriptionOC"),
Filter.createEqualityFilter("objectClass", "profileOC"));
// Define the set of attributes that we want to be returned.
// Since we're returning three different types of entries, then
// we should include all attributes we want to get from all three
// types of entries. Also include the objectClass attribute so
// that we can use that to determine the type of each joined
// entry.
String[] attributesInJoinedEntries =
{
"bundleName",
"bundleCredit",
"subscriptionName",
"subscriptionCredit",
"profileName",
"objectClass"
};
// Define the behavior that the search should use for entries
// that match the search criteria (in this case, for entries that
// are subscribers that have a cardNumber) but for which there
// aren't any associated bundle, subscription, or profile
// entries. A requireMatch value of false indicates that we
// should return matching subscriber entries even if there aren't
// any associated bundle, subscription, or profile entries. A
// requireMatch value of true indicates that we should only
// return subscriber entries that are joined with at least one
// bundle, subscription, or profile.
boolean requireMatch = false;
// Create the join request value and use that to create the join
// request control that is assigned to the search.
JoinRequestValue joinValue = new JoinRequestValue(
joinRule,
joinBaseDN,
SearchScope.SUB,
DereferencePolicy.NEVER,
0, // No size limit
additionalJoinFilter,
attributesInJoinedEntries,
requireMatch,
null); // No nested join.
searchRequest.addControl(new JoinRequestControl(joinValue));
// Process the search and iterate through the matching entries.
SearchResult searchResult = connection.search(searchRequest);
for (SearchResultEntry subscriberEntry :
searchResult.getSearchEntries())
{
// Get the attributes we want from the subscriber entry.
String subscriberName =
subscriberEntry.getAttributeValue("subscriberName");
String subscriberCredit =
subscriberEntry.getAttributeValue("subscriberCredit");
String subscriberCardNumber =
subscriberEntry.getAttributeValue("cardNumber");
// Get the join result that will link the subscriber entry with
// any associated bundle, subscription, and/or profile entries.
JoinResultControl joinResultControl =
JoinResultControl.get(subscriberEntry);
if (joinResultControl != null)
{
for (JoinedEntry joinedEntry :
joinResultControl.getJoinResults())
{
if (joinedEntry.hasAttributeValue("objectClass",
"bundleOC"))
{
// It's a bundle entry.
String bundleName =
joinedEntry.getAttributeValue("bundleName");
String bundleCredit =
joinedEntry.getAttributeValue("bundleCredit");
}
else if (joinedEntry.hasAttributeValue("objectClass",
"subscriptionOC"))
{
// It's a subscription entry.
String subscriptionName =
joinedEntry.getAttributeValue("subscriptionName");
String subscriptionCredit =
joinedEntry.getAttributeValue("subscriptionCredit");
}
else if (joinedEntry.hasAttributeValue("objectClass",
"profileOC"))
{
// It's a profile entry.
String profileName =
joinedEntry.getAttributeValue("profileName");
}
}
}
}
On 09/29/2015 10:22 AM, SINGH, HIMANSHU KUMAR (HIMANSHU KUMAR) wrote:
> Hello Neil,
>
>
>
> Thank you for your response and pardon me for the non-technical jargon I used. I will be as precise as possible in this text.
>
>
>
> We have to replace an RDBMS database(specifically Oracle) with LDAP; hence the non-LDAP terms. Please excuse me for that too.
>
> The risks, limitations and advantages are well understood; the decision has been made and design is in progress.
>
>
>
> THE JOIN PROBLEM GENERALIZED WITH AN EXAMPLE:
>
>
>
> - We have 4 objects, each made up of a few attributes and represented by a unique DN.
>
>
>
> Dn: ospobject=subscriber,dc=alcatel,dc=com
>
>
> Card_number
>
>
> Name
>
>
> Credit
>
>
>
>
> Dn: ospobject=bundle,dc=alcatel,dc=com
>
>
> Bundle_name
>
>
> Bundle_credit
>
>
> Expiry
>
>
> Subscriber_number
>
>
>
>
> Dn: ospobject=subscription,dc=alcatel,dc=com
>
>
> Subscription_name
>
>
> Expiry
>
>
> Subscriber_number
>
>
>
>
> Dn: ospobject=profile,dc=alcatel,dc=com
>
>
> Profile_name
>
>
> Profile_validity
>
>
> Subscriber_number
>
>
>
>
> **there are a huge number of entries in these objects. It is not possible to combine all these tables in a single table.
>
>
>
> - Our objective is to fetch all of a subscriber’s information, including all his bundles, subscriptions and profile in a single search.
>
> Our JOIN conditions are:
>
> 1. Subscriber.card_number = bundle.Subscriber_number
>
> 2. Subscriber.card_number = subscription.Subscriber_number
>
> 3. Subscriber.card_number = profile.Subscriber_number
>
>
>
>
>
>
>
> What we have tried:
>
> We came across the documentation of the commercial version of the LDAP SDK. We are trying to see if the JoinRequestControl can solve our problem.
>
> Below is an abstract of what we have tried so far:
>
>
>
> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> //The attributes to be fetched
> String args_subscriber[] ={"name","credit",”card_number”}; //attributes to be fetched from the subscriber object
> String args_bundle[] ={"Bundle_name","Bundle_credit"}; //attributes to be fetched from the bundle object
>
> String args_subscription[]={"Subscription_name","Subscription_credit"}; //attributes to be fetched from the subscription object
>
> String args_profile[] ={"Profile_name”}; //attributes to be fetched from the profile object
>
>
>
>
>
> //Define the SearchRequest on the ‘Subscriber’ object
>
> SearchRequest searchRequest = new SearchRequest(“ospobject=subscriber,dc=alcatel,dc=com”, SearchScope.SUB, Filter.create("card_number=*"),args_subscriber); //the ‘subscriber’ DN.
>
> .
>
> .
>
> .
>
>
>
> //define the nested JoinRequestValue for the join between ‘subscriber’ and ‘profile’ objects
> JoinRequestValue nestedJoinval2 = new JoinRequestValue(
> JoinRule.createEqualityJoin("card_number”, ”subscriber_number", false),
>
> JoinBaseDN.createUseCustomBaseDN("ospobject=profile,dc=alcatel,dc=com"), //the ‘profile’ object DN.
> SearchScope.SUB,
> DereferencePolicy.NEVER,
> null,
> null,
> args_subscription,
>
> true, null);
>
> .
>
> .
>
> .
>
> //define the nested JoinRequestValue for the join between ‘subscriber’ and ‘subscription’ objects
>
> //Also add the nested JoinRequestValue defined above, to this JoinRequestValue
> JoinRequestValue nestedJoinval1 = new JoinRequestValue(
> JoinRule.createEqualityJoin("card_number”, ”subscriber_number", false),
>
> JoinBaseDN.createUseCustomBaseDN("ospobject=subscription,dc=alcatel,dc=com"), //the ‘subscription’ object DN.
> SearchScope.SUB,
> DereferencePolicy.NEVER,
> null,
> null,
> args_subscription,
>
> true, nestedJoinval2);
>
> .
>
> .
>
> .
>
> //define the nested JoinRequestValue for the join between ‘subscriber’ and ‘bundle’ objects
>
> //Also add the JoinRequestControl to the SearchRequest
> searchRequest.addControl(new JoinRequestControl(new JoinRequestValue(
> JoinRule.createEqualityJoin("card_number", "subscriber_number", false),
> JoinBaseDN.createUseCustomBaseDN("ospobject=bundle,dc=alcatel,dc=com "), //the ‘bundle’ object DN.
> SearchScope.SUB,
> DereferencePolicy.NEVER,
> null,
> null,
> args_bundle,
>
> true, nestedJoinval1)));
>
>
>
> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>
>
>
>
> The intention of the nested join is to join the subscriber and subscription objects.
>
> But it seems that the nested join works only on the DN specified in its corresponding parent join.
>
>
>
> I can’t find a way of specifying the nested join to work on the Join results of the parent join.
>
>
>
> Is my understanding correct?
>
> Do I have a way out?
>
>
>
>
>
>
>
> With Best Regards,
>
> Himanshu
>
>
>
> -----Original Message-----
>
> From: nei...@un... [mailto:nei...@un...]
>
> Sent: Monday, September 28, 2015 7:43 PM
>
> To: lda...@li...; SINGH, HIMANSHU KUMAR (HIMANSHU KUMAR)
>
> Subject: Re: [ldap-sdk-discuss] LDAP SDK - multiple joins not supported??
>
>
>
> It's not really clear what you're asking. Could you provide a specific example that illustrates what you're trying to do? And could you please use LDAP terminology, since LDAP doesn't have primary keys or tables. Do you mean DNs and entries?
>
>
>
>
>
> Neil
>
>
>
>
>
> -----Original Message-----
>
> From: "SINGH, HIMANSHU KUMAR (HIMANSHU KUMAR)" <him...@al...>
>
> To: "lda...@li..." <lda...@li...>
>
> Sent: Mon, 28 Sep 2015 9:05 AM
>
> Subject: [ldap-sdk-discuss] LDAP SDK - multiple joins not supported??
>
>
>
> Hello LDAP SDK teams,
>
>
>
> I am trying to implement a multi-join using the SDK.
>
> My problem is that I have a "master" entry with 4 different attributes.
>
> All 4 of them refer to the PK attribute of 4 other tables.
>
> These other tables are not directly related to each other.
>
>
>
> I have to implement a join on all 5 tables in a single search request.
>
>
>
> The nestedJoin feature of the JoinRequestControl comes close but cannot completely solve this problem.
>
>
>
> Any ideas??
>
>
>
>
>
> - Himanshu
>
>
>
>
|