You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@velocity.apache.org by Andrew Smith <as...@wpequity.com> on 2002/01/11 16:50:58 UTC

LDAP Context?

I've seen passing references to an LDAP Context for use with Velocity.

Does such a thing exist?

-a.




--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: LDAP Context?

Posted by Bill Burton <bi...@progress.com>.
Hello Andrew,

When I first started experimenting with Velocity, it took me a little
while to get a grasp of how to wrap different kinds of objects to make it
as easy as possible for template developers while still providing
sufficient flexibility.  

So, here's a partially implemented context tool that should be close to
what you want.  You will need to add try ... catch blocks and error
checking.  It connects and disconnects from the LDAP server on each search
request which keeps it simple but less efficient.  You may want to look at
using LDAPConnection.clone() so multiple requests can share a single
connection.

I looked at the docs for the Netscape LDAP SDK for Java and as a result,
was able to get this much closer to being useful as your code example
didn't show how to obtain the attributes and their values.

package xxx;
import java.util.*;
import netscape.ldap.*;

public class LDAPSearch {

    private String m_host = "localhost";
    private int m_port = 389;
    private String m_root = "o=myRootDN";
    private String m_search;

    public void setHost(String host) {
        m_host = host;
    }

    public void setPort(int port) {
        m_port = port;
    }

    public void setSearchRoot(String root) {
        m_root = root;
    }

    public void setSearch(String search) {
        m_search = search;
    }
 
    /**
     * @return ArrayList of matched entries each of which is a HashMap 
     *         of attribute names with an associated ArrayList of one 
     *         or more values.
     */
     public ArrayList getSearch() {
        // note: add try ... catch's as required
        LDAPConnection ld = new LDAPConnection();
        ld.connect(m_host, m_port);
        LDAPSearchConstraints cons = new LDAPSearchConstraints();
        LDAPSearchResults results = 
            ld.search(m_root, LDAPConnection.SCOPE_SUB, 
                      m_search, null, false, cons);
        ArrayList entries = new ArrayList(results.getCount());
        // Loop on matched entries adding to an ArrayList
        while( results.hasMoreElements() ) {
            LDAPEntry findEntry = results.next();
            LDAPAttributeSet findAttrs = findEntry.getAttributeSet();
            Enumeration enumAttrs = findAttrs.getAttributes();
            HashMap attrs = new HashMap();
            // Loop on attributes copying to a HashMap
            while( enumAttrs.hasMoreElements() ) {
                LDAPAttribute anAttr =
                    (LDAPAttribute)enumAttrs.nextElement();
                ArrayList values = new ArrayList();
                Enumeration enumValues = anAttr.getStringValues();
                // Loop on values copying to an ArrayList
                while( enumValues.hasMoreEntries() ) {
                    values.add(enumValues.nextElement());
                }
                if (values.size() == 0)  // ensure at least one value
                    values.add("");
                // Save attribute name and value(s)
                attrs.put(anAttr.getName(), values);
            }
            entries.add(attrs);
        }
        ld.disconnect();
        return entries;
    }
}

In your Java code, do something like:
    LDAPSearch lds = new LDAPSearch();
    lds.setHost(...);
    lds.setPort(...);
    lds.setSearchRoot("o=myRoot");
    lds.setSearch("employer=Ford");  // optional: maybe form input, etc.
    context.put("ldapsearch", lds);  
    // OR following and use #foreach ($person in $ldapentries)
    context.put("ldapentries", lds.getEntries());

You can access the result in your Velocity template like this:
    #set(ldapsearch.Search = "employer=Ford")  ## only if not set in Java
    #foreach ($person in $ldapsearch.Entries)
        First value in 'name' attribute: $person.name.get(0)
        Number of values in 'name' attribute: $person.name.size()
        ## Return all attributes with all associated values
        Attributes and values
        #foreach ($attr in $person.keySet())
            #set($values = $person.get($attr))
            Name: $attr;  size: $values.size();  value(s): #*
            *##foreach ($value in $values)#*
                *##if ($velocityCount > 1), #end$value#*
            *##end
        #end
    #end

Hope this helps,
-Bill

Andrew Smith wrote:
> 
> > If it were me, I would agree on a datastore-neutral 'API' or 'data contract'
> > (agreement on what data is needed and what it is named in the context)
> 
> OK, fair enough. Let's assume that I have a little class called
> LDAPSearch that takes RFC1558 filters and returns an iterator over some
> result set.
> 
> If I put an LDAPSearch object into my context is there ever a way to
> give the template author the ability to call that method and iterate
> over the results? It seems to me that this must all be done in the setup
> code and once you call template.merge your context is pretty much shot.
> 
> e.g. a template might look like this
> 
> ------------------------------------
> $ldapsearch.search("employer=Ford")
> 
> #foreach ($person in $searchResults)
>   carmaker: $person.get('name')
> #end
> 
> $ldapsearch.search("employer=Rawlings")
> 
> #foreach ($person in $searchResults)
>   glovemaker: $person.get('name')
> #end
> 
> etc...
> ------------------------------------
> 
> How would this work in Velocity? Would you need to preload the result
> sets into the context? I guess the question boils down to this: does the
> template author have any influence over the context object given to him?
> 
> -a.
> 
> >
> > Then you can use a Context that implements an LDAP backend to get the data.
> >
> > In the future, when you switch to some other datastore, or want to modify
> > the data or fetch somehow, you can do that w/o touching the templates.
> >

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Manipulating a Context after the Merge (was: Re: LDAP Context?)

Posted by "Geir Magnusson Jr." <ge...@earthlink.net>.
On 1/11/02 4:52 PM, "Andrew Smith" <as...@wpequity.com> wrote:

>> If it were me, I would agree on a datastore-neutral 'API' or 'data contract'
>> (agreement on what data is needed and what it is named in the context)
> 
> OK, fair enough. Let's assume that I have a little class called
> LDAPSearch that takes RFC1558 filters and returns an iterator over some
> result set. 
> 
> If I put an LDAPSearch object into my context is there ever a way to
> give the template author the ability to call that method and iterate
> over the results? It seems to me that this must all be done in the setup
> code and once you call template.merge your context is pretty much shot.
> 
> e.g. a template might look like this
> 
> ------------------------------------
> $ldapsearch.search("employer=Ford")
> 
> #foreach ($person in $searchResults)
> carmaker: $person.get('name')
> #end
> 
> $ldapsearch.search("employer=Rawlings")
> 
> #foreach ($person in $searchResults)
> glovemaker: $person.get('name')
> #end
> 
> etc...
> ------------------------------------
> 

That's better - you still tied it to ldap explicitly, but that's minor.

That would work fine though (forgetting the tying part)

> How would this work in Velocity? Would you need to preload the result
> sets into the context?

That's up to you - you don't have to do that, so the template author can
specify what they want, if you feel that's appropriate.

This is a much better approach, as you now can change the source of the
data....

> I guess the question boils down to this: does the
> template author have any influence over the context object given to him?

Yes - it's really up to you - the above would work fine, and the template
designer could call for data as he/she needs it...

-- 
Geir Magnusson Jr.                                     geirm@optonline.net
System and Software Consulting
"They that can give up essential liberty to obtain a little temporary safety
deserve neither liberty nor safety." - Benjamin Franklin



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Manipulating a Context after the Merge (was: Re: LDAP Context?)

Posted by Andrew Smith <as...@wpequity.com>.
> If it were me, I would agree on a datastore-neutral 'API' or 'data contract'
> (agreement on what data is needed and what it is named in the context)

OK, fair enough. Let's assume that I have a little class called
LDAPSearch that takes RFC1558 filters and returns an iterator over some
result set. 

If I put an LDAPSearch object into my context is there ever a way to
give the template author the ability to call that method and iterate
over the results? It seems to me that this must all be done in the setup
code and once you call template.merge your context is pretty much shot.

e.g. a template might look like this

------------------------------------
$ldapsearch.search("employer=Ford")

#foreach ($person in $searchResults)
  carmaker: $person.get('name')
#end

$ldapsearch.search("employer=Rawlings")

#foreach ($person in $searchResults)
  glovemaker: $person.get('name')
#end

etc...
------------------------------------  

How would this work in Velocity? Would you need to preload the result
sets into the context? I guess the question boils down to this: does the
template author have any influence over the context object given to him?

-a.


> 
> Then you can use a Context that implements an LDAP backend to get the data.
> 
> In the future, when you switch to some other datastore, or want to modify
> the data or fetch somehow, you can do that w/o touching the templates.
> 
> > 



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: LDAP Context?

Posted by "Geir Magnusson Jr." <ge...@earthlink.net>.
On 1/11/02 3:04 PM, "Andrew Smith" <as...@wpequity.com> wrote:

> On Fri, 2002-01-11 at 11:21, Geir Magnusson Jr. wrote:
>> It was really a discussion point - the Context was designed to abstract the
>> backing store, so you can implement whatever you want.
>> 
>> -- 
>> Geir Magnusson Jr.                                     geirm@optonline.net
> 
> Thanks for clearing that up. I was under the impression that somehow a
> Context object could provide access to an LDAP database -- but clearly
> Context is just an interface and the LDAP backend is just a possible
> implementation.
> 
> Real question follows:
> 
> As a Velocity newbie, I'm having a hard time figuring out where to draw
> the line on what to include in my Context objects.
> 
> I want to produce some reports based on arbitrary LDAP queries. How much
> of the LDAP API should I be trying to wrap and how much can I expose to
> the template writer?

If it were me, I would agree on a datastore-neutral 'API' or 'data contract'
(agreement on what data is needed and what it is named in the context)

Then you can use a Context that implements an LDAP backend to get the data.

In the future, when you switch to some other datastore, or want to modify
the data or fetch somehow, you can do that w/o touching the templates.

> 
> As an example the following code is roughly what is required to search a
> directory using the Netscape LDAP classes. Can I use this same sequence
> in VTL or do I need to wrap it up a little tighter? I would like to just
> put an LDAPConnection object in the Context and let the template author
> worry about the rest.
> 
> LDAPConnection ld = new LDAPConnection();
> ld.connect("ldaphost.mydomain.com", 389);
> LDAPSearchConstraints cons = new LDAPSearchConstraints();
> LDAPSearchResults sres = ld.search("o=myrootdn",
> LDAPConnection.SCOPE_SUB,
> filter,
> null,
> false,
> cons);    
> while (sres.hasMoreElements())
> "process the results"
> 

I know it's more work, but I would wrap it.

Look at all of the 'stuff' the template author has to deal with - fqdn,
port, etc...

By making it so open and visible in the template, you've now pushed the
duties of the Model right into the View - so your view is now tightly bound
to a specific data source, which I would be will either trip you up later,
or cost you time and money when things change.


-- 
Geir Magnusson Jr.                                     geirm@optonline.net
System and Software Consulting
"They that can give up essential liberty to obtain a little temporary safety
deserve neither liberty nor safety." - Benjamin Franklin



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: LDAP Context?

Posted by Andrew Smith <as...@wpequity.com>.
On Fri, 2002-01-11 at 11:21, Geir Magnusson Jr. wrote:
> It was really a discussion point - the Context was designed to abstract the
> backing store, so you can implement whatever you want.
> 
> -- 
> Geir Magnusson Jr.                                     geirm@optonline.net

Thanks for clearing that up. I was under the impression that somehow a
Context object could provide access to an LDAP database -- but clearly
Context is just an interface and the LDAP backend is just a possible
implementation.

Real question follows:

As a Velocity newbie, I'm having a hard time figuring out where to draw
the line on what to include in my Context objects. 

I want to produce some reports based on arbitrary LDAP queries. How much
of the LDAP API should I be trying to wrap and how much can I expose to
the template writer?

As an example the following code is roughly what is required to search a
directory using the Netscape LDAP classes. Can I use this same sequence
in VTL or do I need to wrap it up a little tighter? I would like to just
put an LDAPConnection object in the Context and let the template author
worry about the rest. 

LDAPConnection ld = new LDAPConnection();
ld.connect("ldaphost.mydomain.com", 389);
LDAPSearchConstraints cons = new LDAPSearchConstraints();
LDAPSearchResults sres = ld.search("o=myrootdn",
					LDAPConnection.SCOPE_SUB,
					filter,
					null,
					false,
					cons);	
while (sres.hasMoreElements())
	"process the results"

 
-a.






--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: LDAP Context?

Posted by "Geir Magnusson Jr." <ge...@earthlink.net>.
On 1/11/02 10:50 AM, "Andrew Smith" <as...@wpequity.com> wrote:

> I've seen passing references to an LDAP Context for use with Velocity.
> 
> Does such a thing exist?


It was really a discussion point - the Context was designed to abstract the
backing store, so you can implement whatever you want.

-- 
Geir Magnusson Jr.                                     geirm@optonline.net
System and Software Consulting
"They that can give up essential liberty to obtain a little temporary safety
deserve neither liberty nor safety." - Benjamin Franklin



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>