libspring-ldap-java-1.3.1.RELEASE.orig/0002777000000000000000000000000011550465534014264 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/docs/0002755000000000000000000000000011550465534015210 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/0002755000000000000000000000000011550465534016462 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/configuration.xml0000644000000000000000000004340411131412553022042 0ustar Configuration ContextSource Configuration There are several properties in AbstractContextSource (superclass of DirContextSource and LdapContextSource) that can be used to modify its behaviour. LDAP Server URLs The URL of the LDAP server is specified using the url property. The URL should be in the format ldap://myserver.example.com:389. For SSL access, use the ldaps protocol and the appropriate port, e.g. ldaps://myserver.example.com:636 It is possible to configure multiple alternate LDAP servers using the urls property. In this case, supply all server urls in a String array to the urls property. Base LDAP path It is possible to specify the root context for all LDAP operations using the base property of AbstractContextSource. When a value has been specified to this property, all Distinguished Names supplied to and received from LDAP operations will be relative to the LDAP path supplied. This can significantly simplify working against the LDAP tree; however there are several occations when you will need to have access to the base path. For more information on this, please refer to DirContext Authentication When DirContext instances are created to be used for performing operations on an LDAP server these contexts often need to be authenticated. There are different options for configuring this using Spring LDAP, described in this chapter. This section refers to authenticating contexts in the core functionality of the ContextSource - to construct DirContext instances for use by LdapTemplate. LDAP is commonly used for the sole purpose of user authentication, and the ContextSource may be used for that as well. This process is discussed in . Authenticated contexts are created for both read-only and read-write operations by default. You specify userDn and password of the LDAP user to be used for authentication on the ContextSource. The userDn needs to be the full Distinguished Name (DN) of the user from the root of the LDAP tree, regardless of whether a base LDAP path has been supplied to the ContextSource. Some LDAP server setups allow anonymous read-only access. If you want to use anonymous Contexts for read-only operations, set the anonymousReadOnly property to true. Custom DirContext Authentication Processing The default authentication mechanism used in Spring LDAP is SIMPLE authentication. This means that in the user DN (as specified to the userDn property) and the credentials (as specified to the password) are set in the Hashtable sent to the DirContext implementation constructor. There are many occasions when this processing is not sufficient. For instance, LDAP Servers are commonly set up to only accept communication on a secure TLS channel; there might be a need to use the particular LDAP Proxy Auth mechanism, etc. It is possible to specify an alternative authentication mechanism by supplying a DirContextAuthenticationStrategy implementation to the ContextSource in the configuration. TLS Spring LDAP provides two different configuration options for LDAP servers requiring TLS secure channel communication: DefaultTlsDirContextAuthenticationStrategy and ExternalTlsDirContextAuthenticationStrategy. Both these implementations will negotiate a TLS channel on the target connection, but they differ in the actual authentication mechanism. Whereas the DefaultTlsDirContextAuthenticationStrategy will apply SIMPLE authentication on the secure channel (using the specified userDn and password), the ExternalDirContextAuthenticationStrategy will use EXTERNAL SASL authentication, applying a client certificate configured using system properties for authentication. Since different LDAP server implementations respond differently to explicit shutdown of the TLS channel (some servers require the connection be shutdown gracefully; others do not support it), the TLS DirContextAuthenticationStrategy implementations support specifying the shutdown behavior using the shutdownTlsGracefully parameter. If this property is set to false (the default), no explicit TLS shutdown will happen; if it is true, Spring LDAP will try to shutdown the TLS channel gracefully before closing the target context. When working with TLS connections you need to make sure that the native LDAP Pooling functionality is turned off. As of release 1.3, the default setting is off. For earlier versions, simply set the pooled property to false. This is particularly important if shutdownTlsGracefully is set to false. However, since the TLS channel negotiation process is quite expensive, great performance benefits will be gained by using the Spring LDAP Pooling Support, described in . Custom Principal and Credentials Management While the user name (i.e. user DN) and password used for creating an authenticated Context are static by default - the ones set on the ContextSource on startup will be used throughout the lifetime of the ContextSource - there are however several cases in which this is not the desired behaviour. A common scenario is that the principal and credentials of the current user should be used when executing LDAP operations for that user. The default behaviour can be modified by supplying a custom AuthenticationSource implementation to the ContextSource on startup, instead of explicitly specifying the userDn and password. The AuthenticationSource will be queried by the ContextSource for principal and credentials each time an authenticated Context is to be created. If you are using Spring Security you can make sure the principal and credentials of the currently logged in user is used at all times by configuring your ContextSource with an instance of the SpringSecurityAuthenticationSource shipped with Spring Security. The Spring bean definition for a SpringSecurityAuthenticationSource <beans> ... <bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource"> <property name="url" value="ldap://localhost:389" /> <property name="base" value="dc=example,dc=com" /> <property name="authenticationSource" ref="springSecurityAuthenticationSource" /> </bean> <bean id="springSecurityAuthenticationSource" class="org.springframework.security.ldap.SpringSecurityAuthenticationSource" /> ... </beans> We don't specify any userDn or password to our ContextSource when using an AuthenticationSource - these properties are needed only when the default behaviour is used. When using the SpringSecurityAuthenticationSource you need to use Spring Security's LdapAuthenticationProvider to authenticate the users against LDAP. Default Authentication When using SpringSecurityAuthenticationSource, authenticated contexts will only be possible to create once the user is logged in using Spring Security. To use default authentication information when no user is logged in, use the DefaultValuesAuthenticationSourceDecorator: Configuring a DefaultValuesAuthenticationSourceDecorator <beans> ... <bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource"> <property name="url" value="ldap://localhost:389" /> <property name="base" value="dc=example,dc=com" /> <property name="authenticationSource" ref="authenticationSource" /> </bean> <bean id="authenticationSource" class="org.springframework.ldap.authentication.DefaultValuesAuthenticationSourceDecorator"> <property name="target" ref="springSecurityAuthenticationSource" /> <property name="defaultUser" value="cn=myDefaultUser" /> <property name="defaultPassword" value="pass" /> </bean> <bean id="springSecurityAuthenticationSource" class="org.springframework.security.ldap.SpringSecurityAuthenticationSource" /> ... </beans> Native Java LDAP Pooling The internal Java LDAP provider provides some very basic pooling capabilities. This LDAP connection pooling can be turned on/off using the pooled flag on AbstractContextSource. The default value is false (since release 1.3), i.e. the native Java LDAP pooling will be turned on. The configuration of LDAP connection pooling is managed using System properties, so this needs to be handled manually, outside of the Spring Context configuration. Details of the native pooling configuration can be found here. There are several serious deficiencies in the built-in LDAP connection pooling, which is why Spring LDAP provides a more sophisticated approach to LDAP connection pooling, described in . If pooling functionality is required, this is the recommended approach. Advanced ContextSource Configuration Alternate ContextFactory It is possible to configure the ContextFactory that the ContextSource is to use when creating Contexts using the contextFactory property. The default value is com.sun.jndi.ldap.LdapCtxFactory. Custom DirObjectFactory As described in , a DirObjectFactory can be used to translate the Attributes of found Contexts to a more useful DirContext implementation. This can be configured using the dirObjectFactory property. You can use this property if you have your own, custom DirObjectFactory implementation. The default value is DefaultDirObjectFactory. Custom DirContext Environment Properties In some cases the user might want to specify additional environment setup properties in addition to the ones directly configurable from AbstractContextSource. Such properties should be set in a Map and supplied to the baseEnvironmentProperties property. LdapTemplate Configuration Ignoring PartialResultExceptions Some Active Directory (AD) servers are unable to automatically following referrals, which often leads to a PartialResultException being thrown in searches. You can specify that PartialResultException is to be ignored by setting the ignorePartialResultException property to true. This causes all referrals to be ignored, and no notice will be given that a PartialResultException has been encountered. There is currently no way of manually following referrals using LdapTemplate. Obtaining a reference to the base LDAP path As described above, a base LDAP path may be supplied to the ContextSource, specifying the root in the LDAP tree to which all operations will be relative. This means that you will only be working with relative distinguished names throughout your system, which is typically rather handy. There are however some cases in which you will need to have access to the base path in order to be able to construct full DNs, relative to the actual root of the LDAP tree. One example would be when working with LDAP groups (e.g. groupOfNames objectclass), in which case each group member attribute value will need to be the full DN of the referenced member. For that reason, Spring LDAP has a mechanism by which any Spring controlled bean may be supplied the base path on startup. For beans to be notified of the base path, two things need to be in place: First of all, the bean that wants the base path reference needs to implement the BaseLdapPathAware interface. Secondly, a BaseLdapPathBeanPostProcessor needs to be defined in the application context Implementing <literal>BaseLdapPathAware</literal> package com.example.service; public class PersonService implements PersonService, BaseLdapPathAware { ... private DistinguishedName basePath; public void setBaseLdapPath(DistinguishedName basePath) { this.basePath = basePath; } ... private DistinguishedName getFullPersonDn(Person person) { return new DistinguishedName(basePath).append(person.getDn()); } ... } Specifying a <literal>BaseLdapPathBeanPostProcessor</literal> in your <literal>ApplicationContext</literal> <beans> ... <bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource"> <property name="url" value="ldap://localhost:389" /> <property name="base" value="dc=example,dc=com" /> <property name="authenticationSource" ref="authenticationSource" /> </bean> ... <bean class="org.springframework.ldap.core.support.BaseLdapPathBeanPostProcessor" /> </beans> The default behaviour of the BaseLdapPathBeanPostProcessor is to use the base path of the single defined BaseLdapPathSource (AbstractContextSource )in the ApplicationContext. If more than one BaseLdapPathSource is defined, you will need to specify which one to use with the baseLdapPathSourceName property. libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/index.xml0000644000000000000000000000304711470260546020312 0ustar Spring LDAP - Reference Documentation &version; Mattias Arthursson Ulrik Sandberg Eric Dalquist Keith Barlow Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically. libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/transactions.xml0000644000000000000000000003250011337444401021703 0ustar Transaction Support Introduction Programmers used to working with relational databases coming to the LDAP world often express surprise to the fact that there is no notion of transactions. It is not specified in the protocol, and thus no servers support it. Recognizing that this may be a major problem, Spring LDAP provides support for client-side, compensating transactions on LDAP resources. LDAP transaction support is provided by ContextSourceTransactionManager, a PlatformTransactionManager implementation that manages Spring transaction support for LDAP operations. Along with its collaborators it keeps track of the LDAP operations performed in a transaction, making record of the state before each operation and taking steps to restore the initial state should the transaction need to be rolled back. In addition to the actual transaction management, Spring LDAP transaction support also makes sure that the same DirContext instance will be used throughout the same transaction, i.e. the DirContext will not actually be closed until the transaction is finished, allowing for more efficient resources usage. It is important to note that while the approach used by Spring LDAP to provide transaction support is sufficient for many cases it is by no means "real" transactions in the traditional sense. The server is completely unaware of the transactions, so e.g. if the connection is broken there will be no hope to rollback the transaction. While this should be carefully considered it should also be noted that the alternative will be to operate without any transaction support whatsoever; this is pretty much as good as it gets. The client side transaction support will add some overhead in addition to the work required by the original operations. While this overhead should not be something to worry about in most cases, if your application will not perform several LDAP operations within the same transaction (e.g. a modifyAttributes followed by a rebind), or if transaction synchronization with a JDBC data source is not required (see below) there will be nothing to gain by using the LDAP transaction support. Configuration Configuring Spring LDAP transactions should look very familiar if you're used to configuring Spring transactions. You will create a TransactionManager instance and wrap your target object using a TransactionProxyFactoryBean. In addition to this, you will also need to wrap your ContextSource in a TransactionAwareContextSourceProxy. <beans> ... <bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource"> <property name="url" value="ldap://localhost:389" /> <property name="base" value="dc=example,dc=com" /> <property name="userDn" value="cn=Manager" /> <property name="password" value="secret" /> </bean> <bean id="contextSource" class="org.springframework.ldap.transaction.compensating.manager.TransactionAwareContextSourceProxy"> <constructor-arg ref="contextSourceTarget" /> </bean> <bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate"> <constructor-arg ref="contextSource" /> </bean> <bean id="transactionManager" class="org.springframework.ldap.transaction.compensating.manager.ContextSourceTransactionManager"> <property name="contextSource" ref="contextSource" /> </bean> <bean id="myDataAccessObjectTarget" class="com.example.MyDataAccessObject"> <property name="ldapTemplate" ref="ldapTemplate" /> </bean> <bean id="myDataAccessObject" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager" ref="transactionManager" /> <property name="target" ref="myDataAccessObjectTarget" /> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRES_NEW</prop> </props> </property> </bean> ... In a real world example you would probably apply the transactions on the service object level rather than the DAO level; the above serves as an example to demonstrate the general idea. You'll notice that the actual ContextSource and DAO instances get ids with a "Target" suffix. The beans you will actually refer to are the Proxies that are created around the targets; contextSource and myDataAccessObject JDBC Transaction Integration A common use case when working against LDAP is that some of the data is stored in the LDAP tree, but other data is stored in a relational database. In this case, transaction support becomes even more important, since the update of the different resources should be synchronized. While actual XA transactions is not supported, support is provided to conceptually wrap JDBC and LDAP access within the same transaction using the ContextSourceAndDataSourceTransactionManager. A DataSource and a ContextSource is supplied to the ContextSourceAndDataSourceTransactionManager, which will then manage the two transactions, virtually as if they were one. When performing a commit, the LDAP part of the operation will always be performed first, allowing both transactions to be rolled back should the LDAP commit fail. The JDBC part of the transaction is managed exactly as in DataSourceTransactionManager, except that nested transactions is not supported. Once again it should be noted that the provided support is all client side. The wrapped transaction is not an XA transaction. No two-phase as such commit is performed, as the LDAP server will be unable to vote on its outcome. Once again, however, for the majority of cases the supplied support will be sufficient. LDAP Compensating Transactions Explained Spring LDAP manages compensating transactions by making record of the state in the LDAP tree before each modifying operation (bind, unbind, rebind, modifyAttributes, and rename). This enables the system to perform compensating operations should the transaction need to be rolled back. In many cases the compensating operation is pretty straightforward. E.g. the compensating rollback operation for a bind operation will quite obviously be to unbind the entry. Other operations however require a different, more complicated approach because of some particular characteristics of LDAP databases. Specifically, it is not always possible to get the values of all Attributes of an entry, making the above strategy insufficient for e.g. an unbind operation. This is why each modifying operation performed within a Spring LDAP managed transaction is internally split up in four distinct operations - a recording operation, a preparation operation, a commit operation, and a rollback operation. The specifics for each LDAP operation is described in the table below: LDAP Operation Recording Preparation Commit Rollback bind Make record of the DN of the entry to bind. Bind the entry. No operation. Unbind the entry using the recorded DN. rename Make record of the original and target DN. Rename the entry. No operation. Rename the entry back to its original DN. unbind Make record of the original DN and calculate a temporary DN. Rename the entry to the temporary location. Unbind the temporary entry. Rename the entry from the temporary location back to its original DN. rebind Make record of the original DN and the new Attributes, and calculate a temporary DN. Rename the entry to a temporary location. Bind the new Attributes at the original DN, and unbind the original entry from its temporary location. Rename the entry from the temporary location back to its original DN. modifyAttributes Make record of the DN of the entry to modify and calculate compensating ModificationItems for the modifications to be done. Perform the modifyAttributes operation. No operation. Perform a modifyAttributes operation using the calculated compensating ModificationItems.
A more detailed description of the internal workings of the Spring LDAP transaction support is available in the javadocs. Renaming Strategies As described in the table above, the transaction management of some operations require the original entry affected by the operation to be temporarily renamed before the actual modification can be made in the commit. The manner in which the temporary DN of the entry is calculated is managed by a TempEntryRenamingStrategy supplied to the ContextSourceTransactionManager. Two implementations are supplied with Spring LDAP, but if specific behaviour is required a custom implementation can easily be implemented by the user. The provided TempEntryRenamingStrategy implementations are: DefaultTempEntryRenamingStrategy (the default). Adds a suffix to the least significant part of the entry DN. E.g. for the DN cn=john doe, ou=users, this strategy would return the temporary DN cn=john doe_temp, ou=users. The suffix is configurable using the tempSuffix property DifferentSubtreeTempEntryRenamingStrategy. Takes the least significant part of the DN and appends a subtree DN to this. This makes all temporary entries be placed at a specific location in the LDAP tree. The temporary subtree DN is configured using the subtreeNode property. E.g., if subtreeNode is ou=tempEntries and the original DN of the entry is cn=john doe, ou=users, the temporary DN will be cn=john doe, ou=tempEntries. Note that the configured subtree node needs to be present in the LDAP tree. There are some situations where the DefaultTempEntryRenamingStrategy will not work. E.g. if your are planning to do recursive deletes you'll need to use DifferentSubtreeTempEntryRenamingStrategy. This is because the recursive delete operation actually consists of a depth-first delete of each node in the sub tree individually. Since it is not allowed to rename an entry that has any children, and DefaultTempEntryRenamingStrategy would leave each node in the same subtree (with a different name) in stead of actually removing it, this operation would fail. When in doubt, use DifferentSubtreeTempEntryRenamingStrategy.
libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/dirobjectfactory.xml0000644000000000000000000003514111100040136022515 0ustar Simpler Attribute Access and Manipulation with DirContextAdapter Introduction A little-known--and probably underestimated--feature of the Java LDAP API is the ability to register a DirObjectFactory to automatically create objects from found contexts. One of the reasons why it is seldom used is that you will need an implementation of DirObjectFactory that creates instances of a meaningful implementation of DirContext. The Spring LDAP library provides the missing pieces: a default implementation of DirContext called DirContextAdapter, and a corresponding implementation of DirObjectFactory called DefaultDirObjectFactory. Used together with DefaultDirObjectFactory, the DirContextAdapter can be a very powerful tool. Search and Lookup Using ContextMapper The DefaultDirObjectFactory is registered with the ContextSource by default, which means that whenever a context is found in the LDAP tree, its Attributes and Distinguished Name (DN) will be used to construct a DirContextAdapter. This enables us to use a ContextMapper instead of an AttributesMapper to transform found values: Searching using a ContextMapper package com.example.dao; public class PersonDaoImpl implements PersonDao { ... private static class PersonContextMapper implements ContextMapper { public Object mapFromContext(Object ctx) { DirContextAdapter context = (DirContextAdapter)ctx; Person p = new Person(); p.setFullName(context.getStringAttribute("cn")); p.setLastName(context.getStringAttribute("sn")); p.setDescription(context.getStringAttribute("description")); return p; } } public Person findByPrimaryKey( String name, String company, String country) { Name dn = buildDn(name, company, country); return ldapTemplate.lookup(dn, new PersonContextMapper()); } } The above code shows that it is possible to retrieve the attributes directly by name, without having to go through the Attributes and BasicAttribute classes. This is particularly useful when working with multi-value attributes. Extracting values from multi-value attributes normally requires looping through a NamingEnumeration of attribute values returned from the Attributes implementation. The DirContextAdapter can do this for you, using the getStringAttributes() or getObjectAttributes() methods: Getting multi-value attribute values using <literal>getStringAttributes()</literal> private static class PersonContextMapper implements ContextMapper { public Object mapFromContext(Object ctx) { DirContextAdapter context = (DirContextAdapter)ctx; Person p = new Person(); p.setFullName(context.getStringAttribute("cn")); p.setLastName(context.getStringAttribute("sn")); p.setDescription(context.getStringAttribute("description")); // The roleNames property of Person is an String array p.setRoleNames(context.getStringAttributes("roleNames")); return p; } } The AbstractContextMapper Spring LDAP provides an abstract base implementation of ContextMapper, AbstractContextMapper. This automatically takes care of the casting of the supplied Object parameter to DirContexOperations. The PersonContextMapper above can thus be re-written as follows: Using an AbstractContextMapper private static class PersonContextMapper extends AbstractContextMapper { public Object doMapFromContext(DirContextOperations ctx) { Person p = new Person(); p.setFullName(context.getStringAttribute("cn")); p.setLastName(context.getStringAttribute("sn")); p.setDescription(context.getStringAttribute("description")); return p; } } Binding and Modifying Using DirContextAdapter While very useful when extracting attribute values, DirContextAdapter is even more powerful for hiding attribute details when binding and modifying data. Binding This is an example of an improved implementation of the create DAO method. Compare it with the previous implementation in . Binding using <literal>DirContextAdapter</literal> package com.example.dao; public class PersonDaoImpl implements PersonDao { ... public void create(Person p) { Name dn = buildDn(p); DirContextAdapter context = new DirContextAdapter(dn); context.setAttributeValues("objectclass", new String[] {"top", "person"}); context.setAttributeValue("cn", p.getFullname()); context.setAttributeValue("sn", p.getLastname()); context.setAttributeValue("description", p.getDescription()); ldapTemplate.bind(context); } } Note that we use the DirContextAdapter instance as the second parameter to bind, which should be a Context. The third parameter is null, since we're not using any Attributes. Also note the use of the setAttributeValues() method when setting the objectclass attribute values. The objectclass attribute is multi-value, and similar to the troubles of extracting muti-value attribute data, building multi-value attributes is tedious and verbose work. Using the setAttributeValues() mehtod you can have DirContextAdapter handle that work for you. Modifying The code for a rebind would be pretty much identical to , except that the method called would be rebind. As we saw in a more correct approach would be to build a ModificationItem array containing the actual modifications you want to do. This would require you to determine the actual modifications compared to the data present in the LDAP tree. Again, this is something that DirContextAdapter can help you with; the DirContextAdapter has the ability to keep track of its modified attributes. The following example takes advantage of this feature: Modifying using <literal>DirContextAdapter</literal> package com.example.dao; public class PersonDaoImpl implements PersonDao { ... public void update(Person p) { Name dn = buildDn(p); DirContextOperations context = ldapTemplate.lookupContext(dn); context.setAttributeValues("objectclass", new String[] {"top", "person"}); context.setAttributeValue("cn", p.getFullname()); context.setAttributeValue("sn", p.getLastname()); context.setAttributeValue("description", p.getDescription()); ldapTemplate.modifyAttributes(context); } } When no mapper is passed to a ldapTemplate.lookup() operation, the result will be a DirContextAdapter instance. While the lookup method returns an Object, the convenience method lookupContext method automatically casts the return value to a DirContextOperations (the interface that DirContextAdapter implements. The observant reader will see that we have duplicated code in the create and update methods. This code maps from a domain object to a context. It can be extracted to a separate method: Binding and modifying using DirContextAdapter package com.example.dao; public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; ... public void create(Person p) { Name dn = buildDn(p); DirContextAdapter context = new DirContextAdapter(dn); mapToContext(p, context); ldapTemplate.bind(context); } public void update(Person p) { Name dn = buildDn(p); DirContextOperations context = ldapTemplate.lookupContext(dn); mapToContext(person, context); ldapTemplate.modifyAttributes(context); } protected void mapToContext (Person p, DirContextOperations context) { context.setAttributeValues("objectclass", new String[] {"top", "person"}); context.setAttributeValue("cn", p.getFullName()); context.setAttributeValue("sn", p.getLastName()); context.setAttributeValue("description", p.getDescription()); } } A Complete PersonDao Class To illustrate the power of Spring LDAP, here is a complete Person DAO implementation for LDAP in just 68 lines: A complete PersonDao class package com.example.dao; import java.util.List; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.directory.Attributes; import org.springframework.ldap.core.AttributesMapper; import org.springframework.ldap.core.ContextMapper; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.support.DistinguishedName; import org.springframework.ldap.filter.AndFilter; import org.springframework.ldap.filter.EqualsFilter; import org.springframework.ldap.filter.WhitespaceWildcardsFilter; public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; public void setLdapTemplate(LdapTemplate ldapTemplate) { this.ldapTemplate = ldapTemplate; } public void create(Person person) { DirContextAdapter context = new DirContextAdapter(buildDn(person)); mapToContext(person, context); ldapTemplate.bind(context); } public void update(Person person) { Name dn = buildDn(person); DirContextOperations context = ldapTemplate.lookupContext(dn); mapToContext(person, context); ldapTemplate.modifyAttributes(context); } public void delete(Person person) { ldapTemplate.unbind(buildDn(person)); } public Person findByPrimaryKey(String name, String company, String country) { Name dn = buildDn(name, company, country); return (Person) ldapTemplate.lookup(dn, getContextMapper()); } public List findByName(String name) { AndFilter filter = new AndFilter(); filter.and(new EqualsFilter("objectclass", "person")).and(new WhitespaceWildcardsFilter("cn",name)); return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), getContextMapper()); } public List findAll() { EqualsFilter filter = new EqualsFilter("objectclass", "person"); return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), getContextMapper()); } protected ContextMapper getContextMapper() { return new PersonContextMapper(); } protected Name buildDn(Person person) { return buildDn(person.getFullname(), person.getCompany(), person.getCountry()); } protected Name buildDn(String fullname, String company, String country) { DistinguishedName dn = new DistinguishedName(); dn.add("c", country); dn.add("ou", company); dn.add("cn", fullname); return dn; } protected void mapToContext(Person person, DirContextOperations context) { context.setAttributeValues("objectclass", new String[] {"top", "person"}); context.setAttributeValue("cn", person.getFullName()); context.setAttributeValue("sn", person.getLastName()); context.setAttributeValue("description", person.getDescription()); } private static class PersonContextMapper extends AbstractContextMapper { public Object doMapFromContext(DirContextOperations context) { Person person = new Person(); person.setFullName(context.getStringAttribute("cn")); person.setLastName(context.getStringAttribute("sn")); person.setDescription(context.getStringAttribute("description")); return person; } } } In several cases the Distinguished Name (DN) of an object is constructed using properties of the object. E.g. in the above example, the country, company and full name of the Person are used in the DN, which means that updating any of these properties will actually require moving the entry in the LDAP tree using the rename() operation in addition to updating the Attribute values. Since this is highly implementation specific this is something you'll need to keep track of yourself - either by disallowing the user to change these properties or performing the rename() operation in your update() method if needed. libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/odm.xml0000644000000000000000000002704511474433623017770 0ustar Object-Directory Mapping (ODM) Introduction Relational mapping frameworks like Hibernate and JPA have offered developers the ability to use annotations to map database tables to Java objects for some time. The Spring Framework LDAP project now offers the same ability with respect to directories through the use of the org.springframework.ldap.odm package (sometimes abbreviated as o.s.l.odm). OdmManager The org.springframework.ldap.odm.OdmManager interface, and its implementation, is the central class in the ODM package. The OdmManager orchestrates the process of reading objects from the directory and mapping the data to annotated Java object classes. This interface provides access to the underlying directory instance through the following methods: <T> T read(Class<T> clazz, Name dn) void create(Object entry) void update(Object entry) void delete(Object entry) <T> List<T> findAll(Class<T> clazz, Name base, SearchControls searchControls) <T> List<T> search(Class<T> clazz, Name base, String filter, SearchControls searchControls) A reference to an implementation of this interface can be obtained through the org.springframework.ldap.odm.core.impl.OdmManagerImplFactoryBean. A basic configuration of this factory would be as follows: Configuring the OdmManager Factory <beans> ... <bean id="odmManager" class="org.springframework.ldap.odm.core.impl.OdmManagerImplFactoryBean"> <property name="converterManager" ref="converterManager" /> <property name="contextSource" ref="contextSource" /> <property name="managedClasses"> <set> <value>com.example.dao.SimplePerson</value> </set> </property> </bean> ... </beans> The factory requires the list of entity classes to be managed by the OdmManager to be explicitly declared. These classes should be properly annotated as defined in the next section. The converterManager referenced in the above definition is described in . Annotations Entity classes managed by the OdmManager are required to be annotated with the annotations in the org.springframework.ldap.odm.annotations package. The available annotations are: @Entry - Class level annotation indicating the objectClass definitions to which the entity maps. (required) @Id - Indicates the entity DN; the field declaring this attribute must be a derivative of the javax.naming.Name class. (required) @Attribute - Indicates the mapping of a directory attribute to the object class field. @Transient - Indicates the field is not persistent and should be ignored by the OdmManager. The @Entry and @Id attributes are required to be declared on managed classes. @Entry is used to specify which object classes the entity maps too. All object classes for which fields are mapped are required to be declared. Also, in order for a directory entry to be considered a match to the managed entity, all object classes declared by the directory entry must match be declared by in the @Entry annotation. The @Id annotation is used to map the distinguished name of the entry to a field. The field must be an instance of javax.naming.Name or a subclass of it. The @Attribute annotation is used to map object class fields to entity fields. @Attribute is required to declare the name of the object class property to which the field maps and may optionally declare the syntax OID of the LDAP attribute, to guarantee exact matching. @Attribute also provides the type declaration which allows you to indicate whether the attribute is regarded as binary based or string based by the LDAP JNDI provider. The @Transient annotation is used to indicate the field should be ignored by the OdmManager and not mapped to an underlying LDAP property. Type Conversion The OdmManager relies on the org.springframework.ldap.odm.typeconversion package to convert LDAP attributes to Java fields. The main interface in this class is the org.springframework.ldap.odm.typeconversion.ConverterManager. The default ConverterManager implementation uses the following algorithm when parsing objects to convert fields: Try to find and use a Converter registered for the fromClass, syntax and toClass and use it. If this fails, then if the toClass isAssignableFrom the fromClass then just assign it. If this fails try to find and use a Converter registered for the fromClass and the toClass ignoring the syntax. If this fails then throw a ConverterException. Implementations of the ConverterManager interface can be obtained from the o.s.l.odm.typeconversion.impl.ConvertManagerFactoryBean. The factory bean requires converter configurations to be declared in the bean configuration. The converterConfig property accepts a set of ConverterConfig classes, each one defining some conversion logic. A converter config is an instance of o.s.l.odm.typeconversion.impl.ConverterManagerFactoryBean.ConverterConfig. The config defines a set of source classes, the set of target classes, and an implementation of the org.springframework.ldap.odm.typeconversion.impl.Converter interface which provides the logic to convert from the fromClass to the toClass. A sample configuration is provided in the following example: Configuring the Converter Manager Factory <bean id="fromStringConverter" class="org.springframework.ldap.odm.typeconversion.impl.converters.FromStringConverter" /> <bean id="toStringConverter" class="org.springframework.ldap.odm.typeconversion.impl.converters.ToStringConverter" /> <bean id="converterManager" class="org.springframework.ldap.odm.typeconversion.impl.ConverterManagerFactoryBean"> <property name="converterConfig"> <set> <bean class="org.springframework.ldap.odm.\ typeconversion.impl.ConverterManagerFactoryBean$ConverterConfig"> <property name="fromClasses"> <set> <value>java.lang.String</value> </set> </property> <property name="toClasses"> <set> <value>java.lang.Byte</value> <value>java.lang.Short</value> <value>java.lang.Integer</value> <value>java.lang.Long</value> <value>java.lang.Float</value> <value>java.lang.Double</value> <value>java.lang.Boolean</value> </set> </property> <property name="converter" ref="fromStringConverter" /> </bean> <bean class="org.springframework.ldap.odm.\ typeconversion.impl.ConverterManagerFactoryBean$ConverterConfig"> <property name="fromClasses"> <set> <value>java.lang.Byte</value> <value>java.lang.Short</value> <value>java.lang.Integer</value> <value>java.lang.Long</value> <value>java.lang.Float</value> <value>java.lang.Double</value> <value>java.lang.Boolean</value> </set> </property> <property name="toClasses"> <set> <value>java.lang.String</value> </set> </property> <property name="converter" ref="toStringConverter" /> </bean> </set> </property> </bean> Execution After all components are configured, directory interaction can be achieved through a reference to the OdmManager, as shown in this example: Execution public class App { private static Log log = LogFactory.getLog(App.class); private static final SearchControls searchControls = new SearchControls(SearchControls.SUBTREE_SCOPE, 100, 10000, null, true, false); public static void main( String[] args ) { try { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); OdmManager manager = (OdmManager) context.getBean("odmManager"); List<SimplePerson> people = manager.search(SimplePerson.class, new DistinguishedName("dc=example,dc=com"), "uid=*", searchControls); log.info("People found: " + people.size()); for (SimplePerson person : people) { log.info( person ); } } catch (Exception e) { e.printStackTrace(); } } } libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/simple.xml0000644000000000000000000000302411046412571020463 0ustar Java 5 Support SimpleLdapTemplate As of version 1.3 Spring LDAP includes the spring-ldap-core-tiger.jar distributable, which adds a thin layer of Java 5 functionality on top of Spring LDAP. The SimpleLdapTemplate class adds search and lookup methods that take a ParameterizedContextMapper, adding generics support to these methods. ParametrizedContextMapper is a typed version of ContextMapper, which simplifies working with searches and lookups: Using <literal>ParameterizedContextMapper</literal> public List<Person> getAllPersons(){ return simpleLdapTemplate.search("", "(objectclass=person)", new ParameterizedContextMapper<Person>() { public Person mapFromContext(Object ctx) { DirContextAdapter adapter = (DirContextAdapter) ctx; Person person = new Person(); // Fill the domain object with data from the DirContextAdapter return person; } }; } libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/basic.xml0000644000000000000000000003222611471054707020266 0ustar Basic Operations Search and Lookup Using AttributesMapper In this example we will use an AttributesMapper to easily build a List of all common names of all person objects. AttributesMapper that returns a single attribute package com.example.dao; public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; public void setLdapTemplate(LdapTemplate ldapTemplate) { this.ldapTemplate = ldapTemplate; } public List getAllPersonNames() { return ldapTemplate.search( "", "(objectclass=person)", new AttributesMapper() { public Object mapFromAttributes(Attributes attrs) throws NamingException { return attrs.get("cn").get(); } }); } } The inline implementation of AttributesMapper just gets the desired attribute value from the Attributes and returns it. Internally, LdapTemplate iterates over all entries found, calling the given AttributesMapper for each entry, and collects the results in a list. The list is then returned by the search method. Note that the AttributesMapper implementation could easily be modified to return a full Person object: AttributesMapper that returns a Person object package com.example.dao; public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; ... private class PersonAttributesMapper implements AttributesMapper { public Object mapFromAttributes(Attributes attrs) throws NamingException { Person person = new Person(); person.setFullName((String)attrs.get("cn").get()); person.setLastName((String)attrs.get("sn").get()); person.setDescription((String)attrs.get("description").get()); return person; } } public List getAllPersons() { return ldapTemplate.search("", "(objectclass=person)", new PersonAttributesMapper()); } } If you have the distinguished name (dn) that identifies an entry, you can retrieve the entry directly, without searching for it. This is called a lookup in Java LDAP. The following example shows how a lookup results in a Person object: A lookup resulting in a Person object package com.example.dao; public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; ... public Person findPerson(String dn) { return (Person) ldapTemplate.lookup(dn, new PersonAttributesMapper()); } } This will look up the specified dn and pass the found attributes to the supplied AttributesMapper, in this case resulting in a Person object. Building Dynamic Filters We can build dynamic filters to use in searches, using the classes from the org.springframework.ldap.filter package. Let's say that we want the following filter: (&(objectclass=person)(sn=?)), where we want the ? to be replaced with the value of the parameter lastName. This is how we do it using the filter support classes: Building a search filter dynamically package com.example.dao; public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; ... public List getPersonNamesByLastName(String lastName) { AndFilter filter = new AndFilter(); filter.and(new EqualsFilter("objectclass", "person")); filter.and(new EqualsFilter("sn", lastName)); return ldapTemplate.search( "", filter.encode(), new AttributesMapper() { public Object mapFromAttributes(Attributes attrs) throws NamingException { return attrs.get("cn").get(); } }); } } To perform a wildcard search, it's possible to use the WhitespaceWildcardsFilter: Building a wildcard search filter AndFilter filter = new AndFilter(); filter.and(new EqualsFilter("objectclass", "person")); filter.and(new WhitespaceWildcardsFilter("cn", cn)); In addition to simplifying building of complex search filters, the Filter classes also provide proper escaping of any unsafe characters. This prevents "ldap injection", where a user might use such characters to inject unwanted operations into your LDAP operations. Building Dynamic Distinguished Names The standard Name interface represents a generic name, which is basically an ordered sequence of components. The Name interface also provides operations on that sequence; e.g., add or remove. LdapTemplate provides an implementation of the Name interface: DistinguishedName. Using this class will greatly simplify building distinguished names, especially considering the sometimes complex rules regarding escapings and encodings. As with the Filter classes this helps preventing potentially malicious data being injected into your LDAP operations. The following example illustrates how DistinguishedName can be used to dynamically construct a distinguished name: Building a distinguished name dynamically package com.example.dao; import org.springframework.ldap.core.support.DistinguishedName; import javax.naming.Name; public class PersonDaoImpl implements PersonDao { public static final String BASE_DN = "dc=example,dc=com"; ... protected Name buildDn(Person p) { DistinguishedName dn = new DistinguishedName(BASE_DN); dn.add("c", p.getCountry()); dn.add("ou", p.getCompany()); dn.add("cn", p.getFullname()); return dn; } } Assuming that a Person has the following attributes: country Sweden company Some Company fullname Some Person The code above would then result in the following distinguished name: cn=Some Person, ou=Some Company, c=Sweden, dc=example, dc=com In Java 5, there is an implementation of the Name interface: LdapName. If you are in the Java 5 world, you might as well use LdapName. However, you may still use DistinguishedName if you so wish. Binding and Unbinding Binding Data Inserting data in Java LDAP is called binding. In order to do that, a distinguished name that uniquely identifies the new entry is required. The following example shows how data is bound using LdapTemplate: Binding data using Attributes package com.example.dao; public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; ... public void create(Person p) { Name dn = buildDn(p); ldapTemplate.bind(dn, null, buildAttributes(p)); } private Attributes buildAttributes(Person p) { Attributes attrs = new BasicAttributes(); BasicAttribute ocattr = new BasicAttribute("objectclass"); ocattr.add("top"); ocattr.add("person"); attrs.put(ocattr); attrs.put("cn", "Some Person"); attrs.put("sn", "Person"); return attrs; } } The Attributes building is--while dull and verbose--sufficient for many purposes. It is, however, possible to simplify the binding operation further, which will be described in . Unbinding Data Removing data in Java LDAP is called unbinding. A distinguished name (dn) is required to identify the entry, just as in the binding operation. The following example shows how data is unbound using LdapTemplate: Unbinding data package com.example.dao; public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; ... public void delete(Person p) { Name dn = buildDn(p); ldapTemplate.unbind(dn); } } Modifying In Java LDAP, data can be modified in two ways: either using rebind or modifyAttributes. Modifying using <literal>rebind</literal> A rebind is a very crude way to modify data. It's basically an unbind followed by a bind. It looks like this: Modifying using rebind package com.example.dao; public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; ... public void update(Person p) { Name dn = buildDn(p); ldapTemplate.rebind(dn, null, buildAttributes(p)); } } Modifying using <literal>modifyAttributes</literal> If only the modified attributes should be replaced, there is a method called modifyAttributes that takes an array of modifications: Modifying using modifyAttributes package com.example.dao; public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; ... public void updateDescription(Person p) { Name dn = buildDn(p); Attribute attr = new BasicAttribute("description", p.getDescription()) ModificationItem item = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr); ldapTemplate.modifyAttributes(dn, new ModificationItem[] {item}); } } Building Attributes and ModificationItem arrays is a lot of work, but as you will see in , the update operations can be simplified. Sample applications It is recommended that you review the Spring LDAP sample applications included in the release distribution for best-practice illustrations of the features of this library. A description of each sample is provided below: spring-ldap-person - the sample demonstrating most features. spring-ldap-article - the sample application that was written to accompany a java.net article about Spring LDAP. libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/ldif-parsing.xml0000644000000000000000000001654511470260564021571 0ustar LDIF Parsing
Introduction LDAP Directory Interchange Format (LDIF) files are the standard medium for describing directory data in a flat file format. The most common uses of this format include information transfer and archival. However, the standard also defines a way to describe modifications to stored data in a flat file format. LDIFs of this later type are typically referred to as changetype or modify LDIFs. The org.springframework.ldap.ldif package provides classes needed to parse LDIF files and deserialize them into tangible objects. The LdifParser is the main class of the org.springframework.ldap.ldif package and is capable of parsing files that are RFC 2849 compliant. This class reads lines from a resource and assembles them into an LdapAttributes object. The LdifParser currently ignores changetype LDIF entries as their usefulness in the context of an application has yet to be determined.
Object Representation Two classes in the org.springframework.ldap.core package provide the means to represent an LDIF in code: LdapAttribute - Extends javax.naming.directory.BasicAttribute adding support for LDIF options as defined in RFC2849. LdapAttributes - Extends javax.naming.directory.BasicAttributes adding specialized support for DNs. LdapAttribute objects represent options as a Set<String>. The DN support added to the LdapAttributes object employs the org.springframework.ldap.core.DistinguishedName class.
The Parser The Parser interface provides the foundation for operation and employs three supporting policy definitions: SeparatorPolicy - establishes the mechanism by which lines are assembled into attributes. AttributeValidationPolicy - ensures that attributes are correctly structured prior to parsing. Specification - provides a mechanism by which object structure can be validated after assembly. The default implementations of these interfaces are the org.springframework.ldap.ldif.parser.LdifParser, the org.springframework.ldap.ldif.support.SeparatorPolicy, and the org.springframework.ldap.ldif.support.DefaultAttributeValidationPolicy, and the org.springframework.ldap.schema.DefaultSchemaSpecification respectively. Together, these 4 classes parse a resource line by line and translate the data into LdapAttributes objects. The SeparatorPolicy determines how individual lines read from the source file should be interpreted as the LDIF specification allows attributes to span multiple lines. The default policy assess lines in the context of the order in which they were read to determine the nature of the line in consideration. control attributes and changetype records are ignored. The DefaultAttributeValidationPolicy uses REGEX expressions to ensure each attribute conforms to a valid attribute format according to RFC 2849 once parsed. If an attribute fails validation, an InvalidAttributeFormatException is logged and the record is skipped (the parser returns null).
Schema Validation A mechanism for validating parsed objects against a schema and is available via the Specification interface in the org.springframework.ldap.schema package. The DefaultSchemaSpecification does not do any validation and is available for instances where records are known to be valid and not required to be checked. This option saves the performance penalty that validation imposes. The BasicSchemaSpecification applies basic checks such as ensuring DN and object class declarations have been provided. Currently, validation against an actual schema requires implementation of the Specification interface.
Spring Batch Integration While the LdifParser can be employed by any application that requires parsing of LDIF files, Spring offers a batch processing framework that offers many file processing utilities for parsing delimited files such as CSV. The org.springframework.ldap.ldif.batch package offers the classes necessary for using the LdifParser as a valid configuration option in the Spring Batch framework. There are 5 classes in this package which offer three basic use cases: Use Case 1: Read LDIF records from a file and return an LdapAttributes object. Use Case 2: Read LDIF records from a file and map records to Java objects (POJOs). Use Case 3: Write LDIF records to a file. The first use case is accomplished with the LdifReader. This class extends Spring Batch's AbstractItemCountingItemSteamItemReader and implements its ResourceAwareItemReaderItemStream. It fits naturally into the framework and can be used to read LdapAttributes objects from a file. The MappingLdifReader can be used to map LDIF objects directly to any POJO. This class requires an implementation of the RecordMapper interface be provided. This implementation should implement the logic for mapping objects to POJOs. The RecordCallbackHandler can be implemented and provided to either reader. This handler can be used to operate on skipped records. Consult the Spring Batch documentation for more information. The last member of this package, the LdifAggregator, can be used to write LDIF records to a file. This class simply invokes the toString() method of the LdapAttributes object.
libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/preface.xml0000644000000000000000000000255211021722676020607 0ustar Preface The Java Naming and Directory Interface (JNDI) is for LDAP programming what Java Database Connectivity (JDBC) is for SQL programming. There are several similarities between JDBC and JNDI/LDAP (Java LDAP). Despite being two completely different APIs with different pros and cons, they share a number of less flattering characteristics: They require extensive plumbing code, even to perform the simplest of tasks. All resources need to be correctly closed, no matter what happens. Exception handling is difficult. The above points often lead to massive code duplication in common usages of the APIs. As we all know, code duplication is one of the worst code smells. All in all, it boils down to this: JDBC and LDAP programming in Java are both incredibly dull and repetitive. Spring JDBC, a part of the Spring framework, provides excellent utilities for simplifying SQL programming. We need a similar framework for Java LDAP programming. libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/overview.xml0000644000000000000000000005010611470260546021047 0ustar Introduction Overview Spring LDAP (http://www.springframework.org/ldap) is a library for simpler LDAP programming in Java, built on the same principles as the JdbcTemplate in Spring JDBC. It completely eliminates the need to worry about creating and closing LdapContext and looping through NamingEnumeration. It also provides a more comprehensive unchecked Exception hierarchy, built on Spring's DataAccessException. As a bonus, it also contains classes for dynamically building LDAP filters and DNs (Distinguished Names), LDAP attribute management, and client-side LDAP transaction management. Consider, for example, a method that should search some storage for all persons and return their names in a list. Using JDBC, we would create a connection and execute a query using a statement. We would then loop over the result set and retrieve the column we want, adding it to a list. In contrast, using Java LDAP, we would create a context and perform a search using a search filter. We would then loop over the resulting naming enumeration and retrieve the attribute we want, adding it to a list. The traditional way of implementing this person name search method in Java LDAP looks like this, where the code marked as bold actually performs tasks related to the business purpose of the method: package com.example.dao; public class TraditionalPersonDaoImpl implements PersonDao { public List getAllPersonNames() { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://localhost:389/dc=example,dc=com"); DirContext ctx; try { ctx = new InitialDirContext(env); } catch (NamingException e) { throw new RuntimeException(e); } LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls.setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search("", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results.next(); Attributes attributes = searchResult.getAttributes(); Attribute attr = attributes.get("cn"); String cn = (String) attr.get(); list.add(cn); } } catch (NameNotFoundException e) { // The base context was not found. // Just clean up and exit. } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } } By using the Spring LDAP classes AttributesMapper and LdapTemplate, we get the exact same functionality with the following code: package com.example.dao; public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; public void setLdapTemplate(LdapTemplate ldapTemplate) { this.ldapTemplate = ldapTemplate; } public List getAllPersonNames() { return ldapTemplate.search( "", "(objectclass=person)", new AttributesMapper() { public Object mapFromAttributes(Attributes attrs) throws NamingException { return attrs.get("cn").get(); } }); } } The amount of boiler-plate code is significantly less than in the traditional example. The LdapTemplate version of the search method performs the search, maps the attributes to a string using the given AttributesMapper, collects the strings in an internal list, and finally returns the list. Note that the PersonDaoImpl code simply assumes that it has an LdapTemplate instance, rather than looking one up somewhere. It provides a set method for this purpose. There is nothing Spring-specific about this "Inversion of Control". Anyone that can create an instance of PersonDaoImpl can also set the LdapTemplate on it. However, Spring provides a very flexible and easy way of achieving this. The Spring container can be told to wire up an instance of LdapTemplate with its required dependencies and inject it into the PersonDao instance. This wiring can be defined in various ways, but the most common is through XML: <beans> <bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource"> <property name="url" value="ldap://localhost:389" /> <property name="base" value="dc=example,dc=com" /> <property name="userDn" value="cn=Manager" /> <property name="password" value="secret" /> </bean> <bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate"> <constructor-arg ref="contextSource" /> </bean> <bean id="personDao" class="com.example.dao.PersonDaoImpl"> <property name="ldapTemplate" ref="ldapTemplate" /> </bean> </beans> Packaging overview At a minimum, to use Spring LDAP you need: spring-ldap-core (the Spring LDAP library) spring-core (miscellaneous utility classes used internally by the framework) spring-beans (contains interfaces and classes for manipulating Java beans) commons-logging (a simple logging facade, used internally) commons-lang (misc utilities, used internally) In addition to the required dependencies the following optional dependencies are required for certain functionality: spring-context (If your application is wired up using the Spring Application Context - adds the ability for application objects to obtain resources using a consistent API. Definitely needed if you are planning on using the BaseLdapPathBeanPostProcessor.) spring-tx (If you are planning to use the client side compensating transaction support) spring-jdbc (If you are planning to use the client side compensating transaction support) ldapbp (Sun LDAP Booster Pack - if you will use the LDAP v3 Server controls integration and you're not using Java5 or higher) commons-pool (If you are planning to use the pooling functionality) spring-batch (If you are planning to use the LDIF parsing functionality together with Spring Batch) Package structure This section provides an overview of the logical package structure of the Spring LDAP codebase. The dependencies for each package are clearly noted.
Spring LDAP package structure
org.springframework.transaction.compensating The transaction.compensating package contains the generic compensating transaction support. This is not LDAP-specific or JNDI-specific in any way. Dependencies: commons-logging org.springframework.ldap The ldap package contains the exceptions of the library. These exceptions form an unchecked hierarchy that mirrors the NamingException hierarchy. Dependencies: spring-core org.springframework.ldap.core The ldap.core package contains the central abstractions of the library. These abstractions include AuthenticationSource, ContextSource, DirContextProcessor, and NameClassPairCallbackHandler. This package also contains the central class LdapTemplate, plus various mappers and executors. Dependencies: ldap, ldap.support, spring-beans, spring-core, spring-tx, commons-lang, commons-logging org.springframework.ldap.core.support The ldap.core.support package contains supporting implementations of some of the core interfaces. Dependencies: ldap, ldap.core, ldap.support, spring-core, spring-beans, spring-context, commons-lang, commons-logging org.springframework.ldap.core.simple The ldap.core.simple package contains Java5-specific parts of Spring LDAP. It's mainly a simplification layer that takes advantage of the generics support in Java5, in order to get typesafe context mappers as well as typesafe search and lookup methods. Dependencies: ldap.core org.springframework.ldap.pool The ldap.pool package contains support for detailed pool configuration on a per-ContextSource basis. Pooling support is provided by PoolingContextSource which can wrap any ContextSource and pool both read-only and read-write DirContext objects. Jakarta Commons-Pool is used to provide the underlying pool implementation. Dependencies: ldap.core, commons-lang, commons-pool org.springframework.ldap.pool.factory The ldap.pool.factory package contains the actual pooling context source and other classes for context creation. Dependencies: ldap, ldap.core, ldap.pool, ldap.pool.validation, spring-beans, spring-tx, commons-lang, commons-logging, commons-pool org.springframework.ldap.pool.validation The ldap.pool.validation package contains the connection validation support. Dependencies: ldap.pool, commons-lang, commons-logging org.springframework.ldap.support The ldap.support package contains supporting utilities, like the exception translation mechanism. Dependencies: ldap, spring-core, commons-lang, commons-logging org.springframework.ldap.authentication The ldap.authentication package contains an implementation of the AuthenticationSource interface that can be used if the user should be allowed to read some information even though not logged in. Dependencies: ldap.core, spring-beans, commons-lang org.springframework.ldap.control The ldap.control package contains an abstract implementation of the DirContextProcessor interface that can be used as a basis for processing RequestControls and ResponseControls. There is also a concrete implementation that handles paged search results and one that handles sorting. The LDAP Booster Pack is used to get support for controls, unless Java5 is used. Dependencies: ldap, ldap.core, LDAP booster pack (optional), spring-core, commons-lang, commons-logging org.springframework.ldap.filter The ldap.filter package contains the Filter abstraction and several implementations of it. Dependencies: ldap.core, spring-core, commons-lang org.springframework.ldap.transaction.compensating The ldap.transaction.compensating package contains the core LDAP-specific implementation of compensating transactions. Dependencies: ldap.core, ldap.core.support, transaction.compensating, spring-core, commons-lang, commons-logging org.springframework.ldap.transaction.compensating.manager The ldap.transaction.compensating.manager package contains the core implementation classes for client-side compensating transactions. Dependencies: ldap, ldap.core, ldap.support, ldap.transaction.compensating, ldap.transaction.compensating.support, transaction.compensating, spring-tx, spring-jdbc, spring-orm, commons-logging org.springframework.ldap.transaction.compensating.support The ldap.transaction.compensating.support package contains useful helper classes for client-side compensating transactions. Dependencies: ldap.core, ldap.transaction.compensating org.springframework.ldap.ldif The ldap.ldif package provides support for parsing LDIF files. Dependencies: ldap.core org.springframework.ldap.ldif.batch The ldap.ldif.batch package provides the classes necessary to use the LDIF parser in the Spring Batch framework. Dependencies: ldap.core, ldap.ldif.parser, spring-batch, spring-core, spring-beans, commons-logging org.springframework.ldap.ldif.parser The ldap.ldif.parser package provides the parser classes and interfaces. Dependencies: ldap.core, ldap.schema, ldap.ldif, ldap.ldif.support, spring-core, spring-beans, commons-lang, commons-logging org.springframework.ldap.ldif.support The ldap.ldif.support package provides the necessary auxiliary classes utilized by the LDIF Parser. Dependencies: ldap.core, ldap.ldif, commons-lang, commons-logging org.springframework.ldap.odm The ldap.odm package provides the classes and interfaces enabling annotation based object-directory mapping. Dependencies: ldap, ldap.core, ldap.core.simple, ldap.filter, spring-beans, commons-cli, commons-logging, freemarker For the exact list of jar dependencies, see the Spring LDAP Maven2 Project Object Model (POM) files in the source tree.
Support Spring LDAP 1.3 is supported on Spring 2.0 and later. The community support forum is located at http://forum.springframework.org, and the project web page is http://www.springframework.org/ldap.
libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/executors.xml0000644000000000000000000001320311021722676021216 0ustar Adding Missing Overloaded API Methods Implementing Custom Search Methods While LdapTemplate contains several overloaded versions of the most common operations in DirContext, we have not provided an alternative for each and every method signature, mostly because there are so many of them. We have, however, provided a means to call whichever DirContext method you want and still get the benefits that LdapTemplate provides. Let's say that you want to call the following DirContext method: NamingEnumeration search(Name name, String filterExpr, Object[] filterArgs, SearchControls ctls) There is no corresponding overloaded method in LdapTemplate. The way to solve this is to use a custom SearchExecutor implementation: public interface SearchExecutor { public NamingEnumeration executeSearch(DirContext ctx) throws NamingException; } In your custom executor, you have access to a DirContext object, which you use to call the method you want. You then provide a handler that is responsible for mapping attributes and collecting the results. You can for example use one of the available implementations of CollectingNameClassPairCallbackHandler, which will collect the mapped results in an internal list. In order to actually execute the search, you call the search method in LdapTemplate that takes an executor and a handler as arguments. Finally, you return whatever your handler has collected. A custom search method using SearchExecutor and AttributesMapper package com.example.dao; public class PersonDaoImpl implements PersonDao { ... public List search(final Name base, final String filter, final String[] params, final SearchControls ctls) { SearchExecutor executor = new SearchExecutor() { public NamingEnumeration executeSearch(DirContext ctx) { return ctx.search(base, filter, params, ctls); } }; CollectingNameClassPairCallbackHandler handler = new AttributesMapperCallbackHandler(new PersonAttributesMapper()); ldapTemplate.search(executor, handler); return handler.getList(); } } If you prefer the ContextMapper to the AttributesMapper, this is what it would look like: A custom search method using SearchExecutor and ContextMapper package com.example.dao; public class PersonDaoImpl implements PersonDao { ... public List search(final Name base, final String filter, final String[] params, final SearchControls ctls) { SearchExecutor executor = new SearchExecutor() { public NamingEnumeration executeSearch(DirContext ctx) { return ctx.search(base, filter, params, ctls); } }; CollectingNameClassPairCallbackHandler handler = new ContextMapperCallbackHandler(new PersonContextMapper()); ldapTemplate.search(executor, handler); return handler.getList(); } } When using the ContextMapperCallbackHandler you must make sure that you have called setReturningObjFlag(true) on your SearchControls instance. Implementing Other Custom Context Methods In the same manner as for custom search methods, you can actually execute any method in DirContext by using a ContextExecutor. public interface ContextExecutor { public Object executeWithContext(DirContext ctx) throws NamingException; } When implementing a custom ContextExecutor, you can choose between using the executeReadOnly() or the executeReadWrite() method. Let's say that we want to call this method: Object lookupLink(Name name) It's available in DirContext, but there is no matching method in LdapTemplate. It's a lookup method, so it should be read-only. We can implement it like this: A custom DirContext method using ContextExecutor package com.example.dao; public class PersonDaoImpl implements PersonDao { ... public Object lookupLink(final Name name) { ContextExecutor executor = new ContextExecutor() { public Object executeWithContext(DirContext ctx) { return ctx.lookupLink(name); } }; return ldapTemplate.executeReadOnly(executor); } } In the same manner you can execute a read-write operation using the executeReadWrite() method. libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/resources/0002755000000000000000000000000011550465534020474 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/resources/images/0002755000000000000000000000000011550465534021741 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/resources/images/xdev-spring_logo.jpg0000644000000000000000000011100011134200352025677 0ustar ÿØÿàJFIFHHÿáñExifMM*bj(1r2‡i¤ÐHHAdobe Photoshop CS Windows2006:08:05 08:34:10 ÿÿ   I&(.»HHÿØÿàJFIFHHÿí Adobe_CMÿîAdobed€ÿÛ„            ÿÀ "ÿÝ ÿÄ?   3!1AQa"q2‘¡±B#$RÁb34r‚ÑC%’Sðáñcs5¢²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷5!1AQaq"2‘¡±B#ÁRÑð3$bár‚’CScs4ñ%¢²ƒ&5ÂÒD“T£dEU6teâò³„ÃÓuãóF”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö'7GWgw‡—§·ÇÿÚ ?•6²»ç¸5§ÚâLh}²¯ØÓt#Ss–}wZÏHTç‚Û½]ØÙ,ÇÈfÖÕúKqr¿Uê8ïc2=)»íUÝëøùUŒz,}´œ?ÖÎFvç0–Ug§“‰ŠçŸçw±õÐÿ´}¡žž5?§ý2ÍŽb;ô+i°Çµ­qy4'MYïoùÌõkȪ×Ù]62ïM­.²§o`q×Òõa¬uµþ§¿bͲ÷ÛS«}UÔß°¶ë@¾Ág¬ìWØüm­{jô~Ù³Ìk?Ifû)³}vìVmÏ5 œÑ@ªšqìam’Kí47({Ýé6†2Ì—ú{=jŸêzž—è8%[‹¢©…­Û}¬ì㹿{ÿïÈ6–¹ƒÜ$翇(™¹¹¢j–Ýs>ÐÐòÃUgn7ªç¾›3œß^ì¿Gô^uzáP:…ù;j§Û̓ ¶¿uüÆäcß‹?ÎÙS±Ùê[½õ~‹Òôl®«öjR—¾ÿ÷ª¥«qe€ù­;›êã9úCâ^U­eùæªéôqæÐ=gØû굌È,õ1ÛsYüãêÌÄ£«Y‘•e¿á/Ñß]˜íôIÊʨ\붸ãÔÖ?êË]èz™žædYú½Œ¯ù›SgÊä$c¡®»ÿŠªi¿Vwº¹ðQo¡§e_k»—Õ‹[‰c­7ÙVElõ¯ªÿÐaz9gûUv?Ôõªý ~Š…9XÖRX t[aÉǧԷééº^]¶ÔñöFÖÜŒ<Ë©ý[׫×ÿ¤† ÷ŽºUI,ë¸Ñ —챤éªzòñ­£í ,£ÕäÛesƒêØû2¦Qe›ŸfnÚ/Ûo­ö¯¶}—Ñû"bé³&¢%_³žì‡Õc­°ºÜZ쾆Ðûj¢ïK;{1èõ=_´Uÿm8`•Ñ"Ž–Š{ª™²,ÃyÐþ–¯ú›[ÿRõÑ/;é½BÊ3>ÒÏOeO¦º\_4=GÛaß¿&¯§éÑè3è3Ó^„ǶÆ5ì;šðÒ;ƒ¨SòÒ4qñŸù©nÌ’I%ar’I$”¤’I%?ÿПdôÛö¯KËÕÛòÛê+˜¬¤_Còli$Yöìô jßµz>Ñvýþ—Ó±y*K&¥ól~_û¯ê¬®ŸÙa¤³–zžâvmõ'óçü/õ½è•~ʆ†ú¦+5ìßêOèO§úOµ} žŸé÷¯I/µ/ªdQÓë|Ñ‘ëZn÷6±Xhº-ßö¿±×[>׳í>—Û?Mý/Ñÿ•_dÜÿKÒ˜ý>ͼ÷õ¶ÿßו¤›ÒÿæA}6ßÙþ‹#Ðôw~Ž6lÝüÌÞ‹€zW¿pÅÏ'ÒñüéþRòÔ”SùNê}g'öVÇëᇲ#ó=_í} ꛽oæí<ÄlüîÁ¯2I,_U>Ÿú¿Ú™»ÓõÁnÛ¿þµ»Ýþb¯zvÝ7öÙ·þ•^p’—ªŸWèæFÏ@W½Æ½¿Kù~ŸýùwÿWz]m¹¤5³è¼Çº³«ï{~Šù¥%')üô·ê¨üßGꤗʩ-ïÕI/•RIOÕI/•RIOÿÙÿí ¼Photoshop 3.08BIM8BIM%F ò‰&¸VÚ°œ¡°§w8BIMíHH8BIM&?€8BIM x8BIM8BIMó 8BIM 8BIM' 8BIMõH/fflff/ff¡™š2Z5-8BIMøpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿè8BIM@@8BIM8BIMUI xdev-spring_logo InullboundsObjcRct1Top longLeftlongBtomlongIRghtlong slicesVlLsObjcslicesliceIDlonggroupIDlongoriginenum ESliceOrigin autoGeneratedTypeenum ESliceTypeImg boundsObjcRct1Top longLeftlongBtomlongIRghtlong urlTEXTnullTEXTMsgeTEXTaltTagTEXTcellTextIsHTMLboolcellTextTEXT horzAlignenumESliceHorzAligndefault vertAlignenumESliceVertAligndefault bgColorTypeenumESliceBGColorTypeNone topOutsetlong leftOutsetlong bottomOutsetlong rightOutsetlong8BIM( ?ð8BIM8BIM8BIM × à)@»ÿØÿàJFIFHHÿí Adobe_CMÿîAdobed€ÿÛ„            ÿÀ "ÿÝ ÿÄ?   3!1AQa"q2‘¡±B#$RÁb34r‚ÑC%’Sðáñcs5¢²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷5!1AQaq"2‘¡±B#ÁRÑð3$bár‚’CScs4ñ%¢²ƒ&5ÂÒD“T£dEU6teâò³„ÃÓuãóF”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö'7GWgw‡—§·ÇÿÚ ?•6²»ç¸5§ÚâLh}²¯ØÓt#Ss–}wZÏHTç‚Û½]ØÙ,ÇÈfÖÕúKqr¿Uê8ïc2=)»íUÝëøùUŒz,}´œ?ÖÎFvç0–Ug§“‰ŠçŸçw±õÐÿ´}¡žž5?§ý2ÍŽb;ô+i°Çµ­qy4'MYïoùÌõkȪ×Ù]62ïM­.²§o`q×Òõa¬uµþ§¿bͲ÷ÛS«}UÔß°¶ë@¾Ág¬ìWØüm­{jô~Ù³Ìk?Ifû)³}vìVmÏ5 œÑ@ªšqìam’Kí47({Ýé6†2Ì—ú{=jŸêzž—è8%[‹¢©…­Û}¬ì㹿{ÿïÈ6–¹ƒÜ$翇(™¹¹¢j–Ýs>ÐÐòÃUgn7ªç¾›3œß^ì¿Gô^uzáP:…ù;j§Û̓ ¶¿uüÆäcß‹?ÎÙS±Ùê[½õ~‹Òôl®«öjR—¾ÿ÷ª¥«qe€ù­;›êã9úCâ^U­eùæªéôqæÐ=gØû굌È,õ1ÛsYüãêÌÄ£«Y‘•e¿á/Ñß]˜íôIÊʨ\붸ãÔÖ?êË]èz™žædYú½Œ¯ù›SgÊä$c¡®»ÿŠªi¿Vwº¹ðQo¡§e_k»—Õ‹[‰c­7ÙVElõ¯ªÿÐaz9gûUv?Ôõªý ~Š…9XÖRX t[aÉǧԷééº^]¶ÔñöFÖÜŒ<Ë©ý[׫×ÿ¤† ÷ŽºUI,ë¸Ñ —챤éªzòñ­£í ,£ÕäÛesƒêØû2¦Qe›ŸfnÚ/Ûo­ö¯¶}—Ñû"bé³&¢%_³žì‡Õc­°ºÜZ쾆Ðûj¢ïK;{1èõ=_´Uÿm8`•Ñ"Ž–Š{ª™²,ÃyÐþ–¯ú›[ÿRõÑ/;é½BÊ3>ÒÏOeO¦º\_4=GÛaß¿&¯§éÑè3è3Ó^„ǶÆ5ì;šðÒ;ƒ¨SòÒ4qñŸù©nÌ’I%ar’I$”¤’I%?ÿПdôÛö¯KËÕÛòÛê+˜¬¤_Còli$Yöìô jßµz>Ñvýþ—Ó±y*K&¥ól~_û¯ê¬®ŸÙa¤³–zžâvmõ'óçü/õ½è•~ʆ†ú¦+5ìßêOèO§úOµ} žŸé÷¯I/µ/ªdQÓë|Ñ‘ëZn÷6±Xhº-ßö¿±×[>׳í>—Û?Mý/Ñÿ•_dÜÿKÒ˜ý>ͼ÷õ¶ÿßו¤›ÒÿæA}6ßÙþ‹#Ðôw~Ž6lÝüÌÞ‹€zW¿pÅÏ'ÒñüéþRòÔ”SùNê}g'öVÇëᇲ#ó=_í} ꛽oæí<ÄlüîÁ¯2I,_U>Ÿú¿Ú™»ÓõÁnÛ¿þµ»Ýþb¯zvÝ7öÙ·þ•^p’—ªŸWèæFÏ@W½Æ½¿Kù~ŸýùwÿWz]m¹¤5³è¼Çº³«ï{~Šù¥%')üô·ê¨üßGꤗʩ-ïÕI/•RIOÕI/•RIOÿÙ8BIM!SAdobe PhotoshopAdobe Photoshop CS8BIMÿá-http://ns.adobe.com/xap/1.0/ 4294967295 524 73 1 72/1 72/1 2 2006-08-05T08:34:10Z 2006-08-05T08:34:10Z 2006-08-05T08:34:10Z Adobe Photoshop CS Windows uuid:3f50d993-23b7-11db-9576-fa409a7502c7 adobe:docid:photoshop:3f50d992-23b7-11db-9576-fa409a7502c7 adobe:docid:photoshop:86772fa8-2454-11db-8c34-c59e0b1bd60f image/jpeg ÿîAdobed@ÿÛ„ÿÀI ÿÝBÿÄÌ     !1 AQ"aq2#3‘±B²s$4r³t´5u6 ðÁRÂ%v‚¡bĵÅ&¶7 !1A"Qaq2ð‘¡±ÁÑB#3árRb‚4’Cs³$Dñ²ÒSc5u6ÿÚ ?Ö1(@%+¶Ÿ¼ Zw =ß.¾WK¨TוjLæ%®Á{*QN†LGxm:cÓ¡È;ˆ5èÊ%ðÓp¼Õ¤€²šµ˜õS]DÄJ'¹ÉI3)¶ ‘U²žtT â'Ò+%Ò¢@7NšÛ#~¸cx8·íOg9`Ü1¥p;w̾íxªfù¦§žd)q³”Œ©€@=º3AÖ@Ì%ë-T¯l€9va8ºdf©ÍªáB<ª‹"e†¡E#¨  ”¨Ô½zi—Ó‚EH**õxY(Ç*Wë£ÆÊ¦dªIïE`1j)€ˆî …6ô ޤÅ)©#›%‚¢­Ñ¸ÌmÈŠ’‘§‘lC©ûì†R5}Çð2ñëí TB´ë¨Ïâ72m]Ù8j:ŽCF ´ä«¿#Ù¤•ÚÊænËq.øN—r%HÆAôi’h âŠèF€= mH„rÛê:šíTíÕ\¾!1;p$¥lK JYˆ–4SMTU!’%µo §éðˆ&`ñÓwlÕ 5Ȧ u8­´ÂDÍä~.ê‚ mKö`ñ1 ;F€+@÷ë\1è“*’FœÖ²1P#–ˆ8I@0ì&QqDjÒPÝ}š\ÏÓ¦¹!´¡Ç-ÚâFH£âC”D‹q*b4éÔwß>Ò4‚ 5¯žžlB«#";Èa"?µˆ¦=MðuîR¿¦Û<ƒI®£A€Q€¾jOt6òŠhQ XA¡öípßOv­u`Ò×%j*åôC˜ÇnÝG ê¸&í &P;=J'ªÕ ôk8¬º€ -ÌB¥FY_ú@–Ó«^Ú°wT)JQ% ZTGyëÜ’â1<}‰Lè…û˜w¢E”+q+Ú pî–¥8´¨j)88Ë™MHh[CŠR=¢œƒ‚Ä…EÒû—Ð7’§@*P1;eд¥zjâÝÅá¬2b{Öcy'‚ùP©‘är$†.ÅPQNئÜ|ð‰LWClúU?´zuÓ€—±Ît”¡¥qÁ,¸—SN 9#¤Pvóîƒe[9/mØ üÃîÔyjøÌ^¥J´ãRx €îSÅ;1“¢µL!A‡l yHõDˆþގŠ„)€¢aï 5K£v—ú••¶á®²8H;0?N#¸­nKsïO(8w– Ý[oÛ'e#ad =A7"Š¥\© ;þ>Ÿ8ëF¸alÀ¸ù¹OØŒ*âÖÕÁwkÓW0’jÝžÅrK˜]Å”·,ªqûE{ %ÐDNn›ë…­EE@ë¯PÿÛwT9öÛÇH]Ëù‘8Ï'!²´w¡àí<ö­·§nõÇ%³Ž\ÃãŸ×ã™]NשÖÌF„#B¡ЄhB4!F„#B¡ЄhB4!±fÑÊ­VpÝ•b°¹h¢©”çl¹‘Q¸¬ˆ˜STPXäܦÖRKâÒæƒCQÜrYzÂR4!F„#B¡ ÿÐÔµÚš¢P¡ÐåøŒNŸœ0í§¾•×Ê÷ó4Õiìå~­¢„Þ a¨t5B´üÚGéj$g025… ŒÓk Ω2-ˆ±JtVOµÜKqEL. €›h,‡@üñökeÛä×¢n¢À™J¡L1vÔJ P¨SSÂ…ÔûWµÍ2†£†šä‹ÍñÎâX‡Ç ¹´®løÆ Ê4| 4Ú*T‰n)PüšœMün¥ Œ"¾¡&a©¤—*܉dJížç‰™nÚ‚’€P¤ È`í€PÁáÓ¦²C\ÒQ™ê6€ŒátݺŒv©&ÐAÀ c*rCJAÚ™ú~ k7-Ó+Fš|¾Õ*¸EE)߯Ür((„¢{Q)…3PŸR=:×®™x[âŒ0R¢¦ðÉÈmpQí¾`vŠ )†Ú¦ ‡@ ?¹`”êjÉ/î(ùúyüÊ`S¨O*L>¤Â@ÙZ&n… Óâ¨uԨݦ  ¦ÍáSP—+²”+ù-¯S*„E4~ÑN “¶c&@($jQ*€Ð®­¡{KF++$dAœuUê%hC7$ ™PLÂqGã)F¢5Ó„´“†4BÙ6FX²‹&Wɦ° ™Ž°¤P¢& ¤ ¦m§uð bŒ 8#ëN#øu´Zº¥Ä·} XTÖdJªrù ‚6(S&³iz ~%0{½ºŸ£Ð?/”žÕ•nðÑ~ò^\V§g·ñ‹ƒð6Á7ÚTÞ4öiÇh2¹®¦ª}‹£522Å”F¯óiµ÷…4þÈš@GÜ:3chu!)óWæîÕ‰Dî Ú#ƒœÄÙEtÔ)OAúÂ`÷ê.¶ Ù¤pÍ+ÓP¼æÙIyÖCæ’ï,ŠÛOÛ&Ð!B‡/j†0FB”Ò%lnl‡NJ;ÚçD–—+yÒ’v’täîH)õ\C`¨tÌè ‡@¥4í¬Íl‘`j@L‚| ­ ÚÍR<âbá8+C Ý U>°ІÀ Ö½ujÓ2 ®ÏÅHh-šÍ´©Æ}°a®¾X–ÓÁj>R½=™N^”0©zÔ(a÷j :œÔNÓ —nH©qG9HÀPQO,c€J©Šbw‰®@>jêÖÆAÙZé B•É\· hÏ4 ™8ˆ!(­VO½pS‰‘w½"DhˆÓÙ«Ðã¤ùNIzBÌ|Ì{è‘TÂ+À¾B¦ïªÚGrÑ«ŠÅ1Á‹äIR”(5ŸQ\Þz Ö]SCصÒÍÛ»NÙºˆPMÉ—<ÀE*$]'…ò(»N%:‡jä…˜âÜ!¤,e B’‘PÖ+¥×gNLê<âó´B”Š‹¡4MÀÙtTÜ‘Û8Xª‡Cxt®¤W‰8,O6!G`—qdÖÚeÆ9Q¡Ê—ÐMý¶ªj¢ª` a2r& uW¨iñirH¥qÉ4\?F'Ûw˜ Æuˆ4I4ÐIÃE¶?D†17ª‘ŒºcáÓ­4ÌLoï$`rQ ¸dT†õqf¯“,NnîolÅΞ`·T³GŒÑ›R·‹,ŠpF~ª,P–š+t¹7d¼‘1Œb‘5"o÷7Û6͹_íö^µð l- –ë{šÝO æsbf©\ÖâàÍ8HÙºc§§ê=Þ;&ÈÈ­]4¯pdQF3|’ £8—9­hsˆiµ—_3øWìt£³Ìãh»ŒH#pεr^^¹dö¦ƒ³kÛ²OÕ %йL¼”ÛÆíR ˜Çp ]yêÃÛÿp½ÊÝ„±½Ï$›»ÆË ´Lâö‰Ah9G ­04èóì;’A¶ÞÅ%¼x¡Œ*N ;!©๑Ç\‘³ázå<˜Í(ùL¹-;s£ ØP)5‘U[nÝEeª=þ€#Xðvb$w‚ØW2i™A!}/ºtÞÕÑû^ÏÓ;4ºíìíÚÍG7¸ É!5¼¹újCk¤W*ÝnŸ{w5ËÇæ<ðáÀsçÛ°q“Á-Hr¶Ê*w ¹DÍÝ*ŒGpªíKƒÆ8ªÒ ™ŽmrÚYÙ:j ³6û™ÃríPï Rî8®ÜCéPugp÷ÆØfhò<§§ ƒBš¯c²ÚšàA@AÁ@ÜE©²…øÄáU: çÔó¬”籧ÂpÅÄSÄ@l³‚6®ðØ•Þ5èRƒQé×Zîílš»S°;Pv-Tš1è¹h`I`1ÁÇÛŽnÐL—^¥V´«Ù¤°ƒJ§)@¾jv'IÑŠ ˆlÀt(˜€˜Æ¡„(nÑœ9KP8-<ãF*"Ìæ"¦1D€ê½ã „TÄ ˆˆœ< MIa à›pâ–-bËÓ KöÀ¨ƒq0"S‚fß»ãÜPè¿&¦Û½àÓY&”Áh Hß.ÈŠà±—D®L®Ó¦qT 0L% ^ƒ©à¸ز¾Š1&Tšþ[´M„¸Þ ÇqŒ÷‰´ñé](j§b§V“¦-ÊÔDóFXCUÙ´ªž€CnnSÀ+ª=ê$.¦I@àB·V»ÖŠ˜†K»ÚìÓj„Wx©»iD@j¦Ñ/zë”_BÖI pÃâ©€ŸdÉèïÞ"Qø€¥.êà”ÛZüº¬n–´€ k÷,â!F/ÆRÑ®™‹¢©‡¡Š`T©˜@Hs J(4\XÜ6 ¸ekˆM–*TD™5y"‰ÒXŠ ¡‘@´T½±M3·„($Pj;«Ó¯†»”À²" AÅa¹© `dXÔ«@Q0t?Z;‰OŒ@@B£¸½(Õ>âÍ7&Í&\ÁQiT¢{®Œt–2e!\n ìS¸`=j#ׯ³OYºLMSE@ÑÉ¡A5Aqp¸=VØtŒuk°DåLL5 Pk­ºÒWâÂyhœΆs.¦"ænt R’‹ …Aˆî(Š^i©ñÉ!`þeVn_nÑbf;U¾!PLa©|LO²ü==ú—Î]^ëYP·iÅMDźàÕDŠm…+‚˜]‘A8˜TŠBZÓðê4Áæ<)ª¨ <âß|ÅN &¯|Žh‰è¶ÎÀ¬@ÚsÂ@J½­uÒÒâkÈR@¦%M¥‹$¢kƒs *†àTDLp!‰Sר˜@iMt±Ö£W‚@©à”ÓM#E³åÁ%ûäYTÛÐUØDɰü[7j'¨ÓÇQ´>'†áB7ߨ¨Ã þ=¸¤¸6tš©¿(ƒ€}ANÜèŽ&‘a¯Â Q÷jâÞYe„¼š9§ ¾*S|£Áb¤% !œ­¾?¢â%9HqèÃJ,PúUøGO’þV’(áB²pÓ ¥q¡Š1‘T”H€ø£Þ›¾*u8”E%ÀÔÛJ€êŽý“ŒÌ?ŸÚ| Bi툴‚ʵãl¬Y& ³PÜ‹Ù}À®åPU#(ÕÁŠc ¶¨j«½¬îeÌ z37XîpóA …Í™Ä|ªŸ±ë$hø§ãÜ2íΛ†(œDHS θ ¼:ôÕ4Ì4|y57íJn çö¯Ñ·²¹26g éqV^ÃX°Š ƒõªÃªZQ”)Ul§ÂFä¯Ò {oØN©;ïG ¢ê][†Úá9˜]Sÿ ðÆÞÕ¼ì×[Q5tx|8ê+¯®ä­Ñ¡ЄhB4!F„#B¡ЄhB4!F„#B¡ЄhB4!F„/ÿÒÑ¢JOZ…DCâê_ B†—䮾Y:¤­Iâ˜ðO‹ZO°ÆJå{Ê(à¾,âI†µÁ}µ·Ü]÷ï~IyǘÒÐh»SJÜ‚M°,åeÑ‘ÊÑEÑêísúžÚã{ݯM¶Ç ôê’GàtFÚZWr4u'ZÀeg¨M#={’gçïIìís0Ç–Ö{æ/né×e´òÇ'ml17ƒ˜T8ƒÝêc™ù{ Œ„JE»x¼s,pô©&u©Áío@ÞRÖÒöúÞìà/¢öW† ÀÒÚŸï;pR…­³Žç4÷Ñ^îTc‰>d¬uÇÛ§ø¶RùÂ6ÎFkw"Ý!Ö½K=3uÇÀ“°ÝÙb£æb £0P °2~ÜTPÊo)u¾¾öá½(Û7ÛLéaôš\â›ð2¨V¦‡Qq‰€Wëïfh,G )ÔŠ†Ãœ[ƒÆä#¶â‰À¥/›I D@vœ( q‹XY#FËíðPõi5QÓ³Øé†J¤"( ¢s äˆ9W¶ô¥L¢tÙ½HèÝí cÔÔFŽ ²à2Z —i5º­{”Šm¤‰÷À±ÊMÁ·,xI¨™êaÔ¦ú%§´tP }3™XmE pZUÚ¨ÂfI°¬&zÅЬW”þ§§”US@éHC¸Ø˜4‡02V‚qX¡¯½&!›ã¸;žâ^D ñõß…Ø¥¾}ýü(Þ]OW‰EA¡ä€E@ðàP6­¶(n·]½×•ý™•¡ô<Új5S¾•§zz&ê8Š®œÃ½8—È>O@CðrNø¹ð‡ð%¼k©õΖDB1¾ERJh’Ão%“Á½â-Á.Ô§ó ù6ÎŽëîý¨.¨©Þº»gé–fîÝ9‘膊—87·Fº¹º¨ ÿ´@­CE6Îví‘mP=¬°Öæ´úÇKå>i -Q"0] ÷—Lí®ØvôòOUŽ]tÑœErT‘]M®I²•(•R Cå×½êýÂ@ø‹Ü#Ékây+B®È@ÇY %ÑFÂÍG½Eb„SîÙ`Lª C( ”z @=úÑw)ß4Úåyq4úQ15qL‡i€ ×iAMë¹h¨” ÛѤ= ð ×ߨq;œ])Ÿ7ó($ …J±*ç(3IÊñÎwTí* ™"ˆÂpÜ4üzØcdsFæã«I§Á80 ÝLÂd †öÌ&eHÍ2 ¿"±…ÂBjRX´ÚZk1Ým„T¡ñ(oŒ6J…›l8tSK$o,)¨²âàH'ÜQ¨ xiJJõñÔmÁìiä• h¦KêÈÓJFËçdpǨÆÈ˜½´æôMà µ: ï%ÚB¨Ü *T!„@(!Ôu7¢ö£rÝE¾ôéÅèè׫ yùixö)‘5²>®žïâ¬÷8c½>}>‘À®2ÖUç ÜÛ“–,žAǧÅÖf —-ضÖÊÊ}þápX®#Ÿ.Þìjd“HŽƒá8Ä€Ò·þËtFÝKu¸º7¶ ·ÑÀ`q«[ÛÞ§›(]‚Lqÿ;úJr"ÙØµÏ#9„&névV”Æs±pí½hÊNÉ(“h¸§7-™-~G@šAÊ¥I5ä…‹@P@§X»‹X»µ^ß_L ŽÿpcÉ Õè_µÔøÑ YÛ¹ÔÔêü_"³œÅü‘ä¦ÎUåñ5ÿ5j‘Óú¦âbÜ@ÂöÏŸÓ#Ü6›ÖoÄ RyŠMqnºè÷ôžéuhÒ]C\s-­ZOy%Aš œAFÔ„e"VEKï*¯tê –:{á¢a ¦µÈsNy&òA .’g’XÉ•—˜‰”Õ:∓p‰D´¢¢mÞ5é§E8Ö•Y¯í éâQ¬Î"ÌIÉ{fÞ¯xOæ”)„ÄÛôwΦ.â2PAÉ[K:MꎒÝå{¦hN¥î eLU k¼T2ƒ×À)×\¯u·|3jhÅ:Ê´Å8Z¨s6Wì¶Š‚" >ðèZÔD7ÓÇÙ­]õæìªQÉz>Ed··p ju0Ñ>âœ7GÛá§ÛêÂÔ2C <¦ª¤dX‡‘$ˆB7‘H®¸ËƒÙ8Ÿ²¿:î tþž¼ýų«©¦‰°Nª¡MW«µ‰­vèƒsnPO°2«@ o/Qެ·P55íËŠÄ™-l‰$»²f!YÅ$ûå1–ÊPHûE›ª%¢>ÝF²{A婊ÒFiRðÏÈÖ4Jf}:€"eJ¦ñYPTMRv÷k·¯…5¶Ú—:µ­ë—zÁ¼‘ 3ň8¤2 &[´$*€wt0OÅ«6ˆ„b€Ò§çJÕCÞ¤gYÉâR9…¯•:€%8˜ýãÌz€À )P¯QÔÀ1®5X ¨*5,I•*¤謄B‡\È¿@ÿ‹¸&§ÉM4š+§WÒ²I%j™¬ð¬](&j ÎèÀ©JuEBª ¦*`")DÔññ ûµ´G µ¢ÅGÁ4EWë¤ÄÆ3rܪ S`¤¡JPûCh)¦€¬~šå‚*;Ô&Mgg2+NŠ9:ýV‡¸€t¯B¼zé©ÊÆìp L9ƒC€K9Ä¥¼Ä)ÄŠè•r6À6ùBˆ™z]‰…•ë©VŽk ­ â£0¼8Ÿ ¸%å##î 4ÓcC¢¡žÔË V¦*Än"b¯Ä=5kk%š(Nx|êS œjF íd˜¾IzRfNdqÆ?>Î^Ø‘ïÿgõ m‰ù÷’x¹ýĵ³dã+¾zÓRØ”¶2kTJ¤¢ïŸÊJ‰ )~ú}½é;Ž”¼¾Ûà¸}É k”€áBÒhÆ;E4æÔGhVæÎÜÛ0]§î%® ºÝ\pñóê¡~úŽhÆSã8‹ùq351ºŠ w…z¼™{ìï·  Ö±<É…hñóPñ-^þ7khÄà~Ï—‚¸’˨ܱʸ‘ïì¨ÔÆ“c(«P9@L˜›zuê¶à#AÔÃ_𜠄ÒhÑLB8—OŽótl«’! w–Ô©AQȸxªI±t`PÀT¼¼‚H˜êSáD õthz©Ý+×{w­%6Ëïøy;½B48ð%ÑSÁ…ØUu³\: ‘ Œà~8ˆqùª¿Bºú·DhB4!F„#B¡ЄhB4!F„#B¡ЄhB4!F„#B¡ ÿÓЧC´T¥ú}£‚ #³¦ïwˆP}ºùk(trãÚµR ÈàŸ¸6pƒ7ñW)zazƒ_ï¸ýpå‚e¬Ÿ”rœU­ v«plÚḶun[n`¤¹O6fÑRqRk6ó,Ý$‚Çö'´ÛÆÑÒc§o&È\Ç`<ß@ ×<4À«›9#1«G,œ‡þž<ºðòœmȸ?–vÆ‹Œí¯=g\3mÊB™4#Ù9ËÆà»“¹D jÐéÏÛ>§‚øî.íÄ5¨i%ŽøV¬?é‰-f\NP,ƒ—yC5Å~3òkOÙÿ¡/»>߸¯–ó¹ñÆ7„äoÍúI°—·lVÙXÀH3Qt°W¢ŠuPÍõ>á{qµ[lûÕ¡Žò&‘WR )Ü@¦TJçÈÀǶ„.ÞDÁðž[Y«”×%/ëÕÄùÆû2Ög´„³ÔJźeáñþ'±\2W”åÁZÇD ³ã(îMpL²d:¦{nö³¤7-ŽK«yç2ú€z²4Bí1´j 9œqì¢SlíÝ)5®ÁWŒÍÏI¬ù˜-œ ò—xôù=òv Éëöäµc#^)Ñ€Bâµ`“·ìø©é•»l\¹fý$U |d2«"ýŸ·ÞÜÎãµþÎàLì®jÕÔr rå=ë"ÖØ öÕh³Ëx¾$òçã/(¯ø»VÓMµñ’lKMœíÇvc¹¸¹S[S¶í¯/5 ЯŸÎEsÔŽøSfé`C¸*$îó}×Û6ž¤†Ïp¹md×Ô ¸¶‡M\uQ®©åÄŠÓ_jÖ¸5Ç—ìNþk/éïÅK ‡\˜¼óacŒ³æ a“íÜ_ Õ„ÿ&óûÉûz͸­…IíxÜqŠíK~׸€· ŠÊ ]­áÀŠÄé>ÑtlPíwm7ÓÓÔáPe”šÔžHÀÕ¤q ©Å<ë8(ÃCO¤ª›œyèÞ¼¶#y²§(-¬o‘q¥Õ/™¬HlzµÛxÚdl͘ÞÓ·e|ÉCAÆNKÅ»¸NõÌt…ÃA™ÑL\W~Ýt;ç³’ÂKˆ"Òu5¤9ÚªÚbó<Õ¡pÀPgU›hyCjó#àŽ ó=N;áh vÐŒð–>¿œŒÔºóÓR²ró{9Ž–MΆ!Å&é Ý3öÓ 5EîGLA¶> Kñié7Ìââ]R $öá€vÅÔT!­<ÃuÃ{ςٔ–W!.Û/ fxŒY{æn@Æ)jÀÙÍÒ6>™ºYZxÞÃsqË^²Vö@fÒ<\¸w%2±!š—rác·{QÒŸOÉue<Æà¼VP¤ %Úca Õ¦ƒSœkÄf–ËXLEÍ&½§îU«sÇÒã0å qǵ­>b¨Ë*O[ø–‘×½¯n4ºze¬%» îÃ…,ÆÕ—™x‘rí9 Y3;D¥*Ê&å§·>ÜÈöm³Y\¾áܾ³¤ÚŽ  W*‡SžByh|Tþü¸_`.@g^6Ü— gä± øö¨Ìˆ"ÙYhy‹bý³¤5IE‘BEͧr3;”Šc Ê5Âúó ÝÓ;ܶ6Î×pÒêP–+´ ü•tÖú@8‘Î<€==1Ö”ÎVuýž¹Ș‡W½·†m›å|WeØ{°2²wUÉ7rÉ΋ÙT‘"Hp»uÉõ$n :ì»7¶Á´X]o¶ïºÝ'Œ9ÌÖcŽ EhKAsœ+Cˆƒ€¥]5–ñ66Šš(´ !ˬçð͉ ÅnÄOތͲ«HG Oìö»¸÷,þ¹$²]ƒM- hsXÁMOÜ4à9±D~Ö2U!Ëþx+”—Ïy9™³NN–m’oËZj÷Å-eÒãŸcpÊ4·,i«¢5áò–Eº &›9¹–1΢I´Y$Ü»+¶¾Øt&Ûw<[“e—SJ8¶8ÛS¥µ[ˆ+ÀâRE­³ZâM~…áv>ÅÁä'ØZ¹‚æ·¸{Ç<‘–¥²ÌÃͲ¶ ´f– V‘Ò­4gpÌ[ÍÅÊ®Þ4E»DQU[A#Cj^×m›¯PÞEÓ™±@òêP°VŽˆüDPPšVM2ÍŽ•ÚOå¡ÂüîôêÊ9†ÍÅ3œGÏÖV1ÈÔ%›ÚrmÌÞMµÿ‰¦ÙÀE_7ˆ6\|ðˆ¸x^³h™üª&0"/N˜}šÛ¤:IÛ¶Í²ÈÆ¼†‡úäÈ+€qC+Ú)AßÅÆÃlN’Ã~?r´¹ú.+…ļxÇ~ßòó6…ªµ™p!}°‹lîê.5»Ðc+çT·¼ìs×D k‡‹b®Ù®ZÊdXœ'ÜOiìöŽ¥·´}ÓÆÎùYW†‚ñˆÔCjÖ¹í «Cˆ€pjKqµåW—+K/ƒØšOy”1Ö#¿ò=Û#;w[Å’ÍMÅ«#~ÙËãLUŠmå\[³’]åtä$,Ú:5pícÛ ÒböÛ‹ŽœÛ7k›¶Äç—I+ô™dhÔÝ Œ~S*áP㨙9)bÚ-p%Bøq•ø-êQvß|yãý«É¬ ±µÅñÅó”î8+’×¼š@ÈÂÅ(K­Œ3‰ñ<ìûUhŲE}ó¤èTH‰)&ÓÙl:ŽÖçlÚ,nmwFKe3zšˆ çn-ÌŠ††áZR¿m šX*/½yáé+Ž0´nÿó-͉5 ³~Çb¨×ÀäZ˯Šc¤å .kåœ(   æAd£äÊ%Y…%J ¯aöÇÛž˜•¶WL¹½¾p£ä/ôãÿ€‡v¸šç‘ hAoœå%æÎ;±ø‹Èkǰ·f¬Cjç|\úæ:Äö­ÔþaˆBʪF̈ôÌ•ˆÛ¸PZ¹M%@Ë$¢Šj^ë{wi°9³m:e+C›«Ú’ IãLÁ¦F‡I‹ynBܨ¦ÙFÑÜRâ…Ë~QÁæ ­!ž]¹CPâŸ6yn?eìi™í¿üÑ={ÌàWvŽKZe+&߆Ÿ¼R°o¥Ð´cœÎ‹+Noÿ$*-H£–áÝf‚k ˆÁغ3¦n·K›Ëó9Æ:Hy@©Ðp¨?b1HŽÚ¼µÍ4áŽJ½çžCâLeÎlƒˆq›0'peïza»¯¾Î½ìƒ“îÈ‚ì·ànø+ñ–7t•¢Îâ#ÈWíb‘™"©7éÊðFëÑÛ¦÷ QíŽý˜%¦?PêyæÁÚNœÛËCå¥qÀ}¼QÉMOeU†ä9°5ÓΛKÓ‡‚øß(†rBþ´²Eñ2ª7U© sÿ +5‘læÐVò†R?¤g NÍؘŠÂ¼I‡!J±äïÞÝì—ÛvËdæ]º@÷?PCM2neÕ®QbKH‰ÆÞzñ+Ó”¼•àÏ óŒï#ñ&[æž@Åï mg|­ÿšá;f&òn‚&ž´±Í¯kZ—Jª+n®°·r¬£Ç>^EPúò€¨R^‡èýM•Í“îæhç‘ÒÅx†5 Ðïc†)_µ‚1¤°¸ö“O™L9¬ _Œxüi»¯+§‹¢A[^NÜÈn"–É8S( ê]“«.îq DËE}ío=f“°H†!ÒGq×#ÆË)­õo·QXÁ½ì/s¶é0-u £8ñŒ­*(15E»²`g«-?Brñs p[•qºH•6"²àR\t§¶Ý1¹lÓÊù'~䨅KÀc#{®Ò\ðÒ."¢œ ”«k icsêuÓæ'ëT‚'’‡7w¹eGäþX“9Ø6ä¦#Ëí´â :_hƬŒ*‡i8º"-ÛrFåZ:é2‡[½çJ¹¶ÃÿCôe½œíÓ(¾c9d&•w 0r^ÆŸŠ¸§¿in#‘¢ºÇŽešÉ¦§™ÆlG¢¸ñg0iO»8Œ¡†›v…)«½ªÜÅÑûŒ©8™‰è…-^;þäÝôýãÕ·Æ+ï7sžÕ½ñ·퓨µ¥È`Êo-yå${6ñاbDìé)ŒÃp«,ÍÑÖ‘Ž~›F=S^•LNo°{w±n—W;ßQmr±ÇD¢RÊáOLE¤ë¯5]¨ZxCŠÊ)Ù'®Óé“ió}ê ÌÜ'šï«p¼]Ãù‡X¬¥&äÞ\Ȭo û¹üwðûã[qvû(ûÌj-\t““—ð¡½>ÅUÑúÿ¦ºVÎ&³c³tA­v¢é5—‡SNiZð¦4û½´:L--¡Æ¦¾p¢èŒL·“˜™E×lk(Š€`ÚJ!ÝGq(%T¦›®¼û+\Öixô*f Š!kákšô’³ÿ?ÓãÌ‘rùˆs_]ó­X·UÙ¢ãX¡ÅtådÜ$˜»âM´ë©A* ˆeT¤C˜ªéY&¸:2KÛ;¾m1¢Ñu3ª¨ð^¶²6(Æž1‹IæD½åà-{](¤Šyqºž½@`Ü NNÂõ9–܉R1Œb”¢!Áìw-òã¬mì /|Á  ñ?PÌö T:¸ÊÐ+šµ¿¹ÍȾ§ÖÖ=ˆQ›õ1w,ë7">lªk*Êä¸oþ÷ol½*DÞE¡íkš6@ uk$  €˜ýÓÜ»–5öºõ˜ŽdÓåÚ¦\p¦j1êçíë›zÛrˆ å£ G4leQ*§+fö@çD‚4îv¨€‡Mc¬/®m:?gž#ù†Î2|t1!g‚¨™‹Žx­¶‚»š0d.P"ñrPTÎg {­J²¢@Tô –A y×dêÍÖ}á°ºGh.ïíU™î8®‘úÀ¹CÖ–¼™“+Y.âv®wˆr&ºriNN´®äŒ`ññ×s÷îg¢Zúʲºü Ušì¸$} 9¹n D óÔ*§Ñì™b¥ÅÔÊ¡„ÁB¶ ˆZ¦t=̧Û˹K¨ÙÜú1ýë8ö¹W¾<áûü´È´† s>–JA/.eJám¢¹”ôˆ"à5ר÷­Âã®ìa|Ž1¨Å1þØL1ÿ˜Á™Ô˜¾¢œ+ëÏtTPÊ«þ^»d·(²Ê;âæ@‚$)Œ¢†= "au­5¾û±¼Ç¥šžK+S·>qà¥Þ¦¹;ŽØpûzœß?ùÉ…qûóEdÛ'Ýù—Ýø¢pEŠ·rc”Ôt¾JP#rìÖª÷4DÞ×*E“.›y·M¹ì–V[´ŽƒrdMsF¡ÁØŠžÝ$€k%Í/`k°u.äo¨'ã¸3szxð+ï$Fæ»öáä¿%okU¾8gs±k!°[8âÃ;黊>]+R=ªÊI®ŠÙÊ`EÎôê·¨’öÃ¥ö6Ûi^÷¿S#†N Éµ4OÏTÌl0éªÇÀÖë+2ÃgXäHåDS1V€(Ñ–…¢&Ý´B 5g޼Ô7Ü/¤”º¬$üV»#«­:2ô›gÉòàÝ8õŠp1“Ø®ÖâB™MÉL%Ý_oQÖ£¶DcÞ­….éR¡®¦Ó%»ÿQÅ‚\ˆóÒ'º(ïâíæ1NNìVÚ "_£òkÝ}_ºÿIéýº}ü†ÿåj»™úZr¢..L¹uàÎ+ñ~ñapÜÑ\gÉ™fö´² ýÞâyE-<¨ÎÊ1ó8P¥Z&Ö•¶]»EQ’tU>ó2DE"]üow÷×xé¿éï™…ØêàiAJaJ&µÈ(’Ì 8®­úo[°í=Pøg"›PLs);‰WŒù%vl¦¢¤0×ÃUÈ^M'WCq1WýÛÊfÅÄÌpÇê\`SÙwg-yˆ´´k7 ›A8YE ™„àL³wä8 fÝãׯ¿Vþéo»†ß¹ÌÈæ·QúÊÅôl´jè—½?p®J±9yÈìÑeLkÅ®2âi‰\Ãh`y arì#x)KÖjÃ:ÅLìÿ…Uµgˆ;G´íe¢­Ê’®P¼öžÚï{·Üw‹û§¶Ò!¤†žg’5ü ZæH¥(J~Èç¸ä¨Î$çgÿñ}›Ã¯Hì"¡_å N>Òq˜n¼åÉŒ»:&¸˜¥ú6= ªÝ€kz8)|ÂH5Š|Å«Š[®©úwc¶ÚâõËÅ ‹ÞüøsP¥j`xkX*ºë,»3zËevrC¶Wa`”9J#lª"47AgáÖ‡ï”o ·–!W€>ÕôÑÍ#5µæÕ«'è¥ék²(š,¼ÇÍÇHƒ´SVÿäáÎù£ÕSj@¿º·öof¹i"rÙkÛ„“}ÁHÿ—oËŠ¹¾6›ió®×un±jÕÒ¼uÈÈ,fåH7¦ykælɇɮyÿo[½þãÕÛÃ.œK³È¯n¶&m^]+±Â‹óÅÄ|Eä¸ëp;d»¥âÞ”T¤~Ê»7”Dhaùõ§õ×Rnu•¬,{„zÂL¤‡®’zé¼V#=ú}$ÐÀS#éÛ‹HB©¸ˆ\79 Q ¿F¯Hû‚Èîv­§ÔmA·aùÂ~àb³ž²€åìWý(ùÁþBåÜK‚îÜZçå5ñ%Ñ1iC²½ÂÑǧ²ânÃÁ9M©äY;¶n˜°IB¬ÝF*‘LqT ]¯sÞ ‡Lm»•‘?µô9p¥(0Ê”#¸Š%É'§\ܨ¹/eæÏXL§?lcîpòÒæŸ^>Jqhè¬Ér7"1ëËÎÌK½{*Ö6&1²‹ºxíd› ™Ç85̶¿qwmÒâK;Ë,ôq¥r .$Щ$€8¨M»{ΖT¹O½2«óÜ2.‘k‰sŠǼºÝÑÈx5`²Æmm™©r.ÝfEBÜ¿›Æ8]„J7ͦ*%•¬Þ‰êç?}ô.Hå:M{òù>Xµ¹üБN>BcëßÑüêÊyí<)žàøãéý0í’ç8㋽s‘>ý‰TŠ·ZE‹×‚±—x‚€%4õ2K¤»Sv[ûýË] ÜÎàN§˜üJŸ£Ó/sùweX?&8éëkh0Æ‹û†ió -Ƽh›¸¶Ü†ÁP–5«ŠñeÈí>ËÏß™Fø²m(¢‚³…!%ñLœÓm‚æöÏ{ÎÙ¬ŽÍ ø»H>aíÍ–¸UÏŸBKÚ>Õ'å¬Àý#Ý9Ýþ^b{Â\ˆGùC(ÀÎÊ ¢ëŠe$nÙÅUb§AUÔ¨:ÕzsumÇSGÓTñþ">ܼJ •Ÿ‰IKËÉçç;íì±#w¡Ê\ù.õY…{ŽfY]yvê·®P]ár»{ši´’ )õŠ ì†5 a hžæM¸C¹\EÜ®¿M~‘Š|çàx®žæGØ'ý:WÕ»v"X¹nOòÒÝ[D?*)¼U6sÜRRL×9£µµ‡®tÓ@Ià*“’n…±²f{xÑ~¹*[\é¨PãÛ¤Ÿz’ÀfufRcÓê-‘=3½vH-“LÏx™‹JôCo×€Züšˆpo7|u ¥ôÞ¦ÇÊOšD‹B[ý£ø®Bà¬;a>°Ⱥƒdº«1D{¦ìýM[ì8’¨ˆ˜Å®êT¾‡\s~ê Å›¤öâwpøª©n\ד^+·˜6øÁx Ð'šÆcÁ‰òÁ±ùï!†Õ¹žZVÝç|’ÕâÊVñ¼¬AI(­‘t(Ñì«>9&ŒÐÃÛXúîý8Ÿ¥_5àÔ Á¨?ËsdC­Év#WØ:h˜ûýCœ_°rÎ2·Yb/PŽÙ ­Û³†¶üé£ðîRÄ)?MEf°%•/.³{Yqû’/}³JQW)H–í³·Ý¢ñ»SÀÜ£Œ†´ŽÝø; °ú~pSŽð64]°”;(DÜPnNqÚŒÄtÄ*§i3%åº/¿Gaˆª*ER1LPxNöÿxnå·n‚FÉÈ£¤ÓÿeØÊ…¤î±ÊÙã]ãâ>_BºñòEs±Sh@4fÙ&¤)€¸9Jì %LÅú¥6š€+×U[†¹®~OO©½QÌ)RZ}03)˜ÜÓØªQÈÊØ$àC“ɪ©‘L Bãð(!ÔÇEë¸5Þíï©NÙ¿î/s--¯[ª0rF 4þxõTœIcel}7ùï¶s†—Œ;‡ˆ®«·šö2ÝQ¡ЄhB4!F„#B¡ЄhB4!F„#B¡ЄhB4!_ÿÕ„A(.ãÁ3ê¤tÌã@ÜBˆ6~ |Å܆‰uLŠÕê´–Ï9?Ï>5XïñòZ˜®K:Cgçwy^].x‹AÕ”ê×|”ªÒœÎ?¸ãÑi8DZN¼Û¨¶†î2(š½×Ûïs±mÓe”6?S]x×NŸ A‚²·º10ƒ•VÉÏ©†n¸.ÿNoOË»+ɬ¶@[ Þ‘s’ÄK†íÇP"2ÇŸžzàÊ,º¢Õ\Å0£Bí6àzϤof7Ól»kîÁ®·E‰=®hpi=ä'ýHGú-Õà«õñ;ÉÎkæyÓ•·’·¼ Rpv]¼Ê=¥¿dãËe©»­­›ЋI¼=»‘ˆ~Ùw(ª¨õ§uŸ¹&ý¾Œ3j4 ¦À(Ó\¹ôn®UØK=å®8zòÏ+`‘­»-¾sYðŒ”y sBIÅÏCqžê´î;fãa+q[·D$“–O™:nªK·p` †Çí¥ãÛÐó]¼ÐþåÕãø#p!XZšA^ÿ°*™…ýO¹sf$¯¸}Ãl“®8×QçÌ8ûÝ Ì[ÿx¤å7.,{vé¿®KFÐvã¹±DSf¬iĠЩlM:ùz·cÙ·Ûí!½¡F³žœhI W0=‹V éŒ$ž)ÅYÁ¸îNBå+vÙä6O¸æî;ÖéŽÍÉ\·6AŸ»ZÊ6~òí%¹qÚW ç¨ÊI‹´A¼ƒb‘Úˆ’(¤nsu×V÷ÛÔSÏsDÇ[%K]PEHkšp­EÄ Æ )œ±)Ç›=B¹{Êö=Ë|5àãkNÁ„“²q-çhbl· ~a¸IFQ°ÆòOs´¤<M™Â2!­በɉ·|Þz÷iܶ“c$äº=-§”N^l)Ã0(0Re¦3Z)# » à’M¤¾ÃÙÍuâS™Œ±³½½qÞ:/Êö)ˇDž¶®û=Ë÷í–ˆWt³5;XŠ"¦â‰8¿In[vÕ¿É4övó1 €%isAÔsy…4ãQBp5¾¦BKAI~Ló«˜|ÕP·¶iâ—mÛýš16«Ù‹qÎS·óM½nÜ O´·¸.<ÓxE¯³•œé¹\é år¢dES]©ºÓdß,E¼ñÂe sPê5À’~pªžûˆän“Dü¹}K9”¶!›À1\ôþ‘ãÕñ"…ÅzX³—7ÈFOM4”…‘JvEpäcgfãÞ[ÑË5vs™Ãa`ß¶r‚)fíý}²Úí¯±e­¤p kƒIzðŸ.Äz~Úc9R|g@æl‡Ìf¥ìL¿v_VÍ¿w¥· %bJµÆv”<Ñ¢ãÜÉ;”›“ݪáú‰yR#Ó¯:‡þŸ‰–w’d 9ïb@>4Æ€’IâT§Ê"hÕË牷ã÷?¹eq?”Þ•¸2Å»3j’ñÑÙˈ±K㻊וcúq9ÛŽ)ƒ̼„ŽòYÃ÷SnÑe°L£7 œä]ì=\[iu¶±ú²sy\Ü3¨Çé§qH9ù\ÕF­»‚3*fŒSró€Å9s$cxÅ:\-yÌ[Qw"*5/•2sÌctQL‚ Ô¿ 5æ¶Ø#Ø·[«x_ªHí'´T€~!P\D!‘à*›ŽòÎ?l{Ž-ÆY³zØl\»qNÙ¼Òe*nÆÚ÷U*áfg =¯ˆj)Ê"]PôÍõ–Ù½EygìÇ–P\ÜxÑ®a¨á;ANÚJÚêp@╜Žõ7æO1›AXùï‡Y—=ncîØÄùz'!bvHèùñäÃì÷1 ¯—ˆfb"¬{– £D fæ‰Nû¿{³nû4¶²Ånçȧ–¢•o6pÌ`¬å¹c˜ê´ÕÆÑ‚{j5YFÅš¤U b€íÚ@ íÜ"=}¿.¼‹¸ÏKéÿ(¸ª§º‡”à²c9¿Ÿx_q¥yàN;q—$äx÷óŽàr^g²²%ÓxZ¬§áÛò0vÛËK*ؑёkGµ\»ŠÔ^Qû¤ÅqEaH;§µ]U¶ôÜdIglnK‰õ\×@p´@áQËZ¹ØÐÐJµ±fÁ«·ŠªÎóvYä†Rs”/Ž9ñË]SWEÇ|¸ã¥—{ÙŒ²ÓxH7•—¹ïFW†FÈes8£ä”Tjfe:®×QR¨¢‚p›î_Qm;üm–(bl¢µ-LMI­;©™ÍbêfJ&ÅÊ>Uð¢ì¼.ÜK"ñ´òl[yc å‹eKËd¸TÛÈ6E¥ÅÞFD«6i.ñ$Õjñ:.TEpY#Dö˯À&µ.)©§{Ž'íE¥ÈŠ£ðªÝ;ÍþN« sÛ‹hþ“-¥—íšÚ6= ä5÷ž8Ô×4¿]ºi¤hRÞ?óëš|0µÙà®5ñbç¾Æì–QÊM¸2$œ ù`™<©›k1YÌÒ‰EÚHlÑé¡ÞL‰ WBûÓ](fŽÒÎͯ}C¥ÒïUÀ»V—;]4ƒJÑ€­*‘Íh4%-¼á™ÓÈëeÕø]Ä t·ß1ÁöÎ;ÉqxvjBnfqÅß%d/—ßÌ'>uåÁE¬³X¢´j‚@È U;·Ž·é+ޟ¶ØÈæ¶šÇÉ©:Ëu‚^+AB@“GÍ KBÙòߟÁæ©¡-ŽAñ…Œ†‡RذòÍŒ2ÄTÇÐ*ÊEIº‹µ. Låp ÁÈÅ‚^]Ük¶È¤²ÂŠi(¨©®‹¸û¡²uÔèÛs6š¿ËW|k‚Ëîð[…V¿ ò/˜\7°®lqcÅãlÝÇ|„àò—¿ye—#b©)Å<–‹bGÑvÔªâÜŠ±|“U&›…Û¬ªD1un›÷Ns²]zrXF‰¦ãÝòƉ†Ý“ob_dNaòk0Z38s`Ü!Ä [wväh¾>Z“з.HHÀ¨[·¾Bº®[¢ð’³ˆä¢ C6rÊ1Jy„7 ¶ãÖ›½•žÙmmm£œBÍ%ýÏq%ſݨorÃî#cHcCAìâ ’Ø TÇë[î v @ÄSÁMÀNCwÄ8€€‡³\ÆÇ}Ѻ ¨Í©UÜ&mù=›9Uê3”0´Ï'Öµ2Ààq­œ•«pÇ·˜.›8¸ò ÚÓtC"^fd®Ú k•ƒ~ÛDD¦ö}ëÜOßmð´9¢PÚaÇ´š“‰ãõ+I/5Æó-¦LÈÜ¢œâ=«éÖÕ{pœc·3yyÆÍ…øºžjV\¶#™sÜ Û§Çhݳ Ρ"S{÷©H »ƒ².Yõñþ„ld"¢¸ã\q¦t¥qÉd]·ÒÒâ¶U™ÞÛØK‚ FRPÓNœFËÅÊÆ(‹ÈÙ8Ék 프{ÔHª+¤r*Š…)Š`×4´ßæ‡t}ËA­Aú”ÎCõµ6.ïQnD] å9Ä.'r·&Ú‘¶¼.rÈÖnD·2\ì\A„R5Ö1ÉU¿›±2…Äz·»¼Ç2¢rõsÖ{FìØíem5ãž ~4p⺊@=F‚GjLæ+ï–\þÈ6…ñÈé(VVÆ3…<.!ÃöºÚÉÄxªSh‡°ìÆj¬‹8oݸYÓål‚'\È ‰©ên½†X?oš#€4Q­o`!ö&./†Ø¬Œ7©)8ÃŒn|†ø[Á ¼yìè» 0¯}âL»pÍæhhÛmŪº¹-Ëù :´´k÷§rŠm[°Üè‚ç(ÚôÏ]m¶[q€ÛÛ09 :u_AJ¾®5'&€U9 ËY4´ cüqU:Zí¹”º®U1¥ƒˆœ;W qÖ*ޏ!ñõ¬Dc°+Kb6è¹.ùöÌÜ‹Q]@s$íC.ª†Þ Ròþ¥ÜvÛýû÷vñ±­qÄ4Q¢‚™|sÍUÎöK#Î{•м}^¹BßÜ|TŠà§½.¬i+…ó“ÈIÙ²JÆK·¸$ÌNI åÔûy(Fk øçMÌÍMB‚){F×ÖÛl;pµÖÑÇJèc\Žx“^úÕZEvÁn†Ø?ñU¯ˆü±ÎœÉwFyÁœ`â¤æX¸efæmI<‰då9T1,uÀÒuŒÅ£‹[Ú¹’ÌV&Õ>vb„’’Žº.)Ì¥^ßÖö;måÌÚ#!Î̇rƒÁ¼Ùx×Å";Æ1î:*åžJó"ûa{eŽ6ñwÞîfîÌ€ì+þʺ/c%æ8[^NnŒ¥}1šHíÜÆX[‘éÌŠ@eÅ4ÀšäÞêõNnRG8´µeèu]+D®m Hsµ@T«V·(˜¿tW9  gxWþÝ"N‚N†½¿ÙÎ#SFÈZnê!³´¨|¡ø¹ ä\Gª--{ð©͊îù,máæãòÒ­6_oBg¬ÝCJUQÜRÔ´øˆaè!¦,7¯rÛ7») .a‘¯±í ŠöŒ1QÅ=i# š7°ó‡*Q«Tê4!F„#B¡ЄhB4!F„#B¡ЄhB4!F„#BÿÖZÛ ¨ª Óhí( €í÷ôðöëæ~æÃ¥Îjl…¼ä[¤qò8š†.ââî &ÛÖš×És[V¸… H«áÜ,Råî¨Å¹À¡@¢]z€{vˆÁ¤Cs;M=Có¥‰â£w5 íÔȊ⚤Oi@¦¥¡Pñê#óêm¤£÷QºsV׊K8¬Wþ¢Þ .b&pM»Šølß\3HÌÏâe8‹ŠVÇsò?xG=$¼Å–1Ãr’HÈE³\,ÔëÍ‘R»“ ‡®ºÜý½»_í_«O#"c#©þã@oЮã»m(@øeøÏjÍD8•ytÛÖÜSˉãû±¼lCH;n,ÓNÖ|æ2Šm øA6m’¤Ý*e €â_¹E{}pëWQ®qq À šàC°dgí` ‘¼c"”j¬O`HgfQ©]ûÙ0|À[œÝ[¼D@k×pP)á­(=í$‚ió&\Ð)CPUm艈—ŒÆ«' 3l—! VÒLŠ®™”¨í/šDà$(€Tß.3ÊçklŽ?Ø«Áß?Ñã[ná)>+3¦I* ªë“Èͤ$¨ì,{² °¢"PS¥u‰ö¸ÈÒjåŒ|½Ë*Û‡p•ñm/Ø…MDæâÉÙ¡ŒŠû¢fÊ(=ÓT;…8›ßM4é'ôõ]@PA S,k +h¬ã™8Z-:91[”’ ˜Y.B¢C3ñøiæÜLcoæ È-“K~)¼«&­RM7mVˆ~€ óQjÌVP” w ƒÖ¾ñÓ÷ä‰ ÀÔGa=OjÅií^ÎcؽLÆY£u„¡S§0ˆü"iìðÕ“%‘”-y68à´?uÇ¢S‘Ñ›ã! M´ˆšƒJ¿NÏ$Ž¡sÉ .¨È(Üzg(‚ÈåÞ8…j""%á§-¥,s(üÐO5J$Hxä½6Ój%!@@GáÚ"Ô~Nš·7¿Í)ªVªŠ°c¡·™“c‰L;ˆÐ=¢!Ö£^¾ý"I%1¸z¤ %a‚²6 hs¤Ú‘ìÇhêŠ"Q(í À;„jb޹‡P~äI%%v}«-qÈœg ªAº5¡‹°)TˆZ˜@wÃ§Ž´×ÏpÂO¬ê©~Z\¾AE& )G3¤]…©€:õ¯þÍd\Ü~kª™ ‘ޡן'm:Q(¶~n<Àñ•¹@â@îO¥Ó¨të­bÝ'·Ü!kæw¦ì3í¢(iž)%÷{G,ö*Õ3—hЧ‰Jb…xW¡zuñé­‹q•ñ^ëÖAÜj–‚&·+)5²µ4-I.-…ƒ Úº* @ÛL P*”5€AüzºŽWŒjœm(ÕDU ()ÆÚ(ˆPKù¢oÇ«å™ÌÁÔF4«”~e ˜ ZÑ(WqiñT(PÖ¾ß &<ñ8¢¸’FkIÒ5»¶EPR©‰Ž‘N5T !N€SxŽ¢_ºF~do"‹#2>5è R"’I™#‡ÂR‚Q ÛNQ¨âõ÷é³1–-EÄ’³õ¯9Hˆ‡&9ŽÁ¹ûÄ“9“¢`¥ Pj:a˜1Á¯8`›$‘– {7Ì­HÑ N!vö«R›óL$ñ ûôΧÆóÎHwýJðu\qJu¡£éT<«pó %(ì7r€tºu¶ÓßQÕôZjjÓôqO1Ü¡¡ØÑz°lÍ DÀÑ‹5À^Ñ:pí І ³X¸sÜÍD>”š¼ U¨*Øa¿º‘tí·)U 9`pLCíï¢@0†¢A{<5źÞ\k:Á£±áÇïJæ'U±X â=ƒòD¥¬[è %0Ô: a ø@Ô®’Üu`ëid­Ä4·OáøS—ü5T›©ŽoU™?¿â³•YS·•  ÉÝ’FVÀPn¨˜Ô:­„µ÷‰+«Ù4ú“ALÌߟҢz`ŸR«½š¹€.‹_I9HÛ žb‡SqíT’”A2ˆü)³‘Y%GƧxou5êÏûvê‘u¶n]'s'çÛ8Í9úOu$¹²ïJÝ:zçTRZ=ÕsqGÀýk§:ô¢Ù¡ЄhB4!F„#B¡ЄhB4!F„#B¡ЄhB4!¿ÿ×Q@²õ*ˆ‰N;kÐ¥÷P@iZt×ÍKòÛL‚Òâ󦨀…Ø&©ªJSáëAm<5¬¼8)g"­VH•ALÁN‚Q ÔKJP:tñ~¡1Á®ªÀâKT%ª»wP‡¡h""&-MZÐK_hêu5P°‰ÒÕ±ƒòL¥™ºQ>ïie2÷'V'-CÁ% SuñÛ©×2Dö´8Ò½©`ÐÐW@#ݑŭpŠ'å•MšªdÜ)*ÂA2‰¢Tœ§Ü¥>q¾$™ ¤ù›E ã VòV%£\³*ˆïr$jää •@ý¾)`7bøô7Ošˆø\ãÊòHÄU E&Ìœ«äÎDdÁßmC¨$2N]§¸; Qº¨˜S ý„¾ÀÓå¦Iq€íEFb,¤Dôr‹‹5ö]¤SMÄ#Õ…‹ä€¤Ý´ÍÖ1T0ÃOÁ¤H CP›Õ‰9¬è¥g¶…Èèä]6ë)p#ÝSQ#nDZV§© õ8ÓAi «³I uY¶¹ nd9Ûp‰™É5Ü(ÅÁO±?DÉ$Üâ&7j!Ô¡Ô4Û_¤¹œ jÕ3‡ÞRlÖn4v %š‘j¥Û^=c³”25«ý! nöu®a$Tæ–§¦Þâ* á7vI l‚â`0‘ $EÂ@1A>áËÔ}½zë^Þ-ÃecÂÃÉ}0Åx³nõL\·n³Ÿ.dŽª¨Aw1ç0P>  ÐDGKµ¸1´ÝŠFªÀ¥ä¤38ùwglÅ&é¹lš¬D S Ò0}Gü@­MPÖÇe;Þ^òQ‹•6äŒacò[9´How[Qr ½ ÷›3¤0@O±4Ì4ÿŠº"il3DN,}iÜïãTÄàpK˜w=•Ú©_ˆ í Ó·à5ê& ‡Ï§dÓ,n`ÄtnÌSBH½ÄEN¦- `­áˆ{€j4ù5ª;–GaU ’Þò´ŒNR¬¢b!C€˜ÕTz€Ò£òÐk]E•¾WQ$­Ê¢JeÕ„£A5F•©Ä|GÇR¢ysj‚I¥V°ô*¦)JS »­F½z D~MH!Îmk‚%Cç€÷?÷»”ê"j€Ô@½4¨ÜjÜ2I¦“TÁhJˆWhÐ@Ü%Ý´ÀÆöû+«x‰v5Á, * þ´PäPJ1U¨ü^ß j&¿.Ÿ.n%Ç ”'šÅ~P˜§Ú4§^»«P¥ÃÝ­'¨mËØ^°ÜB®ƒsÝE!ÞjÃøºü%ú?¹”íÓ#ÇõI·ˆ;7Rƒ¼Æ5FàSÖ€=šc…Z±^ €¦&:*ä•(¦¡ ùà`íÚ?íÓOµæ9/~e–€IÔpHi˜sÄËÈGˆQ4Ü(ªuüäÜÕí m5[½Ü¿¸²µ¸n&˜Ÿ™šÐ *ÔÛT(h˜HÐÕ÷ @­tå”ߘÒrPèNÉ%.6¢RœLP üh€ÒzW¨ëyÛ¥Ô[*Á¥¢€$¯ib˜w¤p!ê0 *Q¡‡åêÙã 4w ,3NM(—e]„GpãP:íèP£Ô¡©18Ó2–i¨^’©÷Rtå(€ÃQ=h>ÿ“Ji«ôÕ`‚Or† c¢ëÄÄø†•èp¥j.f‰"8bV(á’gÆ«¸„9„ UˆP¥ *S˜z€ôëO—U–bñÌ Q5§Î½:ÚÍ@0u²‚#Q¨, 'ê t¥|5†‡E)k›ƒ¾Ä—4Œj–ÒR`'U‰@HÅ ¦1VÝBAÜQê!AÖÇɦ‚ºJe팆 fõSÊS¦m¢oˆ6‰LP:‡Ñù}š¸·h¨cŽ5Ÿ½{˜{n© “´Ê¨”<*¦¶µÔ ‡QðÒi©Ž©çiùþA=&†–Ð'&;”ì®ÔåÜU™(DÇã1jÙcî)€âMq§MÁ­ ªmL°ÎÁÃêHõO¯½¬Dß°pÄÆ]±@Â;¶º ­P  "z’>]r-ŸpvÛºDçFXÿp?L{*“s®-ÿ¼ÜGܾ¢ŠáÁžE¨z“éÖUˆ˜ä'P\‚bRhë— fˆ§©.m\Ïë90®ñÛOÕ\Í%§˜ñNËÇÁnØÿƒg?¼-ÏëhjŸyÏàýŸ³ØÿjŸûå×å&¡Z~5æTBìûT?Z·ä lÖ>W|R¿Š¦Ü¤ú8Ãõó¬u?þf÷ý“~´ÅÆE!ã|þOû¬Gåw‚Œ|ðø„äÝG?èZ¬ÿ¨TöæTm?Þ¿ÛþÔWþ‘ðX…¼oâÖä?o—˽eÙ­cÞCç/èV ý/‚ÀÌ-×Ñüò†™XvnKEoä›ôÃWpyWÝö¯†_I/Öééä‚fÚÚ¦ü“ZÎóú¥µ[Ëgì‰óÿ‰®Isú’øýŠDy0{öƒþPÔ4ÓüŒø­c¶_Ò.ž“ôJOâwÁ-r/øˆŸÐüšÜì¿úV|ŸæwÅ)å Q[Õ?vWù&ü¤Óãõ‚S³*§ï?^O÷i×þ›>?bBcBþì‡òÔÿ“U¶ÿæ$BþI}›ÿèãüèis~´^)·fRŽOí“þYœ6ž‡7$IæÌ£K}¢ÿ®Sôõ)ž`£,“~ãÿÏ~˜k?þ D¾Aã÷¦‘ý¬¿ôQþ¶ÛZ—R–wØSLóÐë÷x?Õ¡ýg^x¾ýk¿ç*k2zÜ4ÿ6ÿ¸ÿ9®Þßò±ÿ²+P¨>]«{jˆ‘þüÓ[L;ý_ò7ìO³ÎWêÿü«ÿØwÿ¯Gké?Gÿü—KÿùÖßîXºU·ùkäoÔ [}F„#B¡ЄhB4!F„#B¡ЄhB4!F„#BÿÙlibspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/resources/images/s2_box_logo.png0000644000000000000000000001533511134200352024647 0ustar ‰PNG  IHDR¢M%à¿L pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFIDATxÚì]_L[Wžþ &ÐØÄΟ§alE·ŽµZ"Åt’‡EZjÔ}†dÛ¨‚HwêÑšŠH È*l`¤PÈ2³šU »K5K:˜nVÛvM7 Ó±±IÉÔiHí`ÆÞûÞÞë¿çˆa9ß âÞëã{ÎùÎïÿ9ù|>PP$"JD JD JD JD JDŠ IÄXäd)E—n¤ï”¦‹Ô>Ÿog²Xt”»[oæùfœO|¶óﺦ¬ðšmÖ¨Œ v‰øÛÏównKUŠD8)á  .¼+x°´èûè‹ÿõ\ý§æ…ûž›mVïšQOU'¡€œ9E,8Ÿøzÿã×Ko >·X–‚‰ø»»*yR2:D"œ¤ÃK!‹ ¾¯>ýÄów=í ¿àæ’‘„ˆI¼’ÑKIHÒ^½rèhÊÜüä7Hs²”"!ŸqÔqS@‡@!+…|ûHKÙÙö×é¨oQ¸–¦°´üŽgŸÂî‚ge>äÇœïÞ™ŠùŸ¸g¶Y©æªâX‚oJÓrñZFÒRöÑY à{ÐÞy˜í­°;‡Bî,ÿòÚ¥…VV³ÍºB¬š“Å8Ž„ªÌk”„a!NJGîË"kÏ»!÷~ôcq)€¿ !m/)'K)‰ å}Ir:^Ëè€8)Ž8ETdí©<È\“ïý W•ü:€]9YÊ$""Ôs÷âni1•„ÄÈØu<äÚÞ—“^°@2/ÿ:ý@¨Z~•Ž.1$©¹!×^=(Ά?-&"bj_€4LÃë ‡Û ½qVû̦{÷pÚÓë…ÀK F´9}>ˆ( â³¥˜´˜Ó½(™›»C~^1¦™×L‘x0$ÝÄð–ëÿ !¢Õ>½qœýßùì3gÞÁœk”20€Êcå~S"ƒ¶°dËõ_¼žä»¬ë†nb˜µ{ cPgçA¶ýu¤¦ìÃ_×!cWröžÝòDì9s=g®lÙþ¯9õÆq\Öu…¨—ÊcåPgç±ÿç¾ü!––böÉ ,.?DîËÒ¸åÆšÑjŸAU[-OsI¼ÚíÎ!¸–¦só£0.¿Uæµ5'£nbw,&è·y×åÔ9ùx«°„·@ wd¶G"¶)“ì€Fu8äsÁ rìî8fç…¨Zæœ<úS(™ìµ¬½ûY5mµÏ ïÖ¯¢ö/kï~hTEÄÎÕ>ÝÄ0œî§!cÂÅÉ£åì{l"vèºðA+ngÈ=maIXNýé¼k®Å)LýéøQFÖû¸$mêoFU„Ñ–ïs¦}·Â.¨`(™h¯n!šÃíDqC)û?c’|p£½#¼ͤù.nž¿Ž² 'Øw•Kýv¢ÕþMý-DýÕ¨ŠÐ^}1â☴˜Pßý>Q¿üíÞ<ΊÃíDU[-ê»Ï…p¹D†ž÷ø$t-M…ÁÜü(ÌZ±¸üï|Üïí"I/Ò –.eN ¾ûÒͦç NASKHœyGî»Þ±˜â2‰¸! p÷âé㆗ˆ·3bÇÔ•Õ@.‘±ÿ{¼ó¸÷u]ÔvgŸÜ€4õU؃ÈVœ\×ÇÑ;2"•Õ9ù!^è|öv§ ²/•ŠLôœ¹²ò'-&tèºPÕV‹‚SG°óo²QváĪ ô`5ëp…zêo%ˆ“–»¼qÙÈDÄË*™‹>Ž÷*MÍ…X —òܳßõ«LC§•ÇÊ#ª"‡Û ÝÄ0ŠJÃz•k uv~Â':ÜÙ”D´ÚgX '—ȈlÞ‘Þï– ~A®m87O^$ÁHÆï~c¡sŒ <‡“ º‰a|Ðß§Ô1Eµ ®½¼ž í…‘;àUQÇn'o‚Ãm´*!ÚšŒw\§­ÁÍó×1ÝkÀt¯MÇx‹©C ´gÇÅ|—ç4l$(“ì&›žˆÜh¿\JîyuèºØHKÙ…¬TÐ ®¬Ìó6ç,ÅAÄHá—öêæ¨ ¸!›µ ˬµD3o½©¼æxì îd •ŠŽgŸ ¿@Ù}, …7Â-°hé¿úîs<)sZ[³¡&WÇ“ÐMý-!Y'f¼H£!ë…¸2+êœ|AUĽ#h¬8 ¥"“•Šá6f¯‰QîvâÀÉ8ÜN6uwDUÄs&-wqY×Í#“r ‡â†RT+gC5·}#¼1ШŠ6œDô/Žj^.¼ª­—u]ШC.•aÒ|zãxÂmȸˆÈµ‹HQÕV˦ʲö¼‹9×hØ#+‚!t[ë¤ÙÄ+$ÐM -š`5n1…“&Œm¸Q‹Zë´5œæIõI‹)f,õà ξ«æ#ùE<£WhšHog;Ÿ–²;}.-eO=Ç:{G©Ø/({À(R°7V[r‰ £­C:Nwóüõ˜Áìà~¾èþ‘›“´˜xÕ,¤àÆ!3vUŹ$d‚Û±‘é>K®HDRg硽ºÓ}†¨YuNnž¿²ð䚎7`ºÏr;V~O:vH‡ÛWçäñÚ‰^œq8¢“"—ÈpóüuŒ¶ ¡N[ÚU´…%h¯nF]Y ïù¤šµ‡JXõO€”«ÄIéØ--d+I,å‚óÀL¥R±_ðj×–@[XâOá™MDmL÷0i6ñÈ †Î1èã¼¶åq;g¿'pE²cn' Niêý "bcÅYž$—ȹÁq¬ÈÞ"&b<¡ŸH'^©[Œ§Æ1ÜóBÚ‰·Áû¾Q*2Ñ(äÔM ¯:‘/I#¯3\m0œ"¼`(»p‚'\åý Ž#6Vœå­ÿ'½ÇG–?¿vi¡ÀÈ­Ó®„JD Š ¡š)(ˆ‰èzê³_\\ƒ-›[«9T•%âßÿÜ s-ݧ£KAŒpÅ+¦Ï=ßðð€×ëïØ(»shMXN±5®xÅ5ï[° #}žeïtKÏŠÿG¡)(bÁî 9áéw¾…/>÷| À`…X"ÿÇÓî ¾˜­£’‘""l»ÂÖ Üyþ€Yßð´%€œ,eZÛ?§_•ïU?Àäƒ÷Hߤ±E ¸–¦à|öfŸô‡uj=ô>ý‡¿uý+€!£žþÑ:í#%bÒOJ·ýùÛU©ÿžö’è:Üñ`iÑçùÇÆ…Ñ/ïx~ àßXÌ6«Çç‹í¯$€Ùfõ~<ôÜúË–…Ÿ-¸}f:¤ñðrãÂØ—w<ÆÌšmVéç¹íåÉÿöÜ;õöüÛÓX¦CKAŠóÊ\sý³îßñ|à€/<ÒïGs²”"i²þ¥øÍÒŸ¥VfHVmÛ†T:ÜÁøƒi囟ßÿô¿–ï¸ àS_p™mV6lC¢šC~]<@F1€]xõÍ¿ÞVøCeRζTѯbŸ¦·0|÷ žo¦ŒžoO|ߘ0 à·–Ì6+yq‘CÈ$Ûì°ÀŸØ ªˆÎÉÖ#!üêNäsXäJÁ5#b„L /@2h±ÄV'ã €eøc„+Á0."’ñ‰ÖÖVéi!dUB²*žV"HK"=-„ô´ð|Su{ccc—\rIZZÚÁƒ÷ïß¿hÑ¢K/½t||o!===ýý÷ßÿë_ÿúï|GzZY•`¬Š—•Æ’HO !=-Dì=ÜÜÛdÜصk4ô)§œròÉ'_~ùå===Lþùç¿ð…/œtÒI]tÑc=&=-„¬JVÅÓJcI¤§…ž"ÆlÛæÈ H0'Ú¿¿Wâèèè;ï¼£BVe VE–Déi!„B!¤§…B!„ÒÓB!„BHO !„B!=-„B!„ô´ ƒËå*...((ÈËË›ÚV®\9µ/âñ»EEEÕÕÕLÙ·oŸîˆ‰Akkk¨Ve ÆÄ׌ ¨ð…ž"ü8pàèÑ£8¨««ƒÇÊÍÍÍÏÏç[mmmøÀ”O~×]wMù»ÃÃÃp~¸¾„²Çµá„ðŽLillìîîÆgxýBëƒvít:¡tC•¶S3&^fÖCfDéi!¦Å¡C‡à9è6jkkáWRSS³³³‘Ž”žžžÁÁÁðþâtôôd9r„.—«´´´È Óá§‘¯††³wŒÂR@Ú¢…NA¼†×˜6#uuuMMM2#BHO ql`êÿq\QQÝœ••åp8¨ž!G‰Sžï15z{{›››ëëëá°Y6›Ín·ÃS2^\óF„ˆ‰9‚šÎpÔŒ Ítvcc#¯<77WfDéi‘øÀ¸ÓpnFuuuJJJ^^^II ªFA:[¹SÑÞÞÞÑÑÁ^\#Dö]wÝUSSàÜPza›BÎÎNt曚šâwNLk?G¬qìp8`I222dF„žñ ¬9b]]]__Õsvvvqq1,»FM‚~ãô(ÌÒÒÒüüüœœœªª*jnôCøÀW«—„˜&0Vv»=!…&̇0˜‘ÆÆFqU!=-D,áð*,rYYÒÜÜìp8*** ö¬¯ž£<ß#\>²¥¥½”òòr>ðíèèÈÊÊB^à)9@•´ãýB»£GÝ$›1ñkF²³³‘ §ÓÉõ‘0#ìÕ !=-D89pàä2Dl.&ÜQ¥8ÈûË™ÐñE$Ö#ÆêÖààvð™ŽsÝäçç·µµQ: Ã#-Õ$t$zþa´Z `L ž»ºº`FØ-‡Å°Ùl)))4øýýýPá02Ó‰ª$„ô´H.öíÛ¡\YYYXXX[[;á^SSSÓÐй–ã £§'rÁDGAÏ'//Y¦kÄMÄýmoo7«B…H`Dz²²PùÃ;[:‰1#PÒ4#ÙÙÙÕ†)++ƒSÒÓ"Ù¡°kœÓŒ¨ç‚‚‚œœ¾ à²}É ªGgggKK a]]Ý]nìv;g’ s…m-!⎞žTcÙ·hš®òô5#}nt/„ô´ˆ›‘NƒƒVv86›---ÍllÛÕÕ¥9p"øºÄçmmm|ˆ‘››‹ÞRà5].W{{»:cš û»1§x817#40#ÅÅŸ#°$캷¶¶ÒŒÀgÉŒéicSÅÇm ???+++;;»¬¬Œ)r$~Iæù᢯¯¯±±±²²²¤¤„®±¢¢‚1^jkkåEÌaœÚ–‡S6&###*ö€éð2#p^………H©««cg^Æ$$FGG?úè#•ƒô´˜x…ÁÁAxˆ¦¦&¦p‘ ç=ËîÊ FgþqfÏž½gÏËô«(£(¢B²*ÂG¦¥¥±–Ò5Fb÷x!¼êad´§1Áÿ§žz*==}ݺužo>|xÑ¢Eo¼ñ†nJH tttÀ’˜mtsssiFÌ2k ùeË–-¿þõ¯ï¹çôFTÒÓ✈ÖÜÜl´²Ýnç΂j'árúÎ;ïS±Dkx¾®®.ꛪª*¸ÆT7ü@}}='ܧv—a‘b°“aâqBc‹ )㥧ÿûß/Y²Dz:\ +ÎÛŠþRaa!§ŸQa3‰ÚI *ÿÇ<22‚’Q…‘žNRõ éìr¹ —Ù#/v1ÝÚÚªò ;žh×®]ûÊ+¯¨Lbj8#Ì Çhî*mmm{{»ÊGºmŒZ}cÒÔÔä©§wìØñÈ#¬Y³Fz::·ža^a:˜BŠ8Öä)‡ßþö·(x´7ªVHO'>½½½èI———P=£˜Xž ¡MöîÝ{ï½÷ª¬Ö½„ÈFs`øó‰ãS› Íã=í^u†1´Ÿžzú£>Z¶lÙáÇ¥§cj\mGG‡™! ‡Ëx#¥¥¥LÃM°Õùÿûßo¸á†”””ýû÷«ĽžF%¶þvÓѤ§§‡; Úl6F€˜†€f”:©çزbÅŠ;wª¬Ü^__ŸYz[TTÄ)•Žâ”YΪT›J6ÐïÊÎÎŽùêO=½qãÆÛo¿•fßn·k}˜¥0½q§Ó™•••šš ©mê\3Tx<ʘÑÑÑ¥K—ŽŒŒ¼ð K–,ÑŽo=½}ûöôôô|ð‘GIÂÞð„{ר’’¨g8{ú~n­(u–‚h!¿/^¬ÒH ¥\.Wiiiaa!|$S ¹áùØGE”@ôpUI Å´ßù‡z×Í<ðòË/ëfÅ0#04#ÃÃÃùùùH©¬¬lkk³øÅ£¾ÝqÇüñÇëÅ·žniiY¼xñºuë~ó›ßlذ!N 7j¢z†—ÍÈÈÈËËc øZ‹ôAÅ4Ñ~. öŠa ¬N'jŸÐfʦ¦&-‚´ iii2&²@*3Âø¶ßx‰ãÆÆÆ$è'=¯½öÚý÷ß?áÓ½ùæ›->c ÊÞê™Á•Pų³³ïºë®¢¢"ªgøWÍÙB:lˆéŠŠ ÎéèèÈÊÊ‚§„ƒD¯›ŸQO;:ôöö–––²´ÇÆÆ¼‚ø¦ahF\.nC{@oÐŒp²(j5ã} ééckKsrrpðñÇ/[¶ÌR׆Þ!÷[â(¼„GäÞÈôˆB$à:c5uwwÛl¶”””ŒŒŒææfZ®£Ðüì°Àø-^3ën¹å–‡~xéÒ¥FCû¦ae8e”¾`Fòóó9ýŒf„+@`ddF’NOƒÇü—¿üeaaáöíÛc;†ZXUUÅG-\¢Ë‡¶Zé/&ôˆVD3% v'//ýö––– ÷pTyy9G§äCí½0Ƃ߇6l¨¯¯œ"c"âtÈkjjŠ‹‹6w¿BõÆK&Np= <åi¨^%n&ÜÏ^N'WhQ‘ð‹–‰è‹Â¦¦¦êêjX'öêà&!²kkk¹×ºV6ûÒ××g³Ùø@Ü—‘‘‘åË—ïÚµ+@ŠŒ‰H¤{WWWcc#Œ†ÙÎ"77:è¦@gkÞH‚èéHéŒþYAAÙ. Ž W«…„\ ˆ#àù:;;[ZZØó¯««ËÉÉw„q£5ës“œ 9ÌhôdÝŒÖÖÖo¼qõêÕ£££“¥È˜ˆd¤§§‡#Ö°'ùùùÜ ’Áð¿­­ v-óHF=m ¨Ëå*..†zÎËËc zcíííŠR'¦ƒÑ +sàÀÚ7xÁ¢¢"øEˆlŽaÃ644ttt$öîªÐèZ31fíÚµ7n œ"c"’šˆ®®®ªª*XH)Ža755•——×××£¡%¹ÈN4=Nï:n9t3<‡QϨêT‰°÷Ó¤aeà!©+++‹‹‹)7ËÊÊ ‘RWW—Ïy‘)(T“»²yóæ5kÖN‘1Âh*ôÉÑ3¯©©áÃ±ŠŠ è.hnØš4Àdx2Çz÷©»»›w ÖŸã.‡ƒŠ¹§§G; ŠÈù¿ë¯¿žƒ|Ç .”ñމ_ÄÊ\ZZ »Êh\Æ´ÆËbx‡`6v>xð`~~þªU«–-[¶gÏ¿)2&B¤×ÀÀ@gg'«1ZVVVvv65&'Ö&R=Ÿ/÷†uÒ £÷ÃÑû¡e7Ï4…ˆEn&Ž?¢5/…HH`i9<×èp88¥’oqvxGOQCà&œNgH‘OFFF†††§È˜1MÌ ‚¦¦¦ÂÂBØ›ÍF]WYYYUUÕÐÐÐÞÞ.=6`©ž©•kjjrss¥Ž k$EÌt˜;w.þÃ"˜c‹HBººº ²á¡b™O sFæŠ&øÅ¬¬¬É‚xȘaMzzzhF] 8ÜÀªTWW9.==)PÆÝÝÝmmm(Gng€^ J°¸¸ØÌÅšp‰aj“ššZWW—.FÆDˆHõÜÓÓÓÞÞÎh?Pع¹¹6›->ô´6yIÕV!|‹™@"c"„ˆ¡L•žNd™3U*7…2./¨Ú"„0”––JO‡LæÌhXºÑÑѱ±1+˜uÏ?äÝë¥Õêt”Û»ï¾ûþûï[3_ÉP…â7ãñ[Ibˆ‰œ %jKÒÖ¶0"ቈžŽþ¸+f˜?¦TfÎäÚ'":„0kÖ,‡Ãa‰a’ÝŽcÛfâï^º·UZQ Åu¹9rdîܹçŸþ¹çž»sçÎúúú;vX*_ÉP…â7㑨$ž•0¶'‰1¾‰tm‰_þ:ìÄW“Q±LD&”õŒ¸g™™™»+Ñ$ýß]É—•Ç œÃó Itáq³~ìåñãmŽÈŠ¡={ö¼õÖ[IUn_ùÊWÌËÔÔÔG}Ô7_S+™ø*Š)çÑ:……¶ã•Ù°T~¯szVÂ(Ÿ$V^0–z:bµ%õôtüµuÌE5KÔúáŒïµžîÿkœÇ›he¥£2óYºÿ9H=íaÖMÞqi=}íµ×Þ}÷ÝIUn¸ò+®¸â„ùšZÉÄWQL9Ö)œ(´¯Ì†¥ò‡¥ã¨ŠúzÁ˜ééHÖ–DÕÓÓô×Ö©¨ñeÕU,q¬§£iàÜŒ*½š(Ì™™ÐæyàkæÒÓÓKJJpÁgžyæ\ðÌ3Ï0}hho!ñ¬³ÎBÚL,ÝRºÐÓ¬›ãV™Z²dÉ9çœóùÏþâ‹/œS$®^½ú7¿ùÍyç÷ƒü€h ?÷¹Ïzê©_ÿúן}öY~lÕªU·Ýv?øàƒÄ+·5kÖœvÚiŸýìg‘åuëÖ1Ë=ö˜W¾|Kfppðúë¯GÊ7¿ùÍ­[·šRõ,®ø*Š ó¸}ûö«®º ‰¨9ï¾û®ß/Æ]ÛA[øñüÅ/~ñÊ+¯d[ ,xòÉ'yüÄO,\¸ÐofYI¼šR€d»3•Ðo»ö½àž$x;05ÆÆÆöïßï›>22Œs‰I|©Õß&0ÙmšBݸÿþûÏ>ûìK.¹d×®]¨~^xá·¾õ­úúú56zzªþú„^Æo'«¨~ï…ß3øÞ È5™)øâÀ÷}2…¼‘ ¾¬Ëd'çw`!áL‘ßxàÒK/•žŽ©žöêïºÿùüfëÜsÏu:¨Ç§Ÿ~:ã˜Î;wΜ9w3{öìùóçóó“¥[Az-‹Á1,­’ùó[hçŸþóÏ?äÈ‘®®®æô_þå_rss_ýu4Èë®»n½ó>ûí·£•Ò âcgœqFQQ9üeâ•ÛáÇ—-[ö£ýYöÊ‹9ö-”vVV¬ÿÚµk/ºè"óyÏ⊯¢2°¡p~ããã»wïf8}ß/Æ]ÛÙ´iÓ«¯¾Š‹OKK»é¦›˜øíoÛx‘G}ô»ßýîdmÄ·)¨!A¶;S ý¶kß |’ìÀÔ¸å–[~øá¥K—UýÔSOÁû²›j…ÑèpÕß&0Ùm µn@i­\¹§ýáÙtóÍ7www£H¿÷½ï¨¨–ŸÚ_ŸÐËøÍãd%é÷^ø=ƒï Š\“ ÕŸð¾O¦p‚72Á—Uàb™ìäH¿âŠ+Ð+†RÿÙÏ~9ª¨ø'îïªþóÕÓ÷ÝwŸéΘ1£µµµ··fÀ ]:¼ìëë›,}ªó€õïÝ/L²Jæÿørá5É)pNþóŸ3ýñÇÿò—¿ì÷A>vë­·s¶8-7`·ÛaÝ<³ì«§½J†¥ý§?ý –qÇŽ't÷Dõ,®x,Š`òø“ŸüdÞ¼y^Ó­5ß#ôŒÊÊʾöµ¯ÐÓ~ÛˆoS PC‚lw¬x~Ûõd<ÙI¦`¦Ì† Ì Ú¾}û¶lÙâWO['¾Çj‹o˜ì6…Z7rrrøa¸³‹/¾˜}òçž{î3ŸùL€ûóñéPýu/3Y'«¨~Í‘ï&»A‘h2SðÅ'¼ï~N¨F&Ȳš8¥ÍïÉ!£q%¸`¦?ýôÓQÓÓ‘ îã{xöwÑüvoóÿwÌÆefúŸöÔs_úÒ—JJJ¶nÝŠ{üöÛo3±¿¿/_|ñÅÉÒ'¬:ø˜Y?nâ'{ ÉLýíoóMúÈŠz:ôŒ»\®Ë.»ìÿ¸ùêW¿ªžömJÁÔ`Úßv=Ù>IHv`j 9/_¾|×®]&¥©©É¯ž¶ÈˆõÔj‹o˜ì6M¹nüêW¿š3gÑ?1ºÊï}íøôüuà~ó8YEõkŽ|Ï0Ù ŠD“™Ž/žì¾P8Á™ Ëê„zÚ÷ä/½ô’g§ß#Pw Óë¿÷Þ{¸µ¸£;wîÄÁ–-[˜þ /à%: “¥OX|pÀU2o¾ù&r.¦gb9 RO‡·Ü< Žf¹MMO³´7oÞ¸__U(È<x‚3Î8ÃýéOŸ}öÙ¨ðU\—³mÛ¶sÎ9çSŸúÞ}ðÁžÐF<›Ò kHíÎo»ö{ÁNª˜2›7o^³fÍôtLâ{L­¶øm~oÓ”ëÆdºÊï}‰žžŽ¿ìeüæq²’ô{/üžÁï c“¹êª«þõ_ÿuš¾8€žö«pB22Á—U€b P¥ÓÓÓ‘¯‚‚‚ŠŠ |Wz:fzzÛ6Gf@÷/Ôcöù<òÈi²t«RÈí}ûöùf*Ôœ¢„§W¹…]OO§Ü¦V2‡zçw¬ 0Ý„Zm,žqÔj^ü‡n˜xôèÑɪz™ ©†8§o»ö{ÁO9‹‡úŸŸ¿jÕªeË–íÙ³‡‰›6mZºt)¬·ïsv+Ä÷˜Nm™¬ ø5¿a©'¼ïÑdšþ:˜Š|ýÞ‹ÉÎà÷E¨É„Å£p‚¯H!•Õ”íùÍ7ß÷¹Ï™ôx$îã{L“õë×›`æBz:‘8|øð¢E‹ÞxãË×dÛˆä$ކo„Âñ¢¹¹ù7¿ùÍf+((ð£9ßCˆ@Ï‚…'¿ÿýï—,Y’zÚ«cà»ý‡H,ßC¡~x4ôt4ã{!|Ù±cÇ#<²fÍšÐÓ~;žÛˆdö‚ÒÓBˆ„ÕÓ2pBÄ>úhÙ²e‡N=í·cà»ý‡HZ/GÓ …ÒÓñ§§W®\‰s"k‡ÃÌ4èìì0d¬L$ $yyyEEEfµP$¦+YÜÜ\d¶´´´¹¹Ù"—´qãÆÛo¿½¸¸Øf³Ùív³£U„ÈÏÏw:---GމBÇÀïö L”[®•©¯¯OKK3/a{a _è¸\.xXÝåÉ0æeãÿïÅ•M;~³ ø±¿Hgñîîn¾¬¬¬„d„ž€ja JJJÞÔÔÄ”ÁÁÁDíSVÆáÁü¥¤¤¤¦¦¢Ä˜ÒÞÞ~àÀ0ô‡êêêâ–­GE}@¨««‹•³Çõ¼ëæxùå—}Ã$…ŽŽÔyäÚËóE®càµý‡ÆQ4.š\ØV-˜ŽÂÂB” ]<ÒÛÛ[[[Ëì íÔÔÔ aï‘Æ/ûöíƒ-eá@7sØ‚oµµµÁ´&€ïH€¦-ëq=m…p±ºÍ°øÐÓ­­­¦—•••m47 DCCŒB4 Ê:õÞ T£P&¸0&*Q¤ÀA¢-Ò ™ò8 îlcc#'ø¢_…¬áŽG9_¿ûÝï¢?ß~½&Tòiú¼¯í?¤§4"¨(Hg¨O6%£±Ì F¼€‹§\®®®f›€6ã¼³UUU¹nÒ)'`6ù®š¶²vbu=m¬üº RVÕè­ŒŒ XXX3;¦²²¯¯/\½pë?—ÅD'¤¦¦¦¢¢ÿ---¥ßÚˆûØÜÜŒ|ÕÖÖ²Óåt:ëêêp‹é3xAÜD>¥éïñ2¿Û$6I8߃µMö…4(-I¾Œ¯†€\ä¹áÅ'³††2†%‡eà-.++ƒt.((À-aRŽæ{$XO@ñ=,|­ l ÄVIIIaa!D•%nQQQyy9wòÄgº»»ãbêöô•(:Tfx ŸÊYìf~EÜ=øÃ5ÃËB[ãþâFÓéâeô°£º p™¸kèMÿf…´ý‡ˆ¯v5úKhžéhé£p+q1H ÑŒKE8+L%¼¡öú¸³³ÓårÁ‘±# »Í¡„Ęé'â­GLjÌtdεâúÈŒŒ jnH1N݆úìêê¢JÈÇd°ÅðRÐÖ̵Ýnç#BjSôIà€ñn­€ÄÍE·¡ªª þ†=d®·;alGÜ (Œþþ~5jáÙM‚í*--EËÛ½{wyyy¼ì}ËÌúŒ®#Ì 2Ät¢>zò ì0ÁÁ‚qÝ:eee¸ƒHOª¢ÒÓ‰¦§“ð!)¤soo/ŒtÇnaâ¡2ïrsË-·P‰ÖÔÔ@Í$Æz/(=‘kØñüüüììl*l.ý‡C7#^,;ryjœ““ÓÞÞ>q| +îžwûõ³  7šI–=™MYOOÏ­·Þš’’â¹ãé‚ .\xóÍ7[¼¶Ã„B>¢…šÇeI,*ü—„R=Ã:ÁØ666jUeR5mÅ÷H =­1r/î¸ã:(KµââbNË?³Ùl| Ç5”PœH„'K˜±mäÝŒêêjèlæÚÚn·CÌÁ+pœÛúÀQUUU¡bC|ðùCŸ›ø½M¸r®*Ã*dr>OZS†#•è_þò—-[¶¬Y³ÆårQŠQF[pËôla1ÐW7!SÉNzÆÈ1¨gv죂âÞñS¢æ]M[BË*z:™ã{Äc½‡€æL>²„DC× >Ö“ã»Po\÷Æ› ·ïðà*:::AjÓÆÆFèT”RII ƒ à—wðîEEE¹¹¹¸SæÞÅé lktoRSS5bئ „=yH1ÖUü¿ÿþûo¸á4F3´i‘-{p‘°4ƒ€q0ã¥j÷†6-Ñf³eeeÁpЦ^£ÎjÚ –Å÷m‚ÆáÚG¨78BªOÚÜìì쌌 ŽXpE>€Åï¢:\92ÂQ™¶¶6xØ V(oæ‰ð:VëK˜‰ò.—‹òÚD›2a\ãËÌ¡‚Ùívôß´n)aL—š Ñf%1ÚT¹óÉØnÙc¢³¡³Ê¶u¶jš>=•¦%‡5C'–™å}I€±5me!&=Å÷a“AfN¶Ã:£ÊƒÂRsŽyJw"‰c3ð@\2ˆ¾ǨšššqRÛRã7FTTTd¹1ÛèÄË8J¸²²UˆjFÃcñÛG¥>3‹Pa+jjj áŒ§@;òœ?M¢¼el” ß–0±ÛPànø’Ya8F Dr¢õˆ"þ€ª êîîf@ÔjnH%÷ââb(§x™eá¥ਸ5 '}Â%#ƒH©««³NFPªŽšpoÏÝ…ä;^@W ZÇD®Ö-šC¼ž$` X½Z‡_=é-{Ð`ëëëW®\iBsÀ(ů†f´AtQÐçgœ{”0ÊÒÙårѺ !¤§CFó=â¥@ :;;[ZZ8K„³,–„q-ðVyy9ƒ–Ä…–â™ÐÙT ðgÌzLÁb.µQ’f- ®[*Xü¹6ze@¨= «;aLgìðÁj;4Z_µºiÓ¦¥K—fffr‘_D·ì¬¤ =A{„ôD?3N54ÚJ -™8¾¿,¡ª§`'GFFN˜""×´ã´´ß#)ô´ÆÈ¦@รdmm-ºª««SSS322)Ž»pf3\#¤ª5½£çžºÈ÷7Ö²P1¼xn¾Àà'¸$HŸ¢¢"h+ïê\\\œ ³˜ØO®QIFGGçgöìÙ–Ý·£¤¤ÄKö¡©Bêßÿ û–=°hq999fîYY? 9Ó ¦ ÇÞÞÞŽ¬MsÄSO=•žžîù|À7å¶Ûn»ÉÍÓO?-g^§ì[ÚÒqŠâ{HOÇ+žF€rf3œ%¼&ŸÞÖÔÔ ëìt:#·rt9èé²²2\¿q–¸läˆë;crI(+Ïm)# ×c©}Xp÷!¦U ǸÚÄ‹¸çÙrÑí¹óÎ;ÇÆÆ,xP{yyy¨É\‹{Aå Eå^"g>p‚ËÍúk6¸M+** þSRRŒA`ü¥HToÜ -[¶xê9߆[‘hÚ¾¥-]ÍžªÕõ´Ð|dtoo/ôgo766rê0 (¬««cjÈDº|ëŒm£SŠËãÌl¦ «Àý/©q£ ʰ¥¥nž ›àÝKKK¹ƒ£E$,.…ƒ›[XX_cÁ·Üµk×¾òÊ+–òI¨lMl;¸ °6› ]ÙhÎÙÅ³i áã×Ñ˲윌#ľDŽ;×Aš 'QËã;Ý+—“X+Iâ”ý®®ˆ»ž€â{ˆä…!¨Q]!©©¹! ÿÙ…ÏÃð±é?W&Ð+ðÁ¸³›™hnv—èêꊎºåV,ÐÖf‹œööv(l+ÌqïvÃÒÀ½K˜ë½{÷Þ{ï½¹HUôîPý ¨¤©žQ1PæÑ©üüb®ˆQ NO‚aAÉ´µµUWW³ XnPüÖY²|B= ù«_ýê·¿ý­TutÊ_HOGðB…ˆ&F:wvvVUUA)ÑùᘠøŠ‹‹©Â¡Ûb”šZà­NÁf³1:ÅMtv»Dç^»ÝÎ9*(:—Ë…@¬µãw¡òÜXaÚ4Y±bÅÎ;c{ h\ÀÅ"E½BŸ%l:u‘ý7HÒœœ36fÇJh‰hÊ&àZ®ÿqÙ–]øxB=Mp‹7oÞ,ï =-=\zZó=T ‘ƒS·ÍúBhVhkèÈÜÜ\~ ØMee%%SöíÛý±(\']{aa!å$¦Ó鬭­mllŒô6oÐ(ütFF£õAa·µµE?.ǰö…pSâk;¶\ˆ×Å‹Çð2PhŒeîõø=T§ˆv™z{{QѾ¨G!ß»»»­°7…÷Ñ»6éñ ×GaC‚ÔÓ¸×ÿùŸÿ)ûv§¬ùÑGñ=âì¾7&&ò‚Aø(//·Ùl)))P$LD¨¯¯Çg¢ž*žŠÄ©íïïÇ…q‹N;6»-FBpC3…½ÓMÔ´¤<4A~~>P|µÜõë×?þøãÑÿuS¸M Qcóòò8Ï'Bý@(fvÐpPaPWc8኿ËðùfÃT†ÄA_1®wñôŠWè7å‘GYµjÕ}÷ÝwðàA™÷ð6mßÒ–®ˆSßCzZĸa®84eøiH[Ü©ÂÂB¦@mËGz¶cùµµµqú)”.'¤B3±?€DhHH4d–?g&ÏDa›yA©æääpGOËŽ&ƪår¶ ºœ·@öíÛ—‘‘Q\\¡1~Tx¶ü„çïF³·iá£ÓÅšÉ~&®‡ïZ3FPDŒþàƒd´å”& ŠïšÞ ‰S cL\‚êêj4·Ïn·#Zœ)‘“˜4:O%%%0)))TظÂÚÚÚ0NÞ0ã ÈW~~>~jžoá·"§`pfä剎ÍD$Çæã«åBײ7ÅÒ@UTTxvEÂÂðð0:TÜðˆ¦¢òG­cƒª‹eǸtkÎþ¯Z…œ²²óž€â{O˜(Ôî`[ÜÆŒj3`äÂÆAgã'ðC‡ƒ»*¶¶¶B•Ö××ãeXºþF©;Î7æyhäÂGôööfeeá‘‹d“S¨Z.— ]¸ õ¸HA j…ë©#/²ö✥¥¥áª0´»»•“¿ ÅŒê„&ƒ Ì™ñ»Í¸"‘õ´¦Cˆ«!¡ Ñ$¡ŠŒ$eÜ|¬¯¯/\R¿ÉÒÔÔT[[Ëy#ÐI¹¹¹+W®,))a05ÈšéˆT£° 222 åÍ }xA?¤²²’ã”a,"Ë‚ú€Š"­¨¨0›1×(ŠéOæ8Èn·£l#šyahgä…á¨ñÝNü.×Å !¤§¥§ƒEÓT b2eø BB5l³Ù8™„Ï—ð™°ìßÕÒÒB•}Ñ–––†¢æžÎ¦•8'O Ò@-ìÇ ª9ü_UU“QÌȵ\dÇ,1„nÆKÎ~áN‡Ó”¼8ê.÷…›"%ìˆÖ××£S.³V ÿ†ŸFF¾#$䔕…©¡øqv ߉T)Ô3t•Kf 0HUîÑuÂýÛ¡`L$© ^šjˆÎWÁ¯ðw¡_].'¶†¤³qB|—ïñ]È8- Ë$J¦¦¦ÆÄk‹fÈ¿H´\\?4nVVÊÇt±&ŽOÀ˜Ú®(Üâ‡3þ™‚¾M¸Æ¡Y[p‘¸`œ???ŸOZP‘ð‹¸#Sî• !§,]a]=­øª÷"ñ`ôîêLÙÚßßÏýÛ3228ï–A!Z[[§t!<‡‡=SpfnþÊ)È]0[âTÜ7Ûô4ÚÚÚ‚)‡‰ã3m¸×=/†áèº0æŒBHOLJžÖôˆˆ2###ž/>Æ%bЦÍÍÍ æÀ y)))999ˆŒ+ ÑÉ©Û~Ã’ QMœN'S . b²@ÝPÞŒ¼f&sã%T¦×$ß ÿýßÿµq*ÊJÙD §ÆõJñ¤Èi¹æ¥'È8 Ä7ddd kìx¼ð ×^{-~e蹸ÅK›þ77ád˜`&ÁCss˜¿Î¢@ÞËËËkjj¬¼ñ¤rÊI›Å÷ˆ³kHøÞ˜ä©§žJOO_·nIH…šÌÌÌ|óÍ7#úÓPPfüÕì2C í‹c†¤”„Dîëë£ÈÃ[ZZŒ*ÍËËcÐ@3-ÁKPByC^ã3ÈYÛ—ššúÌ3ÏxÊkÈYÏio\^ {Í5×xŽ ã",Xàw´ò}îܹø–kŽ=?€¬áœž=äñöÛoG ä>3ØÞÞŽÍ™3Çl…ãùõ´´4dFfQJæQ@`PUUUð£6›s?pªêêj”$Ê_A6„H§,]q=­øª÷"©€&Û²e‹ÑÓãããK—.}ë­·|ðÁ˜_d_GGõ($,d(7\ä°4„ ä&4"cS@b¾ñÆœQ U ᘛ››m6Üæ¤3슯?ôÐC?ýéOçÏŸÏ™$8í®]» ðCfn t9×ðQ@›tHÞÉ$5ǤñßÁiÎëàI a¡hï¸ãŽ«¯¾zÇŽîg3­Wõ—¿üÅó»{÷î…솘¦ÈÆ©q/±nvÛFq9NÆ3ág;\m¨SÌ…ÒÓ–òYñ¡§­€¦7¨@D4Ê4z2zÅŠ<^²d‰Å¯곫« ’´¶¶–®Ð—ð6› ÿ9:ðꫯ¢Ã€ýóŸÿ4a¹ËËËi—«««!1!¸o¸áÆ!á6¾ž’’‚¨s3¹‚ïò xk2IÍaé;ï¼Ówpšó:LèèÊÊJüRp1¥¥¥89:ž§å„æ ÷Üyóæáœ[·n¥GÁ×{{{y*ÜD䜟= œG£ÎBÈ)'XßCzzóæÍøÃxœ™™ùá‡Æi¦ ‚9 % • ù[TTÄ%zx ÙZXX¸jÕ*X¼šššGyZöž{î¹ãŽ;H2÷å—_†6]´hÑ/~ñ hrCÚ^sÍ5---»Ü{Û¶mW_}õöíÛ½.?7kÖ,¯Áihâ[o½uùò寙qîÇ‹/¾ˆßÅiqÍf&III ;ëׯÿå/‰kc~‹QL¸in/„ÒÓV¿P!D¼èé×_ÝHÀôôôDÍòàà 7¸1ñ4~ýë_§¥¥ÍrÃuÏ=÷\mm-S _Ÿ}öYHj|Œ)Ínrï½÷2Åk²\?=§÷íÛ7+höûü#ä>Sþíßþ +LÉBéé8ÐÓšÞ ±ÒÓ£££wÜqÇøøø»ï¾»|ùòÄÎ8Ätkk«ÓéLqÃ=ÿüç?{¦lÞ¼ùšk®Ô.(((++ƒ°~íµ×¼R&Ûöo²Ø#a¼g\Ô<®$??ÿ¦›nš;wîC=d® R>ÈøwB9åDÊ‚â{ÄÙ5$|oL²iÓ¦¥K—fffš86l¸ûá˜À?räÈÂ… srrªªªzzz b}SÌ'}¿}éÏBÉËË›?¾&x!§,]aQ=­øª÷B|ðÁüqÂgsšB9sæÌ^¼Ä´rÊI˜Å÷MoPaV¬˜aþ˜R™9“ÐÓöw%_B@OìvLlsËhs „Bz:¢*„qDZi#¦KêÊJÇ1=½mæ¶J·Œ6B!¤§-¥§5½A"„%ô´§˜vÿÏœylš‡Ã=ÇÃóÀw.õÐÐÐ’%KÎ9çœÏþó_|±ILOO?óÌ3Ï:ë¬ÌÌÌ÷ߟéH\µjÕm·Ývê©§~ðÁƒƒƒ×_=Ž¿ùÍonݺU÷B9ee(¾Gœ]CÂ÷Æ„'ÖÓ^ãÓîÿAÎ÷¸òÊ+Ï?ÿüçŸþÈ‘#]]]Lœ;wîœ9sþîföìÙóçÏgú¬Y³Î8㌢¢¢]»vá»YYYÖk×®½è¢‹t/„SV"‡â{¨é !"©§=G¦3gþóüî?þñ3f<ú裞‰½½½H|öÙgùò™gžÁKn“=}ë­·z~÷Oú4÷Ž;N:é¤Ý!䔕… Å÷ MoPa =í!¦woóÿ·­ræ±uŠÿ›­[·BÿíoóM|ûí·ù²¿¿/_|ñEêi‡Ãáù±ïÿû?|X›O“ÁÁÁÆÆÆÊÊÊ’’’ºO‡Ãát:‘H… 9®rrÊÒ–ÖÓŠï¡z/„8a{|ê©§ÒÓÓ×­[gÒëêêrrr233ß|óM¼œÙ³gïÙ³GE7e  ;;;›››©§«ªªRSSm6t6Sººº(¾…SNì,(¾Ghzƒ D‹û!Øô-[¶==>>¾téRhè·ÞzëÁôüü¡C‡î¼óα±1]$<+ª›šš ¹$6w¨éèèà4!ä”# Šï!„ åJ¡áŒž†Œ^±b—,Yâùùµk×¾òÊ+*·(ÓÕÕIÍy#Là...FŠËåbŠ‚!==¡øBC<õôæÍ›ÿð‡?ð833óÃ?äñÞ½{ï½÷^••8zôhoooGG·YYY¹¹¹Fswvv*x¶ÒÓ ¢§5½A"D|éé×_½¨¨ˆÇéééæ3+V¬Ø¹s§ÊÊÊ9r„áü@ee¥Ýn‡,..fJuuuss3T¸æg‹DrÊŠï‘zZcä*!¬ï‡<õôèèèwÜ1>>þî»ï._¾œ‰===‹/V‰Å5íííµµµ•n&Ü;D ããekk«Qä*(9ee!~Q|5]!DlÚã¦M›–.]š™™YVVÆô 6Ü}÷ÝHyíµ×˜²~ýúÇ\%–`@RwwwCg·µµñe®TŒêêj¦ttth‡9ee!(¾Ghzƒ DˆxôC|ðÁǬ"JNŽ=Êy#PÒèe ª°»©ÝÚÚªùÙrÊÊ‚{Šï!„òCÂê ·´´@R———ÓÉö÷÷CpCmWUUAd«ˆ„H4=­©B!D¤9tèPWWW[[õ4þ3~v~~>#à===šœ-„ôôÑð D!’“ááaÎíëë+))ÉËËËÍÍmllœp/pª­­…ïîîÖül9åäÌ‚â{ÄÙ5$|oL¡þ­ˆ/ ³›››«««ËÊÊ]/Q!ËËË].W¿ŠHNYºÂ*zZñ=Tï…j"^hkkkhh ž†Âf°‘‚‚‚îîn~ ··—³ xÏ‚â{„€†T BÈ 1¹ÁAGG‡Óé„ÈNMM¥Ânoow¹\øßÓÓ#œNYñ="®§ßC!Ô¿ dtUUUQQQAAGµëêêP±+**jkkÑOHO[ôB…B>øàƒ°Ÿ“{Ð444ÔÔÔðyzIIIZZ$t6ǹûúú’|ÓußX+о"=mi=­áˆB/<˜••UXXxë­·îݻפ>|xÑ¢Eo¼ñFxîèÑ£Ð]]]T.—‹“FRRR ¿'Ü´„xÂÏA!\ýõΧSÆñÂ… ãTR+¾GRèi‘«@„ÂWàR½mÚ´éÉ'Ÿ4é¿ÿýï—,Yv=}B ¤+**ŠŠŠòóó©°‹ÝTVVÖ××GèGùC1¡ÈqÊæ¥tE¼£øÒÓBµG‘t<÷ÜsëÖ­ãñŽ;yä‘5kÖD_Oû²oß¾ÖÖÖ†††ÚÚZ¦pÞt6Sº»»¹1ûÔÄtFFcFŸþþþ¹sçâ?²cŽeÇ¢_ÇâCO[ÿŒíß¿_vsBãaBÈ qœ¡¡¡ÜÜ\üÇñG}´lٲÇ[DOÐ@ -2áž™•••——Çˆïæææ ƒú Øl¶ªªª˜d„cÒpÊq=8=¡øQÐÓÖ‰ïqË-·<üðÃK—.•ªBÈ >üðÃ{î¹çí·ßæË7Þ~ûíÅÅŘv»ò:3ÕØØXZZ yêt:™‚ÕÔÔ@p3v/†‡‡òý¹–nkk‹ëÁihDCO[mèeÆ ‘›†%„BÄË—/ß½{·yyèСwÝ<ðÀ/¿üòøøxbds`` ¥¥zšº9''šÛH‚òòrô"úúú¢|m¸†Y³fÅõà´ôt²èi3ü322Û±k×®$¯=Á‡ŽŽÎ?ÎìÙ³÷ìÙ£¶'„‰Ák¯½6oÞ¼¥n6nÜèùÖï~÷;+Ï÷ è<ô÷÷s•×{ï½wÛm·ÁÍAÚFyœ?ý¡®°Šïò5´¶¶Þxã«W¯†FTol vçÎ;ï“B~Hˆ„‘Ôv»}þüùùùùõõõ1Ù}Æï,”„× LRÄ÷X»v­W/\z:Pn¯¼òЉòCB$GŽY¸páõógÅJFËŽYÅ÷ÏáŸÍ›7¯Y³&Éë}¨ãa{÷î½÷Þ{e/„"ÞqdÎ4¿Î˜™9s¦g ^ªˆ¢ +Û'r|ƒæçç¯ZµjÙ²eš*+V¬Ø¹s§ÊAù!!@OOìvûÛ6ÿóÒ}¼­Rz:éÐzÄa|M===‹/V9!„H=}\@{yüx›ÃÒzzÏž=o½õ–î ôtÌÐðÏt dýúõ?þ¸ M!D‚èiÍ—<¶¸ž¾öÚkï¾ûîЖBñ=âì¾7&„P‡_ˆxÑÓžÚÐÓÛ·o¿êª«N=õÔóÎ;ïÝwßeâ‚ ž|òI?ñÄ .äqzzzII \í™gžyÁ<óÌ3Ó‡††ðÏ:ë¬ÌÌÌ÷ßß|~ÕªU·Ýv~wùòåŸûÜçpðõ¯ýÙgŸ•®°2IßC¨@„P{"iÅ´çDÏœ™‰ÿžÇ·?øÁ mÇÇÇwïÞ}äÈ&~ûÛß~ì±Çxüè£~÷»ßåñ¬Y³Î=÷\§ÓÙÙÙ¹dÉ’ÓO?;ŸO–>wîÜ9sæüÝÍìÙ³çÏŸoÎsÆgíÚµëƒ>ÀÇn¿ýöÁÁÁ‘‘Ù±p¡ø! áˆÒÓBˆ ŸùÓǤÝ/RO¾ñ'?ùɼyó¼¦/ÐÓ÷Ýw‡††f̘ÑÚÚ:Yzoo/Ìó3Ï<ƒ—ܦŸ¿õÖ[ÍÏi¾G¼Xàˆè麺:\kaaaiiéÀÀÀ„{ÛOTöÉ¢ z„555 8=,àŽ @Иy_„òCB$…žöZ€x\L˜ï%}ÕUW}ò“ŸÌÏÏÿè£N¨§‡ùî—¾ô¥’’’ÉÒ·nÝ ýöÛo3±¿¿/_|ñEßÏ[YOkD#âzš vww:tÇÍÍÍyyyÙÙÙYYYè–1¥¼¼¼¾¾¾¥¥…Ÿ‰PÐŽÐÓøLÁØl6eYYS µ“'¨;2[[[[YYYQQÁ»Ý޶òÁÍRB‘¨zÚ{þtpë!sÏ8ã ³‚ zzÕªU<¾ÿþûýêé÷Þ{úøé§Ÿž,}çÎ8زe Ó_xá¼ä\YéiééÐ@o¬©© 2ÚÊ)8@ ŠŠŠ¨°Q·ð±°‹]œ:ÛLò†¬‡¦ä€:^=zW•ßÑÑÁ KlPȬér £(`8PmmmjuB!â߈Á¬G|饗FGGÇÇÇ/»ì²Õ«W3ñ†nøùÏ>22òÄOœrÊ)žzúÊ+¯Ü¿?TÄC=túé§uÝu×=øàƒžzúšk®ùÆ7¾qî¹çžqÆfìy²ô]»vACC‘Ÿ|òÉ—_~¹ãóÒÓ¯½ö.ã¼ó΃S¶Z©jˆuõô 9pà@{{;g,POC㢇‡› ÿÄê5ÜÙÙ ]FÁM‰‰Ÿîèèàe ºçææâwËËË™­‰wûûû#7}%æ%Ïì#¹nÐÛáz uòÌ™B~HˆÛ¿¿u®Ço4¿tã•xôèQßìPïÝ»—#ÍÓÉÐÐP0%ƒï¢ eÇÂ…â{Ò»f]CCCqq±ÝnÏÉÉa $/GµÍFèa”Ú<Ôd]]]II d=Gµ!: ÊÊʪªªºººÒD"\ŒÎFVVVJJJ^^ö!7ò"BHO‹¤btttþqfÏž½gÏ$ÞrË-?üðÒ¥K-¥ªÃ‹×¸ò ÓÅ÷H@=˜ÁÁÁŽŽŽææf£§‹ŠŠ²Ü@ò2…¦{{{ÃØkéééijjr¹\œˆŒ—ÖÍÏÏç•à·ˆž@ô#ŸD®cÃj”$Ê–ùEÉO¸'j#1ar*Drú!!‚äСCwÞy§ç¨ê† êëë5¿ëׯߺukðéBz:Ѥ6 |ËÊÊ ³ív;Sø¢²²ÒL—Ô>räOÕ××WZZ yÍå€×¸ ·¶¶&ÌjHáwuu9NÈë”””öövfV‘û„"!Y»ví+¯¼b^ŽŒŒ,_¾|×®]*!=\=z´···£££¥¥…)6›-##ƒ‘@@UUUss3>.Q8<< ù^]] ÏÉÊmmmР+W®„¸g혅q Š9Ea"ƒÌt¶Ë屿Š!Dü²wïÞ{ï½×¼lmm½ñÆW¯^=::ªÂIßCzzº˜é× ¾N§“«Ùé)**ÂK³7,R{ppê“§‚ÂÎÏχ¬ÏÊÊ¢Öïî«ƒÅA\Kíþþ~”[YYº.ŒSŽÞàe„"º!?$DxY±bÅÎ;½×®]»qãFN u ÒÓ‘•Ú===œÒuëp8l6[vv6d÷„{Ø»ºº:¼ñ­!CqNˆxHy®}„ÐÇï"¥¶¶ïN„u f4AAa#w%%%ÌŽ+**ÁÖÖVÍÆòCBX 8ÁÅ‹û¦oÞ¼yÍš5ñ›¯˜Ïà†àdÑóòò’ážB±pŸŠªª*3(mcå›ÍÐÙÙÙÜÜÌqFÈ!\3î.;ÏÀ¥§£ $ „`MM CŽL¸§eçææ2À3Gµ¡}§?ҌӢ&A¸S†¢äääddd ýsè&¯­­-îüáj3ýQYYYaaaeee}}}bÌ„ÒÓBÄ/ëׯüñÇÍ˃æçç¯ZµjÙ²e ÷aqºººà‹á¦Í>ÊEEEh³pÓæY4|4¼gÂ̽äNÒÔ$jÄ„O` ã»\.†ðŠ-Ð÷¼f³9 d´2n×§áö!Zx‹Ÿéëëƒ(ŠÜ]“ž¶V_ŠJµ½(ndƒ<á¦å®àhä Q7âX5T)j{Øü]èQnj_"E‡žCuuµ‰JŽvUZZŠÆ¯ª%,ˆæ{ˆ¤bdddhhÈ:×— AÌ'œUUU¶„|ä»pµð&p… °I0äu¤‰¬QÌ2Ä­Iq:žÆcÆð6®â„ý*cÜ Üš´´´ÔÔTêÜ/­ aƒ{ÛGÖÒÓñj wGËgïµ*''‡ÙpT›ÒÓé{¡Fò™Ž©Çè{mß‹ˆ܂Ǭ%…í@k´ÛíÈš±2ªWB‘ÀôööÂ?ÖÖÖ–””Ð3â ;;;??ߤôôôÄéFl¸fjåææfJIHOö น;£•CŒ¾DSzšQ<5'àªÌ“sn‡ÿLá¢)(f¸oÞ+heééć]OÖBÈ\!1Ñ÷8F‹ :eŒf€ïvuu±=àlìÚÖõ7â¸+×xnúcf¿¡ Ð;‡a5Oô¹O!âxŽ4S;Â=ñ¡?ÄGL ¦«ªªøÐ5îá‚™;^9üxyyyqq1:t¾ðïÈ,² /Æ”è÷ PÎ&$.‡üpUEÆqª¨î¦ÞÞÞ ééD†ó°Ñ!¯}ÿ!"srrÐ ù$‹3%Pû§¼a8Ú š;Á4jhÞ‡/ÍÂ…(÷†C‚«BQVèÖó¡’™!‡âRä> 4ßCˆ€«¢/+))áØGEEGš¡&iÆûÜLٗŤ'`´2²­\PP`{iåHOÿõõŒpî,LŽ+S+sL /ïrSFõŒkC"3>œœÁ¸¤§“´O{dš(Ì-ç ÏmÒÑ6¦«!ùÚ:##Ãf³™eXÍÍÍø€÷†ÄõМ!׌܇î5ÌÜ„{„—­]ÅôÑzD!ü 8:&8#Ø^Èå””.ïPƒ˜†î4Ôâ˜Iðt¸rà2=´´´ÜÜ\‡ÃAÁŠÏÀóF-â-‹šž®«««²²>În·s#—˯—““ƒ[ÀˆaÔÓÔÊZô/=-‚…3ÑrÐ~Øï„ˆDËgl¶7èl4~ âL›ù°ï†”ÐÜhÕ°;F…[Ð>2®Ê3jRSS£]…ô´Á‹9øˆ6¸vâØÌi¦-…Ô³àh‹¢ßL®¯¯¯ªª2WÀ ÁpmLáÀm[[[¤wQàH0\Ǩ•qm¸®¼BÉsP‰œƒÁXùÖ&ÒÓ"zF„}SnmèÙ£õxm,Npæ ÎóÄ”¬¬,i›­Œ ò-edQTØ0O\é …˜N2õãÅdh¾‡H` †a 9ư   '''55•Û2p²ÆÆF‹I M.g¤2Æes7 å Á\ÿC­læWqŸƒP(j/­ŒÁ¥Mq1FzZˆÿgC9ǃf&&##MÝs-‚Ëå u~*x ½NÓÌ-ßqØ2Óõ·ˆÂnnnFg£¬¬Œã°€°nÈ8.RAE„ L=̯§¹ƒú„ÍÏËËs:4ûPr¡>ÆŒ fE­Lyj&›Ç°ø@Ô´2~‹³Ã9¿ÂhåÜÜ\\˜IA9×ÔÔxl\¾ž"ÌÀ ÐòÂ.p Ö iÎô  ÇÿF, R=7ÇÁwm6›ÝnÇOÐ 1>I s àÂgdœk@aÄ®Ê[ [aM¸+¬þscˆ<3æã87¨=ë,Ý6C¹\j?áÊ1cä4ÂH(//‡û ƒ»â§Ì¥pçüÊtüçæž‘¸¨•á9†YÐNéi!B€ÏÔ`nhŽëëëò/++‹Zo!ÿñ±`:â´D°Y¦ñÊ m°“žcè5îòHsÏœ………H‘ÂN4ßCX XBɅé0P\0çt:ŠáÛb;ê9EØkÚ,<µ2Þ2Z™7t áRÌ8‡g¡ÁCQ›Anèà¸.=³¾_#ÊÒÓBÄ€ÞÞ^¯x|ÅyyyìЛ€üÁB{NzæðÌÌ1£šp!&&—£Ìqúêêê””îòh"ú©2$ Z(¢,—a!9×nÂýÐn·£æääÐâ]3ÒÛ.=~6ŸFWËåtõTùžS„95Â|>,f–SqZn;‚âOãçÐÁ°Ùl(4î#ˆB3ZÙ"…ô´![=ŽRІÂp—™ììlŽÀÌ1ä_ÆÂps:õ4^æºÉÏÏ7ÛOòéaÔœ Gbº»»™#d‡Ãp-ìEhæœô´žVqÂýü{Ü–——Söq3]Øââb.\ƒÝˆÕµþþ~jeÜR+s(×wDœËé U§¿ƒç®p„ÇŒÈaÖ‘#Ö~„ âñ‹¸*\•ž éi‘¼˜mfÍæ,Ü®…Óµ™9~­¤Ìp> û k ÉNë–í'CJÚ³€^œ¥§§¯Gó=Ä”-ç³±çë„>?ƒNÐÖq>‡¢,a—hN)F=gàj9Þ«¥¦çäòôǨ•9BŒ  L/,,¤Vfw‚£Ú4Ý(CpÊŸ´²žb*pK*×ÕÕ9ØYXy¦pÊןðTžÛOÒ·Á=ÀpóY$Sø,2Ò£ÈÆ%0GVg |ª¥– !‚±-üîzUU•Óé,++£DÓæžyŒ§Áý§¢ðœÊLÆ5˜IÃ\•ȉÔ¬žƒ»¸B¼5ÁÊt°Æ4§¸£^pX'ç#»ââb³CÚz|'¤§…ˆ0ßð°ËŒ¸Ì@"3¢&>@lØq3ÿ–þ/---%%ÅÄ^eì¼¾¾¾(,߯o±Ï`& kÚåQ+ˆfvïÍœ4Ø âQ+£ýr7:è ÜÆ%àEîïïç%edd@ÙO¸ƒ9iªš+§ll{zzÚÝð§M„8.Gù¬\¹’ëd8ÈM­Ì§p2_BzZˆ¸Äø38˜xŽ1%//j>†£5×2b+÷žåzJ^n…Ãy#¡n…ðL¥¥¥øun¢Î1|Š}F Í÷HÌ4e³‹ž™of·Û9ÒÌÕ‰¯ˆÀ™;;;©•9¶ÍÁ]N«®®f µòtØ™qfÌ¿e³Ù˜}¤ÀÁÁlòb&Ü3ô$MHO ‘¼0äÄ4C& /ŧ´ðdð+ö©2[áPÑÂᥥ¥¥¦¦ææærMOOO[[Û g{OÙùAÊ»1®Ž‹ý @„­GL0Ñ õI#Àô¹½+˜‚ÖÄ^k„ÖZxM`+æp/­.’²ž«ý`—‚ï·›Oâ»^Ùšq¦‹n¢)›‰s¸Êäá~¸¢Ä—VBzZ‘€’…iáò9û:›CÔ&N6„‹iƱWÌ,<{>ÚnooIܘF*lœ‘Lp=Œ˜HšCz:@‹kÐgc ÕŒó‘ jC ‘™‹ÊÃýüÌúœœœììls  n¡}MTf_P½N‚JΘ˜Ýœ:‚3­ÌŒìs£mG„žB$;PÏ===1:P PØ •…ÿeee"ÐâF蘡åòòr>7a­ñõ)„µÆ‡M¬@>ʇ²áªÊél9[’s¾£Ä@›Bt² æ°ïd¦q¤ÙoL/ð3}‚²Õ ã„^2×år™‹ã]~_G]â\3Íš[gÖjÔ7Ô@ nêi¤Oa \!=-„Þ0ÄcÖRéBšPˆ@Iydv¢á#{4R]A÷xƒX &ød4ÄMiii~~>EdN ]5ý¸%bú¢™Z·ž1×!O9­z÷-3s#@ÕBM Væ-† 6Ó'(sq¯Ò¾ ^¡n ªð’ÐýãNIÙÙÙÝîz Rš˜Šœ«¸ð¨.È,h)èÚwLgæO˜°¾éh¥¥¥S[C zýõ×3ƒœïã… ZVêáÂ(…¡‰5977zÂ=öÌÝø})p^‡éP­ÌOâ[¸ÑÔÊœ„ó¿ôÒKÛ·oï½÷&Üq`ÌWØÑB A‹O3xÎÓà¾*¦ÇÆÆöï߯&&„žB$/&üÔ’™3m,¡À¸ÑTWWW×Ö­[_}õUj;Æ*1j_iiiJó\¾æÐw+ /i;Ù,‚PÓ fÓ;.†óÜÏ/“ ɇš ÷²®¯¯ç´x¼äJ;”'×›rø¥g&³ p j9H̹ì¸;¼¾øØ+¯¼²nݺ'žxâ¿þë¿&ÜÃØf¹!µ2¾By ΑfÆÊ`à‹:·ÜrËÃ?¼téR©j!„ô´BøÙ455q42Ò Ê/;;›Bö¹çž«­­…\†t[µj÷†äéO…ÚÆKÏéf—ljãó¹¥ /qþ§Ÿ~ÚW4#Ýìü|Ât¯,Ì;ÿ9ÏãÉ> ›––æ+‘CMçä æ‚¸¬¬Œ%ÃmGðC¢p¨‰Y¼µÔÊ(7NÔÁÌäx¼‹ü677­ á‹’G÷ÀsÅ*çÓS+óäœÂùôª'6l0ag„BzZ!BBúŽ »  €!ÿ "! !¦!þ8ª ñÇ0ø0Å7w„šdd@¤¼óÎ;7Üpõ×^{Ûm·q ›ó†÷îÝ‹3ççç{ÅÉÆü¦{Â1é•+WœÆÏÙl6ß&Óÿüç?3î!{¸ ä=gË XÐy€ü}å•W<’2ÎA18po-wóÔSOá%ã2tÃØ1…‹ Ù+àî<øÑ. Á5ïÚµKÍA!=-„á!ÿ̪Dè¿ììlŽjó](ìÿøÿ€¼Þ´i¤0(„)6¤3dèþð‡Ÿýìgø %#7xÇÇ~ûÛߦ¤¤pϸ"ЩHŸl šÃÒ¸žÉ§!y!ññ+^#¸L¿÷Þ{_ýu*{n²»dÉ|׿t:‘¸zõê'Ÿ|Ò+&2uûí·ãwñ1ä¢Óáp@ ã¥ùŠ…“a¸Š”;˜ð"ñëÐÊ_Õ×ÚÚzã7"û£££ªùBéi!„ˆ]]] ?̈"îÅ‚œW ñÝÔÔTUUõë_ÿbj2´¸¸Ÿã7 F—-[–ššJ=Ê1lPÎsÀ[~ªqæY³fùœ†f…¨Å/þýïçŽ9œŽôyóæÝpà ¸ŒG} We|íµ×.^¼øÿþßÿ Ÿ[·nÝ­·ÞŠ=òÈ#øôn<§¾pº‰ž`±/Ö®]»qãFUl!„ô´BÄÇrÞ0vZZÚ,7/¿ürgg'Ä.Ä+Dí<Àt†£öý÷ÿ÷Ûn»Í+ÝÁtßÁi|‘_Œ†hfdåööv“^VV†ŸÃÈz\›I¿é¦›^xáO­ éL$ï„dóæÍkÖ¬QBHO !Dì%ukk«ÓéLqS\\ ‘zàÀPÓýžœ‘þ|9tèÄtAAÁüùóóóóqÌY¡¦'!D ¬ZµjÙ²e{öìQBHO !D,9räÈÂ… srrªªªzzzÌÜèÀéÿß¼Y^éSÆå x†á 5=©RíBHO !„U$õ Ó™3Í߯3ffΜ陂—~Ï0:::66æ›>>>þñÇ{%†=¶Béi!„° Í»Çþ¶ÍÄßÿ¼to«œTOÏš5Ëápø¦?ýôÓ§žzªJU!¤§…"Éôôq}ìåñãméi!„žBqB=í! ù’ÇÒÓB!=-„"(=í) Íqzú½÷Þ[¸pái§vñÅßsÏ=FO¯^½úÇ?þñ¿øÅ+¯¼ÒlF“žž^RRr×]wyæ™\pÁ3Ï<£[ „ÒÓBÇbÚs"ŽgÎÌÄÏ¿c‚; ž¾úê«çÍ›÷Ö[oõ÷÷/X°ÀèéM›6½úê«###iii7Ýt“ùâ¹çžët:;;;—,Yrúé§Çpgo!„ÒÓBIí½ÑýòØ(uëÿùÏΘ1ãùçŸgºßùeee_ûÚ×Ìï»ï> á»­­­º B!=-„ñ¬§½ ÓÁÌ÷hnn†&~ûí·}õ´Ëåºì²Ëþ›¯~õ«^_$_úÒ—ÌéB!¤§…"^õ´÷üé ×# |âŸ0cÌFOïڵ듟üdcc#Ž+++ýêé÷Þ{Z_Ñ]Béi!„ˆW| †ºñ’K.IOOÿý÷ÿú׿~ç;ß¡žÞ¾};ôtoo/÷âŋ͠5¾xå•Wîß¿ÿèÑ£=ôÐé§Ÿ~ðàAÝ!„žBˆ8ÖÓÿN¨§Ÿþù/|á 'tÒE]ôØcé|Ýu×}úÓŸ>ûì³×­[ÝÌ%‰øâ5×\óo|ãÜsÏ=ãŒ3¶lÙ¢[ „ÒÓB‘8øæqBFGGßyçßô¡¡!nKþ¡#ÄÇÇÇ÷îÝ‹ÿ*p!„žB“m#„BzZ!ĉY¿~ýÖ­[UB!=-„B!„ô´B!„BzZ!„Béi!„B!¤§…B!„žB!„BzZ!„B!=-„B!„ô´B!„ÒÓB!„BHO !„B!¤§…B!„žB!„ÿ»u,0Èßz»Š"|||ðiðiðiðiÀ§À§À§À§À§Ÿ€K$+p]_ŠzùIEND®B`‚libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/resources/images/banner4.jpg0000644000000000000000000024265611021722676024005 0ustar ÿØÿàJFIFHHÿí ÄPhotoshop 3.08BIMí ResolutionHH8BIM FX Global Lighting Angle8BIMFX Global Altitude8BIMó Print Flags 8BIM Copyright Flag8BIM'Japanese Print Flags 8BIMõColor Halftone SettingsH/fflff/ff¡™š2Z5-8BIMøColor Transfer Settingspÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿè8BIM Layer State8BIM Layer Groups8BIMGuides@@8BIM URL overrides8BIMSliceson™banner4™n8BIMICC Untagged Flag8BIMLayer ID Generator Base8BIM New Windows ThumbnailîpPðÒÿØÿàJFIFHHÿîAdobed€ÿÛ„            ÿÀp"ÿÝÿÄ?   3!1AQa"q2‘¡±B#$RÁb34r‚ÑC%’Sðáñcs5¢²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷5!1AQaq"2‘¡±B#ÁRÑð3$bár‚’CScs4ñ%¢²ƒ&5ÂÒD“T£dEU6teâò³„ÃÓuãóF”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö'7GWgw‡—§·ÇÿÚ ?§‘OØwRòQauVêþWü%[è+] Œ¯2k­™mv5Œ.iuv=›Ã/§vú}­õ}þÏÑÿ9ê%§QéoÇ>ÜŠw:©Ô‡G½ŸÛo½SÆë·.–¿Ô¦ªa­öZûKN=ØÌüPüº±.²Ú½J­ûEztþôo±còâ„Ï ÆŸáwX)Èeeî¥Õk×®ö¹žÛ7~îßå.»¢úm6QYÞÂÖ¿Ô-ØÒñº»W¹ûªþkÒ½ÞŸÚ?ÁÖ¨[œëéûuÚª/ñæ·XÒ%v㺛\ʶÙeÞ»¿KüÝ~–7è}*Õ§d»ùæ×sI²À½ÍiÈ¿íŒöz-e®Í•z?ámý7«Oój|¸¡8üúþÕÑz†t¯µác‚溶<ºÆÈ>Ó]•7wý¼¼Îú :vCˆý&=­?渱áw]ª4g]ŽÙh±sƒ„_c­cZ÷WŽçîuÙ³ô>Ïô–ƒçúÆ gí*‡\÷0&Ö7"¿úJ(ðF|0ÖªÏï/$V¯5ô.ÓèGÀû›ÿEuW2Ëñ®Æ:¾‰¾¦þó4n]_æl¿þ¶¹wVN6Pà—ÒïëWoùÕZ®tn ì<Ú2›©©áŧ‚ߣcýzËØŸh'ؘŸð},^/Kõƒ5ïÃp‰"L;±;Æ×˜VLÊfO¶à&ï´ãº¯c·<˜ÔÝ_«Ô/ÁÆiû;ZúÁ°C¶¸‹Gõ?1߸‡Ò¨9¸¸¯0Ç]¹çÀ4(N1Ÿ›é|h;½¯W`eÌ{xk )-\ß[d=íýæ<ÿItÝA¶Y€×¼{ÃZç|`Òc—?ÖšöwÎiù¶BÎå}9= ظ¼×ç'óaüª#žÎõ\¶:„?ÿЬéûe»wðÉôbf[Oü?ú/úk'7úuœý3ô8\JKÏ-¿—v>ï¤ô)û6ÓÑéðïíúŸÕüÅ¥§ìkþ—óô§uCþì£ÿ¼‘%7èŸ$ÇgÔhÝûMÿÎNæý³ÇýJµÖŸ»ÇmS<ò~Ÿòÿsþ y"J¾?˜y~ÅÅìñãþoeñn¦'‰ôíþcù{žõ?ÀÂ*˜¿Kæ8\ºJéùrÿþãÓ³ØgÇÛ™ôg쬞wùzŸ›¿ýü£ùê×J™lnŸOócÓ¯èÏ·wïÿ!p©(B?·ëÿ5ièû–¿³íóŸV7ý;~–ÏoõVTþk¥ü•$³aüùþü¶ÿ g«îÙÇö]ù&’Ö„?ÿÙ8BIM!Version compatibility infoUAdobe PhotoshopAdobe Photoshop 6.08BIM JPEG QualityÿîAdobed@ÿÛ„ÿÀn™ÿÝTÿÄ¢     u!"1A2# QBa$3Rqb‘%C¡±ð&4r ÁÑ5'áS6‚ñ’¢DTsEF7Gc(UVW²ÂÒâòdƒt“„e£³ÃÓã)8fóu*9:HIJXYZghijvwxyz…†‡ˆ‰Š”•–—˜™š¤¥¦§¨©ª´µ¶·¸¹ºÄÅÆÇÈÉÊÔÕÖרÙÚäåæçèéêôõö÷øùúm!1"AQ2aqB#‘R¡b3 ±$ÁÑCrðá‚4%’ScDñ¢²&5T6Ed' sƒ“FtÂÒâòUeuV7„…£³ÃÓãó)”¤´ÄÔäô•¥µÅÕåõ(GWf8v†–¦¶ÆÖæögw‡—§·Ç×ç÷HXhxˆ˜¨¸ÈØèø9IYiy‰™©¹ÉÙéù*:JZjzŠšªºÊÚêúÿÚ ?©.ŽÜ"ÂÚøÚøf››Ï`qU”Ó¼‘ùa«¯ ¦xÔÇ,2Çzyž2Q•Ôð¤XËÖ-<ÊÁ:¸ÓI9Âú¨n"§àºid]D‚=)RÔáCÅ«\>Œêá©s²µp„LÔÛ{sä _4°ŸºÆíŒ¾Cìi¦ˆÈðÖÓ¥Ã1Sm$,=–Hþ$ )+¤  Õ¤’-Œt“¥ª4QBô¦`&s¦š´–IÀ5:ªM5`¨ÈpÙ†umËIUÉWÁSVc¥I’޽÷ÛÇÏ8†œ¯Ü¬tsL:2X¿lÊâÖ­BjZŸÀÄÇ ÔaJ UMA („K«*ž>_o ç¶™,Ç z]uVâ8* ¤u¡Öº‡pàñÐ&eh¾ï¹¶ˆ$J†Åň!(X¹Ü"@hÖ†º»¨Ë¤V¢ªÕ$TsFàzWi1H™…xVŸ>êÓÐS^5Î@;wÆÖ¡Èm ½óGÉR™ ¿@òBf:qKºf¬w‹JÇ–zX“²Æ* Õí*ò‰ö2;3i *ÇH!{Té …-–¯vŒb—@Vh»ÔƒŒÓæ˜#WSˆÇD·r,›7 •XŠefÜŸWQ­ØK3´êi`û}kI”jUÁ刂¾ò„J µ8Šw(âãM{‰€†¬(wŽ@øt4WJRµ¦¡\W!¡íÁ¤ ¡Ú4pøfËmêªúâòÍ/–ª-ߺqÑIá’Y!–ƒLŠl„‘¬³håbB1Œi_:V•5ì¦:|¡+ (ì2jhpxUÅ *AóéuB-­º1’b ÔHvöˬ™š¿Ê2»K”­LÈ ¥NF©äÓ}1ÞȨÊÜJ‹â£ëj5HàÇMEkÛOˆgÌÔ=4Ú­¥Jèjp©$+‚I'ˆ‡vx‘ÕŒÐg&Ü;š‡l¨˜ã¨wÜxÉáj©¤y1©œ’‡Â%×+‘:E ²JµZÅ}³.ä·Vqxó‚R" …¨5$ ࢊ‡b¡º?71éz«³´f„€Ì (ÝăĂ@"¯Blƒâýp–xŸQR4 ¨‘™qòÕ´¨¥Eãb­ô…e½Øè’BÕ”çó?‹®EAp¤Ê“ôÐBÓü‹JdÿsOòò‹ªiûËâÏquüôñä3ìl†çÙ¡™ãh7¾ÕÇÔfð”Ïeh%Y!˜¨U³‚É *ÁN¦‘v˽¾ùbmP8 ƒBT` ƒ¨V‹…,êôd¸…@5 êEN’+ÀŠðÏÖi]MìÇïœìôîÕíªL•-4Ÿyc23o-£…ÊZwŠ9§««Aå¼Ae'JÈ#¶@Fæ ,ÑÛZ¼¦„P‡VXÒt’È€Ó •*`Òk ü©ÃåZ|¼üëZ ‡¢«ë¼¦^ª•¦ÉÓîM±· ýÂè§®ÅïšÚ‘ RÐI¯ˆ¥7‘|`Ó‹¹"˜'a~aŠ@P#Iš0ã(~Ö'I©£Vš­Eu ëÕ§âîÒk\é¡ÇZR½$ëñÔãcm ëÒÈ™–âÞ›{-Z KÎô¸Ì~Å4¼.Lz¢Èå'qãE•Ä¥IeQc؉†òêØº² ‰ã<s¬µr V ŠÃNâV¢ª;0^™rh©ÇÌ8þ"£©{ƒ”;C`e()¤Jø°’fr¥`š¦hwæïÄRÎчsN‡·â§‘U–%P]¹,ZB$½Üá•Ø‡r¨h ±ðⓆ© ( ªr;WcR4làP®F¡Æ *1ò£qj‘Òÿ±aÇÐÖárXz)éè$Û½}¸~Ü š…is»GoVå4TÈ6©kê呃­’ÚWB®Ÿa­¼´SÝY\;x¥¤ â…†F4¦*h)N!zm“¿N¹5¼j¨ÇvsB*:]¯^؃iÇLS;·e¥2TU&¬DÙиªaU’×Hž4hK‰žEÒIpLí-´í!í½|«ÄÖ¢€˜$eH©!|¡<Á¥H ý pȧùºZìhsO’¡˜Lôù½Ÿ¸³ÔÑ»IO‹ €Ê¬¥Lr+¬déà”A€Œ4Ÿd×l¶ê²†’@¥©øN‘Ä DUTj$1ÍiÝXÙÙÙpÑ¥*|ÀÎ|ÈÃçãîZ<>á«Êå`’¢†l TõôeŒqãY¼&ÚÊE8   ¨°s¡/‰}>’½Ö$ži59š”Œ0ÅE1ZÕ‰ÔWÛ,ªÇO ‘¤œ’I ä)œÕ‰#¥smÿ¥Ü”ξZÜå ÅÓLõ-<”Ùêªf‡ /ÝÒÒS:1 @}5k†±ó#©V&”5õ`~F„qR”S^’L¯Ò+FTš}´¦A¥kM@šŠ`T5/cãNR“²~1ÐRÎQWKIUBÅ£ê1R@º¼º>¢ ±Ptë’^`XeXuJÊÕÐÐSæh B°mD+V‘FÑÇ%ÀÓQ\€x k@¦´*Ä« Kn¶y›iOF¼˜*ÊÌpžWe¢Œ¢ÓÓµ;HdŒÂ'ÔN–, UÄ9Æc†w™^S!^ Fq$pô ”%°r"ò•ªÚxä0¦@© ¬ª…QJE~¦EJ´•ÍH°EU ÔîöòŠƒ¸¸ÑJ¶äê*. /Ô&Òƒ]5(§ƒó,˜$Ðàímþž@Œ*(E(*¿hu©©ІÔ¸B£JôLû×jÿ’¢1fTv Ñ©’uŠ(Ù´Éc `ü‹ªý/ òÍú›ô E J‘ðµiVF‘Šaj¡êWJÑP5q‘ÜÈ杻Ҽ­ ¨ 0£ Ðl SÐåé*WëѼ€;ÄY …GñÉkËx>Ç;í°¹Û®”‚{;|óüY ¨?¡jR¡.Š«‚;…XÓ zT W‰ Áutd÷ÄQME‡Îêy£¬ÆË¯ûaƒÐ i9ôÊc‘}Höu±`WÜw±h‘æ¶YcC¨º %š´ÃÍEÔuv…PV¾’{E§  ûjM<¾Î‚êÿF œËS¢ïšedÎLJÒ_R"‹ /¦ä3¾ÄÑE)ib>4+¥¸©´Š(k©‰šTÓKÄ ÿ«åþo^™§e) ŽmµiQérBè×"‘c~ ¨Õªà5…c Â@¾(^ÐTãZQ h®Gq:ÔB¤4¨êpÿ>ý¢„‘Šd鎱Ä< 7ïÇO#8Ž9eYUDdØ›Xêü7é$×JÊÈÌ kNÒN)Z ®®8†µ©­>Xò<1çÂ-ñµIQF#UÐiÇŽX‘™4jeÖ$:ËCÒIå ‡ä€7KR.剣?ÃA@AàG•OËé$¤)ÔW‡§Ìÿ«0 éwNÔ´ò³©xåBͬI …¯$zØ.°ÀÛ€Ò¹öºA¬®€PE)ÀÀŠB)]5 ’kŠÕcwé| ’Vƒ€§Ÿ©©©¢Ò»UôÇ-l5d 2Z*€Ä*;‡ŒIéÕÈTÂ΢l¡ÛøåúWÉô ôà>ÓÄâžB˜«SK$LÄüG…(k_@(pq“PN(:1•“Ð×RÔù’)tIÿ’Ìä0ãÔ#œŸëªçØ^HÄ•uJcöŸðšþTêÑib¡h3ž?Ÿægóêð–'oPÐn-ÕÓ9ê·8½á@õ»pHÁ ‡7k1­Ï¤Õ@AÔwä-Ívžb}¶áéà¢ñ aÃöÓùtuµÌCOlÄÅz3}Ý´*p¹*ªˆÓA2£þÉY’ãUƒ5Ôp?>ç7Ò­¨œ—#aN=0õöîYâJF˜P4þÔƒõ-ípÍþ±ö®b·ŠZJ8ãòû>]m\³PðèOÊ'ßÑ3Ç}|:\Ž8õ úZߟñöI4!Æ ,8|ú±Q 9§Rºï:‘d㣩`Xr?N«iêA÷ó¾ÕûÇo˜¨§Îm”°£9#£é´éÓD0؇ p9·ÐÜÚö·¾lsöÓ&×¹Ü)ˆèr[ùù|ºL]bíê‚6åI$“öòÿhX [b ÿcì?Ë §s¶ÇGT’š~}Qök"jÌŒ=GÓ«èDœ©}Vödåè—tÿ‡¤é -FèFìi<»b¯ŸOÛeµ‰+n°?Óü}”ûÓú»uãp NŽ˜½,ÀsJuP=¹0Ž:¢X-’^tÿBG*GÂ÷¿¸S’Ó¾ÔÓÓ ³±©ñ=Vî»Ý‘ƈä2 r EM¿ ?×÷–{2ø3¹qöt¾ÈK"ºjëÕSˆÎŸ¡VçêÆ×þ—Ò×'ék{Ü1Ö­øxôm‚)¨ëÇS¶Ý dw&†Y tôŸíN¥¹!UooñöÎér¶›mäÇ!#­»±§y§¯ï¨6; ©ŽXSÑ-nƒHÒ€ç€/qõ7÷‹p¬›Ô× çUY‡ìèÊñ2¹é3¼b›m.F•ËGiÇqcã7Ô£úrßãõ÷Üí¯õ%»®ì¯V“ôƲ¤ŸåÐùüª7äkò«²ö’(“±ú#x¶>9 2M—ëü¶xÓª  4­Œ£«+{ØocÎhØd»ößvTAú%_çB¬OåÚ>ÞŒ9rãĸ™ ŒšV[ßgÒ‘ 5ÈÍåñ³X†O¸•Ô=L‹-î8úûÂf%YXùªÿ—‡F·JT‚puŸëùPsþÏE7v!ƒ7K•ƒÒÖêK!* d|5N¤ØsV6âàûÈ_•dÛâQøqû:\{„lxÓ ãuJSd-67#LÎ ¬ôÕñdiø?R)×I"üb}¼w*iR?oU¸¢)ñtPò³+‘ä2EX†ÄðTiF‘ø±_sÝŽÊ!Ó Ó.>Ia·-UZ¿SfW‚¦äý9ÓQÏ×ÙÞÜ«õöÒœÿ€õEËS×üÝ\ ž—-’¥rTSä'ŽÁšÜHà}Ëlj+ÑjF«#Ðf½63¹•µߟ¯øÿSíõE )çüÉëPqôºÉþÆàoCšg…:ØÇ›@ÿ0~–‘Gûéǵ„ÉöuäÁá×K}sñ©üéþì~=[nœ)mª#þ#ý´’ˆuQå^ÔÝë¯âÇü=¢`ÕˆÆR 6Ú¬yÿþÚ”T‘òëiÔæÔ'O§Ð_Ïûëí8Ãlžœ­XtǼù–€à_¡úÙOøéìûl¡¶ÇZ–”2á¤+¥<ž>£üõöíÀì&¼L¡£ ž†:¦q CJ›_í7ä¸ÿQþÉ÷ 'Ã5=-nŒçü^rÿö³ÈîT¾ä¢i!5PüGíé«Ù‡^ëÿЪݱyC¼vlùoô¨˜ôܸW¯\œ»¼cN5r°ŒˆÈEQ2Sý«BKäýcA'ß/šKG‚ãÃk|F@Òc&º@ã^Ð<À¦OQô-)tvÖ£9ù7ùkÆ£V¡åÑ”èÝÑÛué67q¤‡hp{¢8äÊ>â1=@Û¹·ßË3IR+¼F2W•"UÂaíÊÞÚVŒD"”Óš$ÆpÍ^ÐUŽ y'(*A+ý.ÒÃ)䌚燮¢¤í<;îZ™%ßõUá)Z‘*ª÷’G‘ŸmÎæ‘¤ijdÇ5XuK0‡ZÚÁÁ¤‹ s£j£SÇ·HµÔ*iG$Ц½®YÀêƒê!–VÓ V§óµÈ®¢†Ÿ5 — í/löfÌÑTö•íÛPøê÷«Z&ÇhѦóFTÐy4éÖBk³Fæ rQ<&A)A A^ê.žâ¢ÕT½C%V&eM¾pIc@U‰Î€B¨4`(kÜ)mLçaîM˜ÆeS{Å«Èaa‚W;‚:¨éÞƒr}ø¦Y ÉrùcEn/¤­eúhî|x%8UXU@ÕÝB¡Tj­j@×°$$¡Ô|È @qø…;ÔàñîÀÃ÷^ß¡¡¥†^Ǫ­þónÕ™èòœÕ¾!h6‡ðØê%ŠY&zªjÏohì¶õín¶FIQÖ% £ð­5⹡$+BÕqBSÇÀ\É.DŒTé9…AÅ+šd‡{Ž—»$Æí—³EJíº‡Ê¥-NæY“!ýïÝfâ"9 ¯XØÑJˬ³¥:Ä"ÚWÂlÐÊeé,ijA¥)ZŒ|M«™rQs/h‘Æ”ÓUuiP3èM@"€€ê6âÿM‡1N¸ù;A©»[%dj ÷G€dNÑÂG•g18‡îß.'3ê!Þ}DÝšþßÓe ±ðK–s’¤žâMx³SLÒ .SÄøŠ* o@03lj<|ôùgÖîÌn×zJø·Ë`üa’WͶø;ntðó%$ùhÉ+`!1Y}1ëÂ…²*ñ²š  P0É4,¹h5­NLdñÑÝA_/5+’*¤=ÆÖ>;ÖnÈ%¦þ&Û‘ÐQÕÌ?‰ËC+ W*š*Û\’r¬.ÇÛjÈ—:[9ZŒœÿÑwh^Z²äÜ3³Èk\qaöð¦p)§ò´½‘Y$1QTURËTñªËQK)šÕ”Ö-=-SHžy ©†FŒ€ìàsézâg¶¸¶IÁ¡ ¨É ì+çOQç `“WÃ,)RÏ>˜©¥}zÔ?æPößH|•ù;׸ì§`dpU,Û‹¬24[ˆâ¥Âï­å´ó´‹ƒ’9ÂÁ&:ê xâѦ‘eRO­LµÉ;†ã±ìòÏ‹˜‰ŽDr¤ t¨:ˆPÄ|F Ëœ%¸·tž`­Z>8Ò”Á©<3ŒÖœ@$æzô§Ú;®?ºí)òuÙí•YŽ’¢³u :ScwÄyh’A*ÕEFÕn³„C ’ΣHÎÒãek¨Ì D²ø{†¨´­{‡PJÐÓ@m UGeîÔbª ¯;‰îÉ©p”¥ïøv %$]¶sÑn­Ù]+Å_¼W!üâ6ÐyêEJË.6 ¦®+±$ò°^I'Ö²l3ÝKúvHbZ¨TÓ®²çJÔ Ac ã8 ^@©ªº¼ÿ–x·åÃçÔ–ƒ¾²Xý“ONݺ•u[º,·‡'ºÒ¦êïmòèù9Ö ÉMA*#L…:ÆŠt„¶îb‚çrf[6St4¯†ÉáÄÇM3 rú©C¨TŒbÒEr²¬"¥ÅAó®ò¥8ùsÒÖ¿ÝÕxêjj9ûNJ|Vec«š’·q@±É_±6ä•ó£SÔS´U”ÙØ¦.SÊ“ÈÞR\Ü’ÎûZMãÛHÎiP@ 3•Ô;ƒ¡xiò°yÔý"Ú±åO!åSÀãì5=)qËÚSv„úåì˜0kØu®„×nÛé‰ÄîÆ¨§ žcA6«(0Øžœ…’A'¹[XìÑ”ÂÎm–” ¨2Æ¡ˆa’U—ʤU¾ˆÓK´¤¶­5§8Œ‘*3Lô­ëÉ;nŸqDù¶ìA@1ù¬„ ’›:Ô´ëŸÛÙ(a,õs•£ÍøUyR |ôö¸(ψÐw"W¥ZD]§‚©b$‘œ=åXbW1±$DYö»>ï+: ¥»ª\Ó$àgãS¨µ è’T ƒuV€`€I8VŠH¡í5â:¬w‹)Ž©€¬r²¬†9£%…U6…œëU`]Д”|!¶·¡èèp –\ŠzdƒOAMY§Î‹SÒõ†•*uÑZ¤<òÀ€@ ¥óƺ‰ ÌzÞª ù—¼µÕØŒ"»²,M(d]8ª#3k‘]ªèC-é:J‘&Я‘…nàIS@A ¨  Â–!‰îÏjÒ©hÀñêiZ‚+Fj·  ]ZK‚{y°ýGýËÈ@ÆÞSÇ4€!’Hf/Åeɬ‘Â騂ÀÓ–Ô´·¯›{¨Ú‡I®tü\*I5KTÐ’@ ÷(Q+*£2“ÃQÓ†j@o2ê8žÒB­(·æZ¡»w­‰iâ ÊVS0š%X¦ŠIˆÿ).Q–ŸÔ}rMLÁµ»9ŽÞþk«Ü‰( ä5+S†i ЊêÔjRNÈ«'j[a4]5©ÈpNX­0 jcp“<ñ»¢Âi&I] •ƒ²™e•Û†D±ýÇÒI'‘ªrÙÍ#Fü"€Ãz“R TT\eˆ­KC¡ 'H¡í£@u.¤eÀ üC¼`X£‹…eV‰È+ÔѶ”ºFV@4€G¥5k·«…go ‘¤­A Ž$qãŸòÔÒ•ÆH ¾Ž·^J!§WZÞáJ1d_Jë 4žÈä>=Qˆóâb1iä‘Õ•äslIºÆ²¹Tš¤Ðu’ÅnþË┳4e#M3L @j8@£äXW$žÓÒÆþ+( ƒN¯pâUBÑ{Y” EVR…ëå&Ô½3ÕÅH¯•eÑöîBÈå¢ó$JReˆµŠ¹Ã…€öoµ],[‚3K†liÀ œ9Á$é €zbö%¨žÜ„!@54 j¨ä­@(WA$®R±I0OŽ#g†M`FÄÙ`Òä)A ¥—›©¿f3Xÿ¢*Fµó­ý¹é5+Ú §JT–¡¥+P)éŠq\àñÎM^Ý7/Z×SsÕâÀ¨§Œ¡R%.ìg§>š€]ä$·Ò÷0òÜ~ïßV*\)ÔA© E:…A (Õ*C ‡f@…›I$-  «T«ÌŠ šÐUA’òFÕÈPSÌQ8‰ÖQ«ÂÀ #@<Ÿ¥ìÀ|!&Dš2DJÖ­A€ 5BÔД$SXÝSÕ:Šˆ!-†6k­‘J¶«²ÙU Ãý-Ïõ<–öüDë49A£ 1©®†PB³H»&´ Åý‚Ÿêþ^Eަ8jI0i* ˆBÉhÉE1äðÇ~-¹²ƒoI’Å#«+)^•¦¤ $SZT¨=ÕüLÃ¥71‚d©5§Ï§©É8àS‰émж­ˆ§Š:ZÈUU çöd’N“,à»i»j[Ü’¼ôÍâ‚ì$ÁôãéJð!FiF%²E'ÂjµÿWåùt$b\§ž‹Æ –î’3…uhÈõø[üÐðß–úy±·¸ót DrêíÀÓCOSVó§Ê£Ï¤‘²4‰#5˜ ¯‘À9ÔšS‰ÁÒŽp™ ‚° *0.…ؼr1 ­uÒ@$±½­¨XÌŸS¶@<;|°@®+@+ÀAkÇq4R#Q‚O¨'U™¨§` xœ¢ÕUÓC%ˆš•X¹!x×/öo©<Š/¤€oøµ½ƒ.mL0ʵW"Ÿý´?oHËd)Ô”ÏóþuÇ—Fg¥·¶O`îý½»hj'XÅDNé êñÜ‹ž‹Rŭ캙#x/í.!q òøMiùô²ÝÚãŸ:W¥:Ùÿp GtõN °pʳ.kKpŠÃSã¦/¡!£”oyËû¤|ǵYîq *÷áqÅ~ß>…Gõ#Ô¹ªÙ¯Zݺå^c§–vdÝW©J޳8HY]UN:`U\tgöîq24PºÈ¤È«©ZÆÏoZÛèõ41ùŽ”S‚zcÉ p¹X²úô;ùÿÆþ¥úéìŠîÕ'Ib4ÒA¯[T=Ƶ¯G×¥w”ll1I6§ñ§Ö×?AÀýDßÞû×ÉRC“ÇCž4Í8ÓìëN¸QÒ“¹§Ó·«4¤~æÙ$‹ÿ½{Æ=‚s·Œ®|AöŽ‘HABAê†7M‡lptÉô$X/¿’ÑÊ8Oæÿ[óÏûqG·¶†AliZS@“5Áõ[Q“[¸+k˜±1@¹ô*‹ÿ_Oûϼ§§ƒ¶Ak^æ=Ú«x @(õý¿g]Ô9y‹ÿiÙˆ]7°½Õ?À÷¯mĺPPàt®ºh'=ß.= Ý=zÍÝOPçöàukÙH iSþÃëì)Î×B-šH¸1þ}7pG„Ú*Ë×­•>3ã#ÌmLt-´Ó¤`¦§èHåAúÿ>ñßî —[»œ‰>\ÃѾΎѫÓíû: >YmàT’ÖØ!ÒYF’êT’ʵ|É´oâºÐ*ÏÆœz[vµWjÑuˆÂäUüÂ~,î)çÃs«EÖ™­Z´ÿ íŠÞ»ª.¶ˆÎáG#éu÷'XìMºò‡0Ø ³b1Z˜ûÿã ôƒc˜Ç¹[ÈÌ fÓO:uµiáe¤ÆTSJÄÍASYE#sä¢zªIR?êD´ŸOéïš7ð}.áym ÊJê>ÐÄP}”= ®SCÈš9é5´rK.ÚÆ/?ä5tñ°KëSO‚>šeJ8ÅÇàûµ«÷dž˜ãåÑwßЊ,¹¼~4¥©¥EÁØìÚÐH/ý†{ßú {mÔLÔפ3Ò¨Wz,]‰G%-EK˜šO°#$B€Á¦ÇWcj–?MF––§èyö%Ùä_D,e zŸü ºÈ=ô¨°ï*: ˆr9*Dš€Ô ˦[hÊ­c¦Òzi‰ÿi@=Ž6éƒíO‚\+0§ª'üøzGˆå MUoò–tÕmìö:¥¼•Ë×Y©UÈ%*`ªÍuåKCr4åÿ­…þžÚÜÕA*Чë ,æ3ûxzW§aPa2Ÿ?Ì×ùS¡:²z•¦¦Ì»´sG^ç^<4‘R¹—Iú28ÖIä‘`æ§Ô«‚(Õ#ü#ü5ê³Ë(¯‹`ãgÆ"´ˆX¹4º¯c< S¤“`¸˜xÿð÷4r…ÈžÞHÔägüµéLeŒQ–tnÕ8,Å4~¡eQ„0'M6J’¦8£úþ–T½É;`Qs ~ެ@hÙkžˆþ>¥›1›‰˜\ÅŒ’5`}/$ «ëÇéÿn}͉‹8X Åt™Xw/ÓÎ.ŸÉ•¦F²¹YIû.Ô@@?V‘yöõ“º€ùWü‡­&Wçþ‰ßbR-íÎÆ †zß5­aë¹cõ?Ÿrµ‹‚0EÏQpçÈô…p|‚äÜÿ‡Ðõö`(W_wR£JEÊ·àñtãïÑ7qêã‰ÇM7%cúq$ï~Öù¹ù¶¿3žºù* ·û°.?N}øš¤tôëf•#©täÚ+}oý>¼ÿ¼{O WÙÕ1ZS§¸Çí1¸°ÿöüßÚ¦µ[Rg¹ú0ãüuý¯¶äÕåÖÔÐtá.¯Ó®Ÿ ñŸö:½r)ǦMâ¯lsÛ·þÇõöuµ0·§Z’ºF:NcI”Æã‰ñõ”Èöªãû'ÇLƒFSO>†Š†g¦µ/ù¤· ÚÚå°¶¿¨öO¸†ŸêÇË¥í‘ÑlÎq™Ì†O!þò•7¹2Æž3åÓgâ?oM6ãÿ%7üWÚ¯?‰ÿÞÛüýz½ÿÑ;“áÎ[¯ó}y¸è†íi7’5S6O÷%(÷mM?…'¨JŠ©ŸðÅ·gm ¾CmÛÜÑx‘ÜJä4zN¬P… AZ”Ô‘M#Q=Ù K·ª4FŠ£PÍA9 ð¨àp}+J¦„7®6¶OmîYçþ+´ vÎ÷Š(i·®Ò¨f53pÓ‚ñ¦ZZ£¼‹æ–Å Œ–0úÛƒGy ©] J¶(ëO =HÀ®E+ME–ë¢P²Ñdc†h@ÇŸžx3Jôn¶nûË´7U#e6„óÉ·i"QM»ðWeÝ{j¶MsÓd%Й(í®VHšB‰rYuH!¥¼l%ñ]‰ø{Ð×ñ¨ÕR+JTƒC|5V¦S5pGŸ¨"Œi•Çq«¾ØÁM>ÈÜ›V¿)³Äë¸vÃRKýéÛr¬>* ÝMºÄÈ,O4s—‰^çÐåT€]P»3¤QQŠ eÔëøphT’îrÅFc¸,ÉâI”©É4¨¥;I# AŒÂ×íL&n’l®ÒPû«jK ÓµÍ4M3xǪªC‘južª7_CºH¨"6!ZÌ$¹Ç!j¢…qøÕªZÐcM°ŒöV'‘ iBE+NŽ–ÀšP D.ãÚnM·²Qä6’UQîÓ5DºvÌ0ÊÕÝ¥M¢*‰r O%\rãÙ¥PY•$RBkœ‚p× $qÈQëJ¿ÚBP5>C$ð¼ðƒ¢EJŸ0pB j§ûPAÍ?ˆ‹ÎkhTÖb65?ñM—å¤ÚÕtîòïM¯Üo}çTšC–Dª„G(VhÃ'‘^1ëFP¹\¤“¶™4—þžÄõêâqÖ‡…*Aâ ÖÐväH°A@kèiÔ=ï³ë_3K8ÉìÈ/µ¶%+­éµ)™~Ïd`)õ,uyX ‘¡-é+$n.Œ¹m&¨Ê…sÞæXñsèú¸ô–áH–B¨š´/€?.$è)æ)aq5ØþôLÈÊmHâNÔ’­ þõíá‘4í»Úo·laÈšù+¼2ûuQPMÓI{ewIa]._ÂvšWHáJ*3åùTq†YE$ÔÊäwœàWØRE*M)NãÕºüGÌ}âRiÈíÚŠ³¬€µâÂ×®¹1U©¨ JÉÙÌnæFeSEk›Äc8T³4H@ Jš €Äµ[H'WFU±¾ªh`’kéLf€i$ÔŸW×UnôÉM2D³xᩊd¼¨’F걤M+pU¤‘ÈãK,zÔHÁ}u"˜­@&§‰hxùº¿é=¹¡õâEió¡õôÏ zþvÝW²»Ó˜•©¯Øõ]=º*2Y\ QÔÒoÍ™¹¶}^G#]QM´0y#Œ1Õ#ªFnìžÏý¾Ü~‡~»ÚÜ2Á/ê(®X””H¡hÅTÈÂ(õäK)†L!â)Cçè¯\g­zéö]EG]æ$›'² ®ôÙ•uA¾v“RÁvSÄÕ«•j8*çž±ÄBF ̤?¹y¦’ Åa‰&)$ EQªYºhÎ>~ ÝõUfS¤  (À§u p<*qÄŠädy €ïsl ŒnÕÚ´±åvÚþ7ºË5VùÙ°ÑÔÁšÁõÜt¦ž¢§+0’?³>xý2F†2˦TÔ(±ÝMÜ÷r4S™ä·ˆådb<¬"º«š¥F¤b*–Pš…EHग़|ñ\é9éŸ-´r8˜ºÓÅ’ëÙ&ÄíLŒ’ ó´D/äì­ùZÂ’C•Q]K fO$nGÜ´±;†GÇwèÝôÚ\Ÿ`j"•X~„HM ±R„䮤Mzq‹6–P4P‘R)Ašj¨®|p*GB&WkÔËÙ´Ã1±ãÇî…±b¥§ymH ªÇìºØ÷‚š£-je¢f†M-°˜åVxÈ,EqpeÙPGjë,SHHhÉ4ŒÄÕ— c—í(Y‰n·(+©)]@di‚@qŒÔPjU‘mZœ_~¶j“'´Z*ŽÍMÓ2î=¼¹˜aÝŒ¹ 6Êå¯5a˜«S¢–DñZÞÈå¸I9y"¸‚bÑÄWµ^•¦•$KVF¥@é‚’I‘ª*8§Ï€Ïø:[lˆ¢¿í Éíä?Ýýá‹"“ráge¤ÉíLN!âµîËGKVòËêU/'è½’n³xÈÁiQ§5SpI(BÀ5Ézt,]¡/—‘ ,qSŒiÀW‰˜ØS¹7îKÜ¢£ÏäwvÔ§ÂSÁ·ò˜¼ “+ýàÀS3ÌðNÑcdébæ‘"A$Á »)%÷2\ÊJËV%ê´ ¤f•Âj¨ FQ—H] ÃZ×Óá.u@:  ÒMAmKQPlü ù5·ú wO¹z§!Žo=‰ì ê¼¾%#‡Ô5´›Æ „?«2†¥kÊè¯.—¼sÌ÷»òl­öÍîÖMÉßF„–&/¬X1 úè ¯ÄÑS€Žiþ–æ' D–]µ~’ëÀª÷2ø‰»FÐí-µä®ÆOIš¯ÈÑË,y:€‘רêKOI¨¸PZÖõêhßIT-j(ÄtÀèhH¸WR¥³VšâHË>‚2FªŽ'V3Üš´UNª‘Á±l‰AOŽÞcpçíò~jz³$˵Lp¬2T’Z"‰gbT‚©ô` g¶x¯†‡Õlu/m;@5:u3q4"¤@0É’¬ºàV¡´tŠÐXR¸eRhhHf"ªÙ±ò´3D•(ÔðESà‹Éƒ ª‘µ$ªâ!äHVôÙÆ‚Ót#HÚ‚€õÉ­2¿êò"¬ ʯA©hP‚Æ„ ùƒŒÓ€ *žÕU[I*‰« $Ø,‹¬ á/AV³iñh`Ñ€C˜ †Ñ®ÚHR¥C70y ˜\HLÀ¡j­ÚÕ\†34Ô(XP€YÛeVðä*ÔA‚2A 4,‚ ”#I=ÐM¶w*Æ”g²A¥OKV‰§ª‚¾@.Øâ€Ù˜#¡5©Žc 0èòõv öf¯ëaTZ*Jh)²l|i sF°JóH%§w…äw&äXê$û9·ŠX¤Û¦–-:ˆ¡©+‘LåTàg‰ÐŒ¢Ý…•îdcSQņ3Br@¾^@€¦OæÝ„lþ©¨¥‰i(³€ä¨ä‰@§%éËI3<þV¨‚XÑ&‡a¡˜€\2«›1ýeÁd’†ŒI$± mU!AÒ¤’,µ…%³EÁ¦<…(Ü%«¥¼”©`–fuíÍ@&¨ÆV=S•hÂÎÑÂgxÑtjy¥hÈBF®ÇCýY[Ü÷°EmgˆâO ó Å<ɧÆGK…«DIP I”©!ˆà1šà„ 4ª’gãc´6@«4ºcAdOæ1ûlðƒßè|kþªÌ}lÕÊé•¢Yi¨TÔŠŠÓ‰¯·–>ºMl¬I*úTƒPs –9QUV!‡i®°nŠSWN¥¢T€2Ç$²3øh¤‡ÅѺ4AÖÚ }.¬@ö–¬Ë 0‚?#¬q4^dé$€0·J¢8¼"ð¯UAàÊ£E ¦“Z"þPàD¸úÿÛ)*ÂZÈ åi]õȶVG±A`[ô%Yt3´7Q0B¶õóÒÕ£ñ`üf¹ åÓVÒ„†XUK 8~FZ(d%†* À N˜Å+géŸ)Y–EIe5ÞÖW‰‹ƒ"(ñ¿‹÷No5í2líüGï€xƒQ¤@E¥ji¨4ífÞÂc}*”EÆ?†NâáJÖ´¯áÉ#ÏDåÒᎨ --TrâæË ŽQ¢xQÝ®‘€PºÛóxÛœà‚ßtKÀ¥°~!F  4¨)ÄPI<šâ™UrŠ? |þÒA48Å Û×.rdñ… Ú¨ÍÌ ™!XÈ!h°/¤ÝVÜ‚{µN·;| q*ºxŒµ[R€«j5`j@:+¯kZéÏʾG||¾tô¯QêUZŽ'Œ’’‡†KyA3[Cë+EtHªª¥µ  >Þˆiv*H Pr+¥½+èÆ­¥–¬ªMzz.Ù…@ ¹ýƒ>¹ó>”4 éó#KJbò±hHœ›F¥Ò²z%Ðñ¢‰cׯB…kú̓۬mW¶&ŠV¾tÊâŒÔ4*NA åfPWý^¿áüú_ÒÎÓÍž oã ¨>‰ ­¯®ëȸ7Ü{^‰T©4óó­ ×Ò ‘Jç ô†JT¯‘­+Bà+ZùúcÖ ¬^B`âpÄù©š5X•µÊé0 Œ¥¼gH*.x·Ø:H•&r¬#×…+Je‡Ÿ“/2iBdVªFj¤jsJVƒâ­M@ N s¢¬’*È$@¤G"…d°&) x_Hi.À’’¯'Ùuͺ´äæ¼}F§ù½1N›•P€bžŸ*|±AÀTsÚÙ¶†¢*:’rCÇ -eW>¨Û :ÿ°öÜlKFÎ¦Š£?åéØÛ¸ÆGk ~}l?ü°{wFÒÍô®à¬SUŠZŒž&pÅé‹i®‚2Þ½Q=˜ö ö³x[KÝË—%j#þ¤UÆ|Àùž„;TÞ$F4uéMòk­æÇVÖÔÒæҚˆ™M™nÀcŸ¯×ÜËuh•…ROðtìÚjp¯Eó¬÷{¡j:†q*I¤†k’>-b·ùê™øhzmY¨*†ÙY£ÉcU—‡Ò²6·[ ûK2ºj£öô£ÅíPJ¤Þò`3kHÕÆÒ‚šˆ³(¾›þ}Æ<ÿ°C¼íƒñÈùÿÅueÔà÷Œôh»7vÁ‘ÛUmlÔ²X+A1~[øß¼ܹ6ãhßVd‹ôƒùg¤²*˜ÊÆjHû:¢­Ã'·d¹·îjÚÃÈf°&÷°·û}öˆ+rͰáP¿—Iš: pèÃï ˆ‹jβ.¶ûb÷Õn-õ6&ßí½¡÷r-¬èAB:j໣éÕü‰ÜV««€ -¬÷õ6ææÿñ7ööËlý€ýž.übPU|ú(ØÄX±“Ï6–š¢GpÁ€vÔÄ+õb¶÷6ܶ©•Tö(¥:5²eðY©¥†)Ô) vRÌVà€Ì-¥l,H>íHáÓäêÒ>ÞŒ'ERh›Ï¤1‘ËV$0°±ç•ãéî5÷Rcðà ‹·9 ¡¡ëbŸ†k&>Ž) !bˆ1¸³¶åI°_Ǽ|äùL[öìšéITÓÔótw±Nªù=_ÌOtRRÓÇ¥‘DŽâ-1¸„Œµ¯a§úû”9Œ}Fá¶ÛEðÖ¬?.Œw3¢*+`‡­vó»ß#¶û mî¼Kºdö~îÛû³,lÁã®ÛYš<Å+ÄÂÚ]&£ ü{š¹RÅRÄ£ #dùQÔ®#ÐzÂB·pH£ƒƒüúúv1¦Üñå2t Qn<]ðDzèÐïu&ãI!µøÓZAü\“ù÷ÊÏq¶öÚùÓxµ+@—ýµÕZ¶©üú”oT³ø‚‡Vnz¶Vª<¥á¯¥n®«M ÐâËI9#ýëì1lºUÐñ¢ä¥|ëÒ¶1Ìó‰êcDyå•WA DõØt’›OÓRµtmk}Ï»L¥hþUé¹0Jy‹¦ý£Ž´¼ˆ¥S))TøÎbŒãõ7»óõöaµIþ7_OοäéÔ`¡cçÑ5ÜÕGWA”Rµq+^ª Ý+)(áÌÄþa‘ÛCHúÜû’v¥U[˜iÚ$û ðÏüeÍz&:’HÉzð¦œî}ÝIJþ½Å‰ìÈéDFËßb±·µ´ª›‚•0I¦ßCr=úéHTfB ±Æ€ÿ"?gJ¢©iµ0zg˜ÕíS‘°¨5˜íጩ ñƵ8žÇIJÚ× Mœ˜.žISnö¹‡EÄqðôJþtìëd*ÆàSU:{)c©ÄUT´EžQ&_èÑ‘¥ÂgÖ÷x’z¦7ú_ãîBä‰<+¹ 2jâ>Xÿ'[·fe5>xè¿xü´ù4qÿ(0µHUC%èÝñ³4þ¦’ÿíýÌìR@GÓÙ]@ŒtE²Ôk‰ì)éUŠÇUF—A_-5uLܰÿ[Üå¶Mõ;,oƧò$õ§,n¨³T\±-VßÒ[Dßr‚ú…PA_oDÚ]X«­5^НwÐa䣻ª9T°ÔV÷áTsîbÛ ÉhŽ£4"tÌM: Å”x½‡ÓðçëíWIêµ®R®¤S¨ð£úr-oè=éŽ{|úØãÃ1Óõ>—N8çÔÃÚþ$c×ül ׬á/$ææú¤þŸBƒü=¶X<‡øzÙã×*{’–þ¤~? þ·õ÷©|þΫçÓâK“ôúqô±·ãü}—µ ®3^·åÔ˜ìG­§äðöÔ‡‡o‘ÿ[^§Î’1þÇôúj_öŸ¨öž2(õ¿àéÃÄS¦½Þ¤Óc˜±6¸þÏjþ€~=›m-úN)çÖ¥ø+ÒJéšs}c›¡eÿk¦Ê>:d†h’‘îÿ«“ÑôÊw*¡:Góù|ú\jTt]3¿ñzÌÿÚÓ!ÿ¹sˆ÷"5K°kþ¯1þöލ~#öôÕìïuÿÒ³z½¹´{S>®²†ªZJœ^FCG1aQN(g@ÆtH­ î£S&Ì@â†Ñ½'0™bF2(u¡8«P€ÀdŠ2•" Ч0O”ü-Á¸Ô“J`Œžšõ¯ÆðøùŽÙ›Ûqá[rc£ª‹¿¾Î„ܨVö†à‚Y‰ŠZS,uFwPì5veR>²Ý¥†Î¨Ë¬’2+ÄQ¥* âE$’À$qr 8j3ÄJ é4+ÐcÔÿÁ¶Õ.ô‚MõŒ©X6Ý2Vxp{²¤Œo=ªRyÖ£1M9XtƯ $² êæi{k˜bmlÇI¤å qLŒqò9 Š©nÞCŒø  Mx<©P¢„Wƒ$ysâ°[:¿7ÞZdÜ;ZIê!Äîbc1bwZADi†jäJRͯÄQ ~¦ŠI9Õ42ÇnC÷àueb¤{¡f-RC2–4éçÂòÔ4uNB-5¨Àþ.™·FßÛÙ}ƒ—¬¥Ý˜Õ¶áÚ³ÔU6èd©1{½|>ÄŠ‰Þeªfcô$,ZÅ3é;-ÌWÑÂìͧÃå£8R ‚ÚAËUIê´Ó“ªÆ´í„ØãN< yšV¥méö&Q½1k&âÝñ5D¸бMS&7eùcÅŠû¿%Š#ä*!t™BydQ`¦ÚæVX›SD¬B•` -Jäpxšä-(ÚFIPÇâQ”0*hÀÐbƒQ5ãÐ Øt›SÌŠm󊥊 ±^ wÁîÉMdRo]ã:O 9€?„¬¡\dÛK+…ÕàºÑlu«Ð‚˃¤bŸ—©ÏŸLH4²ÊGÍ-“PjOž KAÄôÞ[îêó0ØxÚÛ.±ÛŠc(¡Ùø*?¸_%™a—Â’ª’¬¢@®ªá‡³k~UßDd¦Ü즾 ¦àº]pk¢ÖƒÁ'ˆ­4TZPTWº‡<:ÜM'ŽÁ;„ÐŒê=£·Ð©3á7eà0ÛÆ¦ÈN•:.þ’Ü,¦ÛåÓaˆpj GÈ -JñÈÒ šÑ`VHʽ5cý_Ïíü³ÔœHûð纺ìI$Y6Ðß›n¨A-JRföM>àV‚ž%[ÉIM$e)Ç’U‹Ó~SÚx7Ú7m§uJxi( Ä2 І*\°=ÅF µÔ¾ž=¤‘ÐV•à ?°TF8€~Á¥þ+oíoî&ñ¦;óQO[º¶e|òE·7’ÃOS/°"’’H$šÃ=d«1B‚Oµ(%U§Ùç¹’M¾E·*bFUÐv‚½Æ¬ ­v)¨`XГôÍ IÚ+\û1“ëN¯I½ýµö¥O\ìñÿÆRÆ7&ú‚*™¶ÎôO¹ÊQb6ÐRˆ ÛÏYRcàŠVy!Hœ6”,ÁÙL9zææ+ë¥BGUŽ ß5Ôn?Æ]ytªR8‚ž$×^p ¨¨RV™Ïí¯˜¥q\€rzQoÜv Ý­žàèªp¸»Ò’míêÕ mII1z| ´ÑÓWÓ~êT©uÕ$ÕYËy"î–¯·ÈñJfÀ‘2D«‹šÓ)BqBÇH*:«¨ë̇ˆ5 Çí9¡ÉùU=Í·ð´=µå§ÞXÅh{j:õÆÜ2Éö{—>Ô2N1͉Œ®\øÙ¤qOu/¯Òn‰§6wVæcô㆜ )¤•Ô(FƒR_U(C ûJjRIZŠMD y. Ô⮫cb±ÙøsÙ¹v†ç£†‹‚ÜbI¦Âc2sÐM:OAJè ¥¯q-†©СîÑÙ÷ Ø¥ûtŒpÔRú]´2WáÒMÕó¯N[ÆÊÊU´Ž€jx3FéËïžÉ–¯“Û›sqO^˜ì?o攬Ü5é _„EJS++(ž#÷bæNo‡o±åû ›í¢Ðøs­¸_ iüI$Ei|f’H(U[C–Ôu¨‘¥]¯dÛ¹m7ÜÓ2®é,5‚Þâé,<9ÜØE ,\!¤ò ªÄ"—Ç@׿ó¡éíÛI–øãñr³-ØMà’líáÙtTUTÔ8dËK[Žš›m¼¸ÚÊ’³ÐÉ÷26…©§ž5…<_r‡Û»åÖÁ+s> ŠæÁÈŒCžIe""ìñ¢Š)L¦‰n[ò݇‚ÛQ¶‘Á5-J–,äµ4éZÒbªÔ*G¦dÌm£|åkA–Ú»²¢9ÁŽJjœ}U ©,"ÐÍ%2†—… ®X­À<Õ›»­´zcj‚­Äê¦8Ѝjþ#@j+Ü ŽÎú t¡“N |,2j (4PPõ±Vã0nþ°ÛùšyoT«G_M0ûÈÈ–$¤3ËŠF˜ÙXjK;’>¬@»Â"F³^6U64Š$Ò¢‡P,ä €iàIà4„fªGâlœ…¡®¢Uƒ(ÑÀ¢»nL•0ã¤d¼ UI™P¿Œ))*ª¢¶ˆÝßK"’úì@ ª±jÇâÜ,rµ(Æ™$ ጅ`À’ºiª Jš8Ô¬”(ݵ?á¢¨í Š…ÒT:•NKE Ón|Q8ñJ+#G(•4:]^¢YЕSV7YP‚Í FË(ÕJœ‘AQF^ÐÀ öÐZ„ª•* T(8ó¨ÇGh4¤‡‹ƒ‡qa¤¥ªhuT$U0ÌDŠÆ‚!¦±Ö5šípŒ ªÞÎ@b e´Zþð·Ž™@I#È ‚µ IÀ­}J˜7R𡯤R¹9À§ƒkÓ›ZZ(*1³RÊ J^0•1“Éé:È@ \Û—Õêc)rþÖ‰ Ý´‘0“F°h HѦ•!Hò UÒ¿.½™\! ¦ŒqZÀR£ÌiòÀáŽÍÐlûUQU,µTñ]%¥:PÎÆ”·¹ÓÃBìîDf”òø†bž„Ó†µQEWEæO0|J~Tã@ípÚ 4†ê”RŠÈ!ƒ\òhWÄîÈ%‘)‹Ô©š²UŠOMÀ ª¥½MrÞwŽ=E+¬p$F)ð“EQÜj+PåÒ2Êà1Y›5Á#WŸâ§ @iøŠ‘‚rz#Q J.µ1»¬N«O#+=D³‚Ò#·î;54~FbÈ3µÇ´f0.–ª R•4¡ ­ä:(A¡(¡PCÜC*{H"Œ)@qQCÚpp +Ž–?&pÍ.Ý©œÆ­£’ª$,¾" ë]ÊÊ•Yø“@Ô4²ÜiR¦XÝ@~k€i'{´²’ ÅYrÊÝB_Å+1Æ jÇOÄF*B¶‘U£|D &ªh·{S´Yº Ræ&+èyBøâC«Æåч‰X~X ¯,Üǰ8kH‰P+žÔTšajXš’**j(iÓÛ´q–Žh„uVµ¦¢AšŽÝ&£â¥Ô*$õîIè³´åf12H“V%ÿÍmOoQ Aõfõ-b®{²ú¡äQ•8òÈ'M2Ë|…œ× µÍkâTœ ç<)Ç#®hXPÑ‚îlh«‹»ÉãÉRCK*+ªÎ y5Þ[4£Eô–6·(å Ì·mNñ«Q…AÍC.¥¥*(E.}1ÖÚËÄ äœþy©âMH«y€˜WÃ$Nd?q<ñ!LÌuǧÆËåvòLTX®¥Ôü‹)¼Ä¿ŒžlÁ‰`Ì2µ +ŠU©“QQV H ƒ‘ÓsF¬Š?1À°©”1E.ë!K•P¾¦ÿk"dÐõjf¥xÕ€ .T<êÄ#ON+ÌO4Ç8~Î.ºÆNÔuÉ,„Æ]âeˆYÑÕϬÇ)6f½Š³±[’¬nvâ{YV%Î4¶sN@Ã_‡HeÒCn42’£=¿nkLSÇ  3V¨™€N¶2̺UdŒHWÈö]€ –¹üFW‘••† U‰#iž Fœðò& Ð©Ãš©JŠüøPñâiäxŠdð (±õãð¬NV KxLŠ­¦Cvñ1¹,méf7éæ×ö¾€Ù™Ô1U©â?‡ìª×E••Ö7ZµNiCŽ šÐ5« dï J‰#YD’Œ9FÓBÄ©±$¹¹OePõ ¯ yPíÏU’E˜ÉbÇÓˆÀᎯ•kLt!àêÅU2!KUR:¼%µXa{[“¦@ ¹úû _Cá3²ÿfÝ5 }j¢:²çÑéø½ÜõMÛ{+~Ã7Š•k Lª8m:–—+ªÚñÉ y,?§°EÁ›hÜl7‹u¤Ö³)4óO<}•èÎÚå#¸,‚Œx|üúÚ¶°˜ÎÁØTÛ‡¦ªŸ)‹¦ÉÒO*˜xÊ“Ã[ü=äœ6÷–ÑÞÂú œ ÿL*gB—Z Sª[Ýx꼞xÉŠ ‰ØVÚ$êC¤ðAöŹh¦uÐ|6è­•QÈy8œŒŽÖÊ}ý`HŒ³D®pÖÐÜžÖÞí"–p Ðt¢0 PzcË™ñY®§"&Y×7[úÐ7§H?ì²xQ‘–QQS^š:JÕBSÈôºËïÙª°e Ÿ®™¬Äò,œ©ðÛ{‹7žI‚öçÄŽ$!ÍE1Õß¹H?ËU¾äÊ“ÛbVm>YÀ‚G¥Á$1?ÓÜÈ–FÇh6æQ€û3ÑhÕŸC¯bîÓœ‰ÓH}*nÖës}"ßãp}ïÜqo+„ÆiöÓ­IPŒ~]Qpd$Êfª—f¨‘@RÎ9ðoªÅAü{!ä«uµ²ˆ§mz Jéã0Z‚M?3Ða]ÚE Ç •m*G ýæÄ{[7ŒÒ9ó=<Ç$˜=0êm*Åy‘ÀÔ8p”rN ¦÷ÿz× W8§!U^2Ö/N/RÄ´†œ\)*· ’mqÁ½”qÉú{ˆ¹ÊO?¥z$ÜgH±´X'þ+«Êø›\}¨veHéµ¹^A€ÜX(?ì=ãîÌ suÔuâ£öt±„b‡—D¿ç.þ­Ó4QÉ­)RªBu‚ª× cre½Áüû—lk¸ï’KäWùšÿ*t«r˜¸ÑášõOtªÙ½Ö‘]LçX"äë&÷?K\U½ÎÄ‹-¨øè)þNŠíƒ!ˆ”!Ëqë|_‹û˜ïÿˆ÷bÔ=Ud½¶6æVk†”f6Ýlœ”M­á“¦ÿQ¨_ëï›þýí¦Ûž¯.Á"ëüÉ5ÿRpì¡v'Vž¢mb‡9¸©cf *É4^hülÓ 4¯hç…a”c~o¦ÿOpÕ›–@xR½%N4ê'fÐ4ôTUNÈÑCMER€ò‹.6¬Ë6–åžCAÿ‰ö䯆FàzÔ¦¸è°o–,!0ÔSE‘§Wòj¦ª¬ž—HøäRÓiÿi^ü©Ûˆ­äùzA5^!^4= ×¥¡ÊÈEjZ<Ýeœ“a«ÊRe#‡ð¬Óõ²ýmîD¶w3ª‰ã·A¡ÿzžˆô‚Äöœtåµj Åo½¬®ÔѬÝy p¬©ŽËç:·=å—Gä-ckÃñìÊâ“Cxc9)1k"\/ÛÔéèØxÀ73Ð¥Š¤þ÷xé%òÇ…Îbéä§{1µNçël ÐÇ@E¥§¡m6 ü½eÒe-PêçFÓ Ï®¯EsÛÒb¿E-_á›TÅ[šª ŽKoÉùÐZ*L¤’?ñϵü½|-ïãð°Cÿ&åêöÍ¥•O+ûEI¥aþL×´9z2 T†,Ê«}.uHW‚=Ïð³4K <@é`:•‡D˵ↇ±ñ/oË8Q©‰d¨©§®…~·¹ZŸöÞænR›ÅÙn“øt‘äGMq2´àþÀ$;R­ ®Ú®¦Óõ³€XTÓ×ËäzòŸÔè ùsâ«Ó^šìt‹<©Ñ3»4û”yvôM· §pùÒkº‰ÓË¢úéo‰+kÜ¡Qø7ÏÕw¥zj½rçІäϨýU€þ¿Ðû׫+Öþ}2ºÛÉkðTýOú³Çú{^º:Ø<1ÔˆÿÏMɵÉýGêÑßúý=²ÿ }ŸåêÜO^€r¿_ÔGÔÿªÿ_ߤ&‡ìÿ'U$‚:~ èf¹ý›r/kþ>ËëÜÏ­çë4kÏæÚÐX3[–úÿ¶™¾ÊÐù|ºØéÂeâ±oìK7µ×ü}¦Œö¿?!éÕÉÈ4é·u(þD×oóŽ9f?CÉ6ök´±+'åÖ¤5OϤe7ùÈþ¼0üŸÃ/æü[Ùœ‡µúb£Ë¡–…¨>®l«kI'å¤?Püý=“î'ôa"Ÿ°|º^>ÑyÎÅç1ÿk<‡þåMîC?ÚŸ,>GáPüGíé«Ù‡^ëÿÓ6=C½±¸}ÝŠ:üµxÈVcèվ΂8¿Šž N³y"B’F®tS‘sm_:\µº‹t…’g+#(mc­U"®Æª•9¡ %¶]˜®<& ‘B("¾ 3êH­GȾüžè¼&𤛳pÐdd¨Š¡‹¢¤rÉS·rð»"´ÐêžX%0ÀFÒé Ê/'¼¶¸’–×±èHšP8¦œ¤äÖ†´$Ý¥IÔ)¢d4Š‡Ò” †bkñüAJ€k€M%çvNÑÇPï|¼x¢véaÉ)Åíá+B7ŽÓæ…“2¢yÞw‹R½‡ˆ–¹bªE{}óxÆ®<:ê8XøV½º€ ¡cD&«•VPh8XW‡žÓ<|ÇLÛ+qlš=£ŸÆ=Nô||››jª—Çàã©YåÇïVi¼Y‰"–™£†BáÝHcÒ=LTöá.YÁŒÆ³4lÕÕAÅ( ž @ & Ñƒ04~U‰JùÓ+SÌPi®x­xZ½ ›WrPÔUnù!‹pmQ?—€Š¤HØÝØi£U‘K-1ÈÍv ,šut¦Ì« ¬Q UÙŠçí_•®AÆ7[†`!–'R }xÓU4¯• >€ D»vFËÚ{??ßn䥋snùa›ønµ¨|vÍ5 %³mTŠ‚- 39k  ¥¶+[Êõ­ÑÅ*š±,(HÓÁ³Újä×#Vèj°B4ÑpFœŒñ PqãEÇq´’øGñ7£>íïæ±üÍiwæÿë<Å'ñ×âÖݨ‡˜íGÝÌÝvͨÜu”yX$ÈÔï:W’¦¦Ž®–ž‹Fr2ÎWT)—¼—Èg/m¾·¸yH š()©´†¡ÒÍÀS]m¤t$ŽÚ$TšaªJ`SíÅ)“Júy“Ñr¬þz›?¸)(öwòzø1AÕ4ôxµƒhî “·7ñ®ÁÔã"’š ¾û«ÙÓUG˜›QJ²9§œCâeVfkÌ»4R¤pí{x¶BWO…¨„«QØjãÀÓb§køé*U1*±ÄGeþ^»3ù$5_»;xíÞ†¨øÇòÏ¥sùÍ翾-UgWû‰Ü¸Ê}~6·;ŽÅ¼õ8m߀Ãgë)+åZ%¢¬¥XUÒxj¼¬'Ù,9O˜EµÔV’v¹Œf7üBš‡xO„Ò¿OF ‹ Ó"µx>&žyÍNCg† %ü­êí½ñùœ|µéŒmcn`ö`vãÙ»{ŒÅ® ×=—²jû/ibq>L¨–j\ÉÞpRÓ+&¶zeI `9Ùï+-†ãz`"·ñ‰P ¨Ru()P¤`ÕˆÒr $tOy­ÅChI øk\P†à€ 2EI­Ô|ï-¹º0”TðdrhqæÃ%sH–v1F¬L™ lšøcÓPÈñËQXÈ-RÌ*Jä–ZQCÜM^šh*\„£T~#訠àj<óŽ­ÃlfñR$Nò¬ôr‰érÑÍêh*#ðe) Ri±õ/áÕ„XØÇìžòÖK›CQã‘ÛU$^ä&´í‘@£€®z_k*CPç·Ïxùq+P8×ü=igò¿§v_Çžáᄄ¬—xŠ¿Úûw%‰¨£ÅíçŠL&é¡ßY}¶qqÖf¡Š³$5R«¼Š’#GÒÈîVhå+»ÝÛj³½ˆÄ—2PnÝê­¥€1š@É:2½<> J¶0ç§Í¨@Õ]8>Tõ¡ª©qÜÞ½®ë:*JÚ­þôQç÷FsÇ ·<Òä1¸½ˆù w žZO M Æuêv2›'»UÖám»4±K ¹TŽºš•b€\pìþ€$-*Üm‡«Ä ºŽj+‚¿Ä4ù¶@© ·„=rûweÒ=vÿZh6e~>jl>ÙI.£±wüÎ+)¦Ü1h–:Ä”4jî‹Do«Z(ço“vŽKçÕo㉑xÉ@D1|-§IÀbx ‚¥HP̯pÕ©ùž5ãŠ3šñ©ÈÏJLÕ/\塨ÇMU½$¨;`ÉIöX]³ h:ólÔcW÷· ²×Í@ÏåˆÖ9Ñ”C¸Ÿs°š)¿F3õÐ|—õye@®¢2:£²HÀgU*xR´¨§ P* Ø ¾ÕÅí]ï‘¨ŽŸ)œ9Šßº6Dë$x´¤MՇܵ»£mVO<™A[ nF§¦fft‚4€ìÑ]Ù˜œÃpI¡£`2*ÐQ”k Ab5 AW**ÖÓ¬ÑjOÏ¡­|𩨯V}üŽÿ˜§òèø}Õ÷³¾`ì*¸»C5›«ß=ïêfìšýͱðûW¬ê\}?žþ˜Än\5mh¤¼1äÎL ¿Ù‚¹)É·û.ßcyg¸[Æ×È'H`ÊÕí%€¨âräj ¥M,¦ŽßIY$PrN2 œAV µ°&¾EvöçÇbr»G­·§jö^ÈÚPRUÓlνÝÛÊ\ï]mT§ˆ<>×jLa`ª&Š”‡!šâ,Þ÷Û-¦á¢Ú­c‚¬Æ‰¤*K{ÀôÕTRIª(šê[›©æ»˜´ŽÕbÙ¡t8ó§g((¡XtizgâŽÏëãf°ROY·7N<ÓUC Xú¨æÌmÊ¡ï=Â¥Y® É } i ;ÞjÜw¤Ô̈WCÔ·ut©¥M;p`5jµnŸÀD£Œ.¡SZ шÅ…Š£—É¥‰Ù½‰E“Çyé°}·°½‰^±Õæ±øº<µ1‰&“LÑäéTÈ‚çTŒ.F•8ïÍ-i¸ÞDar†BT€Ô‘H|AC}eUAÑðµ@$'W‰'‰ŒgÔj×VﮕˆBà–b¥»­ã^ùÀïï´Égš\†2qË4¢–WŠœÓ–’ÑáhæE°»¹ ’C\\-x<~€køI¯rê˱I¡,ÃŽš´/ÑÆ´pŽ¥I)¤‚X8$€î5Ñh÷ëÈjÕu¸™ð“ÒÕ5Š÷§‘+uÄV–C,ˆÎ&j†’‰] HNU„”b݃I© «i €êV `‘®\Ö˜'g?3L~b”Ï@Ö{¯çÅY*ÓUÕTË<¢71ÓëuÒþY™ ê€È:ß‚Q i¼òäÖ÷ aP]ÁrÌ릇H¢*Çõ˜:pBXÂ+JG¦8gסóÿ0 û Oµ³4Y”Wš90É (X¥SLm,“É ë%tɹ·¸Ç˜lã°»i$>$Æ*8¦W‰¡VÒ5*4RÔÊZ€ÆÕšTd?áùózàu_¿96m&ëøùØpc¡T¤ÔÕ™£‰¤ ¢Wx ‘–I fU¹6RB‚/“üAæ d‹"€ ÕðŠÐ…ÔV¤sROG»4²%ô@–b{MH \Ðý¢  R ÔÖƒ­-2âirÕ®Ij'5³ÄÒO¿”ªÏJë")«!W+`’'·:4f¢4M(HáZ–õ‘’+ÀVú]˜V•¨Ç¡âx)¦p@§ûvœTçhcš?'%š9ÓÈLlÈQ髪ãýI¾Ÿnô] WìâMrÊ)LÐàC‡P^‚›€aâ¹c¬AO2N¦ô:EMGá Á'dãeÁä"’US—´E H)ßÌ%ñ´Š·î‚ܪ·ï#®,j(¯ÂµZ®©Zè5í.#.\4wIñkJ 䌚¶„#އ®ß£þ+²f¨‘uºP¼Ó„CÃ/…™Yç[³Bɨ‹"»½õXÊãÃ’ÙXÒBjÐÑÐ’ @¡@($SF’Äf2“9d 4Ñ29òñ¦AÄ~›fÆî©3! Ò¤ƒšq«á×Zp+Õúê°Jó,Ï¢É2k¹Y¬eKJÌÚÌhÊš[ŽX'Ý-ŽUªk€;©CM!T“JšSɼúØàGŸM*ýÄv)}k¨º¨bŒJ‚¶»1©µQ À)ª*R˜¡ò~ž TT„†Ru#I­+éý‘®<ÖƒÈô¢ts D ɇL'Bk3S“*’Ë£ÔÁü‹duId­xÈÇ…0ß™ý•4õéD±Åe…u ûOÛr½ãª¦˜›%BÜFú°#”1° ÏÉ÷8E"h®ŸŸ——HÖ¯T«:סÃ4é%F€ ð¬UУvš”Z¦Q`L°ÿRÃØéX„NƒP~@ð?‘ëhÄB좌8³­Ÿ—uSö×D¦ÈÈU‰ó{&Cã‘‹O.UÕA1Ôí!ÿ›?‹cnwC6Ýs±\?øÍ›>qžçNè_·Ln¬ã2Ô=Ÿ&ºçí«êª ˆ’d’¢"Ö‘N£ôê£rÄ*êºGM\ H¬>::óq˜ÙK Æà $Ý$N4ÛðXoÐIÌÇ#ÏZW#¹|úsª24êq剉†²lOøhnV•§ªòšñè?§™ªéj(^R$ˆ3Ƥ¨Ø†Eü›ÇãÛVΡZÓÏåóy$$jiމßdm¦‹tRebt˜xÙÁ<ª‘þõí`-n¢h€£œúÅôžxÌm¨‹8ÎzåÙ#&Ô˜+]šsôÓ¥G<‚ ¿ÒÞéÍð´ÛSÈÀáø:I( 2qýTvj2µ“Ê­¢‰X·¨r 'êGÔÿ‡°Ýtb´·‰HÔTƒÅ"k…bµ×‡ú¸ôe&F…¿C•ÑÈWÔH:þÍÇüoؾÒ6DÊ+”–JPñê}å«HÍÕ¨uõƒjìL½[¹)ü1lUܳmCýoè}ã³¼–|Ö÷3F@?>ö¹4†Ö|ëÕqü€Þ—Èeªffa4Žªuܑɷ#Ž.yàÛÜïÈ{cÖ)ä̬j~ÓÒ«Ë‚ÊÌc®h3ÑaêŠ6ÊnV¨ ì 0eQôÕʼn*moröúí 6Ð)î=9iäÖäßÊÛ#>Oâ'÷i¥ydؽ±½qÆ9œ:&3xbq;£nLq-luG˜>‡Þ ýã,¢y¶Ëä5eiÿ¶Zçþ~¤M¾¯b¨Qåù:Y0âŠxPF³µIr„@¼åAc¨]ÓèM­oxÆ”ŠHžÖÇæ¯LÓ8Ö;xt¡Þ”"L=M<¬Ïá–­dÜ(JÊ*£L,ìÓãâ¸þŒµà T>9pŠ;U(ÜOÙÑUª [‹ÈjÓ3ÓÉA Ô¥J§o­ÿq±“FÄÜ\ûKkEÑz²˜ØW ‡¢sºñ‘²OÖõGY®·¨tËm‰°iÛ ¹çÔ/øö?²œÆÖ­«ÿ üëÑ$ªËÄt—–V—mQÔÒ7“!^ñ¡H‚°e’¿·{Œ †‹/GTªCrÁ‡±S¢Fú ¤?¥CýZ'ì ¿—^&‚#ó¯F²a“Înzš8m6èÁTî,Z¶hû‹jmþÅ¢(­Çñ\5Zp sõ'Ø:þ$E†&©DÔOè9Cûc×¥ ´†˜#áé=›‘'¥¬§$jŠšØå²‡ »0I‘¥U éofr¾³ùöÎÕÛu*Ÿ/ئƒöƒÓq½$ùŒ~ÜôR3Ð¥6ã®eñx“4$T*Óeã­§ ÇíøÑl9ï#6Öi-"¥Ohÿ'JœR£Ë¢)ÞmÙµªxEjjCs¦ÀSGöMþQ›ÿ­îjätc¶ß+V tŽBD yuÄŠUÈҀЀÓ̬} ¢õ9<[Æ×ñgƒÄïÐÓ¡éÀ¡N‚Îó- h~ÔÉO$ð»Fb'@Ö@b¿Qsùö.剮; `ô¡9¯¨é›ÁÚæEmš;(ôXkÿSoÔ,?Þý€|ñ®=~}&q”ÆÐ@-ô·6eµÿ±÷dÖK_/òõaž›Ǫ zx½¾Ÿ]dÿ·ö¬k¤X=o5ë’´~sÊXøÿ§ÐÆ9ÿoî¤9Aƒçþ¶k^¹Å¢ÜéáÏ×Oú£oö÷W×_>>«çÓâ1›è¿ŒXzo}íïsí‡yé¯ùz±­z—Šã˜ÿT|ú~š…ÿØ[ëí‡ñ(jþ¼:Qâ2¾+ê_¡_¦±§øöÞÓÃâfº¸_N¬ÞG¨”BØšb¾-K3Ó¢ö°"öæÄû3Ú|Aâ×Wóëo˜Ï­zBÄÈOõþÏâÖÿ‰öláèØ?ê¯I>†LSS¶40[Dd_GÔ‡½¯ùµ¯ìžôHm’šªÏ¥ëý˜¯@sþ/9ûYä?÷*_éϹÓÄ5­+åZñò¦fz©øÛÓO«úöÇþŽö«LÿïÄÿy?ô^ǧ_ÿÔv†O.k>zw\–¼²e%“Ã#.6Í(û/·“Ã.µ!dÿ]Vù‘cY­ë 2 5óÖsACóüC8î3 ž&x)ú‚„“QÜO¨¨È|üº=½¿±;³ Y³rÔKÍA£Ž©iü±ÏKP³+2ªF¸…ÒÜý/îWäf7qI¶kЫøI/@A¦X-*hMXԖࣰCa"ÜÚ¤D~¥â*BÑXyÕBŒPW#H «ó¿:o±rûú™v¥t¸,ÖUß/:#Ý{re€³”AÜËÉ'©t±ž´™Œ’„ZëSëB*+R 4èÕ«>¤’£,›Â1jÔ²:–Á ‚(G‘ꩯU—»°›wlmíÊaÙU¢š ѳª)©“wT‡šøíê~â:¦Äk… Š -›Qší§Çfm—²\4*òЪ8j¯uAŒÔÓ…š CR(”„4P–á#4?m+ò† !hÛ†ÞW#±3y ]¡V‹Oº6šMFÛ®}rKü+{}¼ÑÔ CÒÅ £ÆCy†:J(c‰£ðî¢F” Q½(€€;5âr*厪ÐVÊùÍ‘›Ô`5tžæ¬K7A/}Wa·Tãj©¶µLiüsu%,n*º¡K2aökTÔyN6˜=;BŒ=&5Ž÷`å”SÊLÖ[¼BY²¡ :G¨H t‚I*4„©¬aI§Õ£,’2éZW%Ž‘UáEÓJä€5T… ;|áú§?žŸò3øßÔy¼pOtÞÕê80´õ3œwZ|è=‡‘êlŽÜÞxº*I2mmÁ‚Èåa‚HéüŒÉÁW9USžió)ÛÚXÝ…¹H‘j‰بÔ;¢ æ„N…ž$]?.È zSGÒ‡†ª_$?–GÍ¿ˆµÕ'¹¾oÍÅ´±˜üE ö?Ver;ÿeJ(q”ô`M6ÔÂWÖãähiK±•C°Kú•höó™-+0‘êdj~•TêbôÖ€@,U©R4•"¸ÛηqˆÔ¡Î~^F˜¥Åâ;AÚÕ}GòkiößKTfösõmøöžj í].C˜¢ÍÇ]„“ ‡— •èëñÒƒ u T´’’†k•î7ýŠÕ.n¦(«šiÓ¤¨ÔWP+ÕVQtžÚP[4ÑÜiX´€qR3Sž4¥sZÓOË?æüÂúïççË^ßD³†€t…RäTÕ¢F BV¡Rºzn]ºY«éÄyÒ¾f•¯–sŒõ¬7È~ºì_‡›ê¯ãïÈþ£Èí-ý³³»‚¦§wu^'1ŽÈcvÈÆî­µŸƒÐn±¸¨a)K,ÿÂp;“»·~ëÜ »ƒªúŸl­nR¸à:xâ{¯|Á&顬¢¨§ÈÔQý®ÑÆRK‘¢©õù<ŒâPŠt0÷}›Û»ÆX¢¹ÜÕ`Ž0§N–s’E4!EZš³Ü~-*Ýn;p†Q¨è'È@ÉOÃä M2ª],4”Ó`v<µ9ãWK³è^l´T53ì n;6^½¡†—k;¼ò¹À¥YJ“ o<½q.ਗpäéˆEPo6$‚(Ò*¡œ2Ôj`äAcxÜ;kbA©* 55î µ¯rŠÐlMñ×ù5÷Ïye2ÙNôí®¹êLm.*:JݹÕ[ƒnvîí=nVm·U[]AUýÜÄÇ 5ZÔÒKb±³h”™#bömŽoïãî6€®iÚTápTgQíª@š/7L<-+…¡Îj|Á¥ §®<«¯¤þ|…ùyÐ=[Ü¿ ·ÎÆøWÑ;%w&µ{Þ¥öÖ_zlíÄ(òT3ì}³YS¨©¥)U¢žºJxæý×PÎo(Vfì·Û‘¹î‘ZíÍ-XêÆj< Áu…”’(r–Z™I¨$“½ef­{Fh@?Š”90$5A§V]ñƒùcu&íØÛ™~ÿ2=•òrã©’¿#ˆ—·dÅÐT—àT¶ÛËä3ØÜtµ´òF¦ziSÖº¿W©kýßùSq±¸‡gßA½U£ŠÉR4·fYkܽ²¡‹ _KÉiè44«§Š€SØÁkšÔ“^‚þ ßÛ»evþôéžÜÂ>Úì}­Y‘Û»Ÿ,ÞfL…HUé² ƒ'Éãëb¨§©Fsк0ó\a¸œ‘uÊ›µÖÍtºY\®*ä Ð…- +êÈè¥7°¾• x©áåB(´x\·N—Ò×vÏwöv;¦ºoϺ7ôr®G)U-L8­µ·áª§¢¬Ý9ì§î¦;™5bmæžy@³¼†Âßl}¹ÜyÆòÎ+[_…ªõXT55Ñô†OÀUZ¥4WOO¸Eg ¡‘”ƒBj¬Â(V”`*Ù†’F’©ìZOß·ûõßÈæ˜ã¢Z¹ö·Uu¥VïÇí™*)K4;‡/#ÕÔÐ=:Q±h§ehc}SD+•ÞÕrŽÁp!½ßÜ_Š¢%µS†cÁ¢¶­ZKj3/Aù¯å™Y&ÔèÆV9PQ´©e% PµÇf£eIÖê6ÞÔí.›ùÔ]›ñ£=Êç7{Í_Þ¢Ù[S ­©Èn ÇA,ÕG#- ©4qÈ’Å+!úÈö|£ ²Á{iz%³oµ=¬]®”F¢ •¢ž‘4…«§µù W¸“œ“šd€ÇC¶¸°;yuž+cü‰Û}÷Œß”59 ŽÚþY.hÞUEDø‰ò‘G[Ï0§iü b¦8 .'Žæ+g¶ŽÞüOª¦¢œkZ`+CNƒCJÒ´óêÃŽV<¥%wéRFYˆ` ”i\¸»$A.A:­qõú{‹¹ºúÖ[÷ÌD¨ƒ€h¤Ô(ð×Mv¨ma–@ ©e6ë Ô\q¥8g'óü¸yŽ$_´(1¹ 5F·–ª((Xj•|&(€2ÉŒÝC¨ñºÀ¸1›d ¬ Kƒ§ (€XpZÕ qÛ¥M­ÒDaÄgü½Ï@›£cïÍ¡%]=T鎫j8dsLî ËÊÌVhк”[u1•k~–™c¹ŽúÐL¾&\gƒRµòÈ$Ñ@ZšÀ†hîÀ!ué$ dŒzÄbº… ‚H®“½‘³êöîõÝ»§Žƒrd¡fbT¨ûº­1K uUEéäoJ,ÁD‰ªÇØhîÆÕƒÍÕ\TŠ©*hÊH?· PIèWs8Ùš¸8¥ *ÈHÈÝ’Eé‡icêÆz”¬aV0ÊÒ“ˆ´¢Xã!ñþͤ<5Ϥ,ª™U¡Ó†ŽÔ™-ÝšîÂÔšT‚•R¿ð•T¦¦¥¡M= / ¥¨8T=Ùh%¦£¡žO3yã7i©¦Œ«¡!Yghc§¨ÂC†ŒþH*,.ê2½‘U8άCBI8$©&‡xô$j¥rsO—ú©üºå‘s{.x$IE‚sb-mâ…Ô(Hã_Û.,—ü ý¹_£ºŽBM*+Àbi\ꪻÔ1¨§žJ̵Öî@ t’)Z_ÀÔ$Pµ:¤_‘¸vÇîÙ¼qéŠY5£É¯D¯QžIá2FòS7¯ô¨kp¿A'Ï[¨£$•w9ÒüøÀ¦šÕr ÓUûŒµŠ2k@ÃE5- Ô©5¯ Q…X’¨Ìáµ@Á$Œ¹`=¦B±ãH$€¬X^ê?Ú¤ƒKné-<2@ó©5Áõ#‰Æ¬Ô¬µ,DAZRœ(h*H­BùTíô>n&žŠ ¡þK<-C[O&‰<”ò*Å%cVVÖ¦àê­@߹ζï«sC§Ä¯@®IaR(qÁ…I輄†Yc~uSÓÂ+ò­O ôï¹ýÝÝÙ¼D‘Ê!Jù ¤27‘æhee„1V±!+ ê YZ/r–Ér÷ûtrÆË¨Fu¢Ð>,ã48[M_¥ ‡UH¢Ôf†‚¿e~|8ÐÐt˜>ᨒ¥‹¤2%3p *J”Eš"<¤2ƒ¢ìÀZ4ke:„~)AÇ??ž8Ç*ÖƒQé&° TWˆÅs¤~@ŸN˜ò`ÓM U×?µ3¯§îí†[©wpÁAP rç­,©ª]z›OËâ`Õ,r½Á޲t‚P¨.šÊR -E<=HáLSÌð©prÂK‰=%Khjs¶"H<šË®2åtëS5nÐÊËèä8Ï–j1ÛP3ZÀ‘’ zoã9,+^hAÄ`Ö¢µÉ<Ô5h•ƒ)ðƒ2”%'!d'\… Á·ôôûî!Ôκ… cð¦’|ÎH>dž‹e:T¶’Ôò~GíÁ¯JºzØg+ó-:NC‘¡¦Wt‘UN<6 p=Wú‹¹³•ä`xŠú|ÉǦxS‡’¥BàÓeæ8dú’kÒƒ$&éÕô½3šêb,`”,iõÔïþ6ȯQ¨ŒEAM~]jDÔ¥)þ¯åÐÁ‡Ë…£¢Ë/‘Tœ^忆Ëgüé©¥½ÏÒãØ"òЬí »‡ú¾G§@ #ü\:²ååÝ”Ý_ß8x*kc§Û¹æL6Mdcã\fpëÇU›ú](kŽ‚OÒþËö»³ËüÍ´nW=¶sI¢_á_´ã£¦á¡»6îHŒ¶ îÝM¸°SV@«+ªQÖÌ ²ëŽE6±Wýosº¬se¤T‘áüº”W£ËªeÞ´3lÍÐjLtóT±!¯a(q­l,-«Ÿw‚‘KB´ŒŠSËþ/¢Ê¨,Ió ègÛùhrTBïä2Â$O¨7 žnÛ{~[bSº€õ¦z‡aJçÒ7#á2¡•bYT“ýlÈAãIû( $u)LôÐf=íÐI»²8üDD µõ-•¯qaÇ¡¸#ÚÉhád Ÿ^–f(<3ù— ã{cÖlT vC(#›­ÅƒÀüûcšîD{;G4¼c<8pé,µ1?ÙÕlöø=Bw@­,ÎMÀ¾›ßúqoëù÷ òí轺‚5|/AøÃ(4Ïø:*5¥^pà0¿®à’àj'è¿æAÑCöt®ºÄž!§ùz“‰Þff6 AתÿÔßèHÔ9Ú¼p© qé%Þ¨íõ+Pyzþ}-… J¥¹e*³pu©?ì@·úþãNaŒ¼T# ó—^æ5'£iüvHö¡¢2˜ã{3kÝ!õZ܃Àþ£Ü4lnþ6Š‘ÒÛt–ºÿË¢Ûy+Ï&©¢«Œ¡R ÇA‘2š.Ôyw'ú?ÚXʤ¦†¢¿áè­c¡‘OË¢›¿"Xò±Ì®Lµ)”©Œ`ÒF¸œ²Å2Ÿ÷ZÏ=A°þÒߨÆÍõZT¯ÂÀò5ü¨:/—KHËž}ØV‚6È’þ(é3[?,I¹`¥ÜY­”ÒMÂá;Šœè Oc6a-¬`š–‰×çR‚Eý…¤Ñ ïƒ×¡«mÖMˆ^¸ÉHW¢ÃÒmºÿíé“aÓÉ X #VÚÜhõú{î’[ð¼‚AöK¯Ù­(>Þ•±`‘´`z•–§ûH*)¤ÔÄPMW©IÕSµ·áê€b¶IV‚G-ø²ŸÇ²;"ßP¤¨’8úŠðtÌʃÃ.3_ø¾Š¿eÓœ~áªfR5BѾ¹…éápºTX¶üûÈW¸7TO¨ÓN#Ô|úTÅ[‡ˆoÉÍM¹Wl‚š£%MÌn= [QQ«Há’®ãÜùíÛj[Ø™²G¨ùtŠãâGóé†9VJŒ=HzÖ’R}n˜é¶RµÇ•ÿRßâ~„_óídjJGèùun4ôë`%¬N¥ˆŸKYTsÇ»í+ŒWÌ|úÙø¸õ"Y¸vþË«è=³*Ô®GQéÖ›òééx~Ä#ûkè›ZÞвþ¯M^£×­ùõ27ÇÖ=Qón>ާƒ§Úv<81è~}mG§TH Flÿ­?Ýn?¶¦÷(?Û{b$ÒÎ ˜ôûz³AÔ]ÂáðñØ?¦väÇ Æ%@'fJ•3Eqæ:Óe ú6À±úÁú’>‚ÞÎISë1óé9áÐÇ€™[x“üÜCÓ¦ÅL×ú!·×ëùöMx„ÚQñ1Òøóôfÿâó—ÿµžCÿr¥÷ Ö’Ô ÷—ªŸˆý½4zÕÉçþ+íÊÚÿÊGýT?ô[îôþ]ÿÕuÙ{¢–¯saá£ÁíÊXäÉâaCEG'Ý–5ô’»EVõÄBÌÂG(bô·¬¨Wùݹ‰‘áÿM$ ê$– Šê¥(*H-‰h–ñ­ (xhăÀµ®)Ðå֛ݱ[Šš²57Ž%!4ôNR5MJ$ÓG['¹[9±ý§$j6 G´_I·îpLRšªùUH´Z_<`©ÈS·N"¹’FÀ­ȯæ4†¡Ztt÷þÚÝgÉÑãq•Ù±,g…*§ÝPºù:Úužûq ÓõÒŒK0òZËsŠúÖÎöÒVÒªIjiZŠ Ý#8 €¤T‘$ð °*ÚŠ•ÕœšÓ'©¦¡¨SŠŽ©s´píK·7M$Ûck}Íná“íM4?Ã÷Xg}ìNõ4Tñ‘ ³j^G,Ž›ÁxÐË‚J¡Z ŠŒktÖŠ © Q^ŠuöQÒ«@®óó„š­Xy5Z½Ę̂Ám¼íl{_dS»6œ-xwûDj¼f÷7ªC’»ÍB#R6Xä”s¨c»yÄñ,’0bŒsòÒh(£´àæµ ƒP(籕#£Tcø«ZÖº†ªb„ä’F¢;Ó{ÐÇ׸†ŸnìÑ nèÝð´C1¥¡ÇlyL”q}ùqQ)È0r]êĖ}G›M½Á¾}ɤ*‘Ưè;¸-|À$·‘WU–Šín«6iÇú W=µiò%iÀ…Ýwò§åßÀÉÛýñ—xî‡Ý·hËmêý¯‘¦Ú[çoÁºw5&*|æÃÝ0I‹Í` ‘éjþÝ¥ÕåðT"NKòží¼ìbAw$êÚ”Š‘Ü¥× «÷Ô€A¨ÕP [ˆ4–í8ãŠ×4¥Ióô$®¶ è?øV—mlá;æÅœ.ú†,V ¢¿ô~|m̵Beq˜ì„™z핺üظ`Š †£-n§Uº¨é”¶p–åP\ha©”š:•ÙOìÛ袸Á ép¼A–0qå“û¨¯iÀñêÏ6‡| ÏçWš¦ëLÖÚØ¸ou•’Å€Û›ÓkŽ’ï¨÷*Ô ëöfvˆRʲTuh¢"zÉ%òJi`}Ó–Šz劕êõCMMK BX„’ˆù›s”n7p\Í8Ç`TåššŽöŠ‚AÝËÈ®KN£åJ€5?ˆWUOØÛomuößÄoÍLÏÛÕ›Cvõí6ðÝ»)·639¦‡).Ѓ(øž³^î&’@¨OȨæ+NlŽ;I­å‘ªmĘÓR¡MOñ,‚ŒB†4ZeòMõ‘cTT´õÒ* @ãBzÛ{þ«´iö–ù†ÅE<ÒÐÌ¿"Æ¥KW¿‡@~JÖQÊFzªÓ©“Ó(Á,=JÀLœ‹v÷I¸øˆC[¶„uàx‚ jLd®…Õ;t1\$5µUkƒªøÇ¶æŠ²¢®Y"ªÀd~NÓÃhë$ž¦ø‰©c¨8P(Ê&ÿk¯Åý…ü£â&3JðX€T’F5(é[$I#²f&ê5ã^ˆò R¥««ªqߘNðþc£¾wgÈ ï_ØyÊ\Nö¬ëí²• ÍÙ“l]NÝÁlmŸC0ÄáhM*1¦M"Ew™õXCÞásuÅ´÷-râî&Ô@í ”*Çéိ¡5QÞOi'ÐÆIgjŒƒZS‚UÀ©F4 N*MÔŽš’5&C§šÿÅ9¶=d˜Jªìm»hhšh¨³ûc)Ö£*ج¬Ÿ\¹Œ}-l+! ºHYAeo{ö“šo7nbµI§¶¶R ?…U_Ä(¸m%±¢ª8ÊHR%CWám%Hî¡‚ºž¤äš zþiYiößóGß•xÃÕª25“R •å6oÙË,“6‘ËK†@-¡ÖÓì?÷…±‚ngVh×KÃ¼ï´ «§Q4*EF–áô:Û…j¡|Íx#JØ·òWËàóXï™5˜hdîA¸6sD¹oTŵªv¦b]Že+4Í£u.Q¥Ž ¨Ʋ-({ß-niaáýwˆ ¢Ó·N”òMhô¥x .n!x‹§MäiÇÌÓN£’NX’kÖº=±öþíÃï,§qO<}YžÜͽÛ=Pë©Þ3åj[qŸjjÞz‡ÌO¸¢˜ÔÌíågYŠ.€"dæ.`¶Ýü%Òds©XÐ3U‰W¢Õ“¬äÕ”iexº~;[@VJŠ&„૬pÐ*-STÖÁÉ ‡ãçÌì6õ‚š£ãdÛÚXcƒth“iÔGQ±²¸x*Z¦†,$»y±_zª^ýÇk³?¼•öòw¼Øo¦»EúGbh3 a{Ÿ´ 54%•é©QP¥¦8ñÿ'ú¼üú*_ËW«öŽÕÚpn¼D’’£"b zˆà5c¶yáj¿µfI%xB$Ï'”½@w¸µ½Ç›öÿŶÇá!«5­qÔƒ€ QZ1Y5ÄÂ@#%]5+…6¶sHcuˆ²œg {¸W Pé"§Rà‡ZÞ¦ÊÞ°VV¦‘‚«r"+}~ãRÆÒ<ÄÔYÙ‰ D·üÑ%ÜæþK¶ñ…Xq*µEŽš¤%ChDBÒ1v!5»1™oôôÈ"‡Ëˆ­rµS8§­Ï[~6qF[É¢GûRâ úb.ЦGvUÚ&* ïêaè&?Ý÷h.ÑÖVTÖ5&@§Ä¤Ä£ƒÀk$õ8© 6³LV¾tOåùyž‰\±ÓïcL ÇZŠz9X»:´ÒA @©8ƒS´î쌈@~€aHn “p‚pjBäUJŠŠÅ8Ö¬¦˜Vjš·sø…\zzÕP¹¨nµù·´§Øß';7Ãíš§-S—F2yH릜ǥ¦!Z c©ü*oPcìOËþ41I‹¦HäeÍ1PIò –öÜ>4SY -H¸ÁáÁ5P‚ ;Z‘BA¾§5Y-Ï»$Þ ‰kOwyUüj±¢~ðsØ·äYޝfwUIš¥œê” hËÀ¸4=´N€Ü+¸ŽJœð:M¡Žæ¨`À- Jd®œµ„ç1qC¶Ô¥< öP”…¡o¦‰ ’µY _”EQ¾ \ù ˆ×"ßÚÕ 5ŠÈ@˨à¢à5AãPk€AG£1‡N®òÇWÑ›gW­DuÔ,ªRRÅØĬ^Áõ2ÓÄí#ăÖ»i'…onCOH+«R>t”,|ˆ!hx #U$tÓ*)Œ)ü#émrH‚÷Ãb c`†ÓƒLäxJC•‹¹¨òàó"€‚)šŽ#—ÈL+T&ÙÞÑ!a‘§ŽŠºí¡¬¤Ž8uha#HÒ, sq`‰öSíÆà—P5› ¸hµÔt"PX5F@8Í*× Ò*ÊÊTŠç‡~0ÛÇ¢ß"®yžI@X‰Ù“ÊawŠ7y5:¤b&%Ž¡dµÍÁ2T’GjÊ!‹QV#:H Pj¢öœä ²š€jÕîšÙb’ØDèUœºÁ–G5È>•_¯,/ôãÚø ™”´ÝÄ\ A£dЂI>a™H‚¯N 8d?¨ QOæ—Ìu ,2+à’5 剗J‚¬%Š(Xú@ÖF›F¢÷¸ˆ”}F¦•oˆ ùÔ5*ÙÇÊÕw«²Ñ(´ÔŽ4òÊÔÓ†2kƒD/BE4±­MÙ”­rFcpZ Öb²9$º ° êeô‚}Ç;¬,°ñ('ò`@Çʧ#ãJ”R( ‚1ÔÄYiç…Ã5„»9 ¨¶»1bÆÑ¿ûqì31 ³ŠÈß3J 5é–A5§íýŸ!ÀûJšZ²©†HØ4p:݇%éª=,Mÿ²—æÿëû"š/)"n'‡ÛÓd‹S6O— t+ìÙ„•uX·˜xª¡adÞõÞXMÅՄѶöÞ#ý$¸÷©É§—V Y¥¶gíâÙž„m«™“oæ)kUž6ÃÈ´ur ÿÉIªšBÂĵpR±R=nvŸ¼vÙ  ýeª’8H™¨ù‘ÓÞ!VŠT°€~}mÉñ·)»ã¡6õm\±Ï™ÁQ&ÜÏÁßî¨cE;©:µO«sõ¿¹’÷¹lÖѾ¯¨ƒ±™§~ß.†×"âç´?æè¢|¦ë7¤ª®zxHI*` ?¸Ù@·Õ‡ûbÆ “;§ÏÈô–tUsÀŽŠ&ÆÜ“Òj •­-,‚Ê[ž ­kÜ©éý}«Ð=ª ü±ÒQáê94þ]Û¾X28©+"{0õ}I,¿Öàý=£ž7Ur=:±—·HAOŸUÕº·ëâ÷Jcd™9%ý²$#P×ëV¥M¹öVfT0‰5?gI„½æª?.ŒÆ6ó»qg[5é¸`.J˜ÅÁª/—˧zûx+~ã7­xÞÄ߀x>ÐÜ1•É#î F¿˜òè_Ùiãõ(K\kÆ÷ú}‚·ÑTbD’T¬Œã)_òt>WÖÉ1ÔÈVЋ-îUìF« Ûƒ{{ŽmíÃÝ =X˜ÄBI ƒ¢MØy—x‡¤(-oKý³ýGûsß.CàYë#˥ʡ¤Ô=:96ù‚Ž’O†˜Äúˆ»¦åmô³_ñõ·² Öài¼œŠ¨ž‡£Ëfpj‡?çêø>nJ½ß[G§M>ÿÂn½7•¼õØ)òx™’É•ÄBT©?×ÞoÒϸî\Ãa:âkwUùwV¿Ê¶¹Yo´=40ǧVkÛxôªÄER%»F‹TÖÂ4”ÄÜXŸ[sþÞ.3ª‰$~ʃû:YwÚ£#Pðy(rÛcP!w­ª¦ q ä衆ëõ³=UTúT~GøûT‡]ªS'Ë­xšÕHŸ@vì…W;LXUI=ÐCq[[`î¿HÿˆQG¯òëïl¨ ÿ?—I$¢»=2z)}“O=\‰ !ž)qÕ(Ζýª©2Xšèn~‚Ùj{~ Ÿ¨ö'Ú$*X“¨<òŠîꢵè¹ÑžÍaÌR­NGnîŠvúRµ0ô¹êPäšý¢ö·7cìolá¶™ª’!¯È1B?Þ$Ïˤ1—¤Š¤x™Áá^…|UD¹] ÑS;5T{Ç4U‡‡±6%ç€[é7€” ý]½–ÝE£H⿜iý¥[ùt¶ MZw|¿ÉЃYö™šÕŽ Iy\¶^’yt’Z›|`㯥Žöâ:éN‹q}_ŸaHÉK_#ú8üºfç¾55­ :/½­CüJ ¥],zc©Ædño4Q8W&–iÀ&¢ËQ‘°ŸOô÷/ò Á0\Û;ŽÖ>cø¾Þ•éQ¸oÂ:®Ï‘Q­nÔÃÕ„¸¯ŒÈÞ)I—O¨‹¨%Œ”äýyçÞGûzþì˨T§¨õ>‘\28Ôôà««ƒ¨"FñSPÄHŽCoÇÆ¨RX$qrM‡ÖÞÇ“ÄD÷ Q^ï1ü-Õѵi='û’Hj¶õ=B¬âHk^ªJ¸W¦MšXVæÿþ¿Ð{1åÄe»`YhWø”ùCÕ.Ecè¡ÌÁ™…œY_û{‡é§Ÿ§¹>5!G ’<ÇÏçÒ:=Di•7nèööŸðöèCÝZqcçóëÔÆ:‹1i8oTic¥Áú7?KØûP€ˆÔTa˜ùu`0:ˆÞ#cô^tµøÓÇÓÛÅj_‡í>­þ¥@àE›õ±ý þ­áO¶%SD"• óQºz…ÔÓf¿Ûú×Ûë¦ÖÿhdCãŠkõ\qêZº‹pö×û®OÄŠ~º~¤}=§ÑƤp>cÐüúÐéÊ¢D1FB¸´‘ýcmª[ñþÇÚXQƒ½Hà|ǧÛӇˬYÇVÂ2ÙøšüÅ 0H>¥@½ÿ_köµ"Ir8zQóëgàaòè7B<Šyý-ý–þ«ø·³Ò Fœ}GϤ‡}-„þ’ôç?âó—ü¹<‡?õU/±ñ ’Ôãéž9Ç^?ûzi¹ÿRäßø¯µ^#ÿÊ;þÕÿ ºõ>}ÿÖLu¾îݵ{Ÿ ÒWêÉááRà„fYAŒ'Z9(ä»´„H· p.úÂdO6c¢ÇQ. wf†¢ª$¢5 J|”ôñn&ð£utR<ÓHÒ“ð©**¤•TÂH÷³³;¶¢YDɽ)Äæd‰äÃLåLmzÑJ ÐÅ š€¬=jÒj¬ûŽg‚q)ý3âil  ÆM´OÂ(I¯Wg”X0`Šè>ZA4ÅI9=[ë)4Uø\òVÚJSÅ-D:£–®–0!t‰K,¬ì̶uà–_Ø÷Ûíöw¸ýݸÈåIª“EOi¡ áN A!á€!ÚîÖ{w…Y‚ùŠ‚A­­x®ªåŽIUÒüžØìe>V¿÷SÃS_Œš•àÇSU²QÉI—žAáJeòÉ$'êÅ…Ô¦Ö–¬_Hh¦zk¥…R¨‚@?íp–>º‰ÕéPjäW¸ã5Î0¦«(RGT+Qûö“°©°[®¢Î ©s›y(Ù6ü>V±{ŽJ¸Ò”b€0Ã5<&YþÞ¥ý°£fœÊöîíµo*¥8Š‘Jp$æ•,J¦ÖXуPäÐ5i«ÈzR•Å Gˆ¿tä;:.»¥Š²-Ä*ãÏnªz´›n´ ´Qâ¶©ÆÊêq0Ùå– +€¥›U¯k™o’þ‘÷d2xDöþ 3RXü\œZ¾~Z‰e@ )¨9Ç€O­¨øNV£e¿æð˳¿™ò®ø!óßãÖ#%ŸùÔÿ:ëÙ‰ ¥›7Ù»?„ ¡ß4jP¼Û“®÷ÝZ¿HèÏWGYYCP`C™|ËËvüÏË»]üp‰%ŽØ)|Ji¦„ц4ùŽ'÷0 »zស–@­21çœúqëTwÖçÌä#£0f£û|6Ú£¯Ç¾Ü"º‹5ÜÄÁ—‚¶š»¹L¥>X̳Âúd‚Ve*„÷Œ{žË&Þ÷ ¨ÖGpp²6•ÃäP¼@Í èŽTxdÕ¥‰Ò"ª~UàGjŠ =$·žÜßÕýù¶°CE»*7î_·¨1½eË – Ã6åmÕíÏîÅF>˜UŠèêjià ‰:›,6äK»Ë›X¡q¨¨ Ô±8 ŒšŒ £*(¦ØJn%'8¨ ‘\äU1äkN¶ôÿ…3öµ}I| øó¹ò™ï’&‹tv·c6ÕCŽ£Áu nËËedXi¤J|~îìl»¶>5ˆµAÅJ¡UTƒ.{¡=ºì»U¥üŠnÃÄÍ‘‚Yç·G¡À¢“Ä/ øI¨~¡&žUÁãóÀ>~CÈ‹ÿÂXª÷$ÿÌ×¹!ÎC–†8þöi„dq‰ŒŸôûñµPǦ†‰¼ÌºË!TÓÇû.ö¥,îçè^"‚Üü «‹DMN£QÀƒ\’OŸI¶Ì0ø+<êIÇÏççÐKòOxvÅßçó›½1™|$;—·ó}—´Ú\LñÁ˜Û‡º0;›nfð’´&­$ØLÌ‘»¬u4õA¼oGKï^Å3nSIá€^åË`êefy”'ò45:E Zjø«¤¯(Nx)$Ð`Te€Z€ n¬±7½GËʾ½è¨Ïo.ÑËãvµ5!«Z*\ÌŸe™ÍdéâF’ ·qÉ=\òŠ*q¬útÜíß)Ý_oV6ÖÑ E•‰ZÕT2—&NÞ%Ž– [ËQ2^ÝP ¥È'ЊЌ’H® ®:2ð§¾ãÅí~Žø“ðÃdVTÍ»7`GÚY XKe²8ž¾êý•¸¶&ÙMÁåYmM¼w6ï" ¥VóË…¨6"7÷—þáÜAÑØB1¦¢ÂÑB²ƒÄyka†2C+&ÒÔ&œúRŸŠ€¤Ð7CŸ.©£ù%„?ͳàÎ+*&¦©££ùVÔ“PÓÆ«;ü|ù#OG2УÀç"¶…dSCvìöÀ¿;+)GàE*Ñ䨡eÓƒAUX…¥I€‘‰TùÄŒ 8vžÒuj¢gþQ¹eþl&)ð ^Ùl6Òøý–Çš,tï6$tþÒ’¹Š´†Ž®7k€"±-¬˜sð…7É®®éG"ŠÔŠ*p¡Tã¨êehOM]%FqÇâ©Í)’O¥i\R·±÷èÝR÷Uç“)E‚ªÊÓo͹_Û±d)¢£ÚÛÄÔÊ ’Z/òšz¼OŽgû†‘R5sªíx Ù[¤05¨ê¼3U @Âbǹªé ¤1,´®z߯ šñ ã^>TW×ëc_øJ6í—zb~lå23M>~“ñs˜zŠJŠI¦8ŠŸ’Tô5•"®åšzÊWÕ¬ƒx‚U`AÊnS·¿P EH´€Ú¨qJ×( à‘CѽYHýM|¨+§ˆÍAÉŒ~Ú0éýÝ $Ù=ÙO˜¨ÓQ¾ó»s-EY ii ÞYƒ««H«é ©_±È¥4¬íª=Eœ)7¾ÈYÏm¿íÞ!Êš+P¬µ¨¡&ªiZšà„7¸)Û «¨£TiP§Ä’XãJ±m,úº<ŸÎ/3Eˆþe[êªZ‘uŸT‰”<²‰6ü®ˆdtq’?& ÚD‹¤r.ûÂZ]Üoÿâý®`KQˆ¨¤@iÛ\šjÊ•¨*öÿì H v!jTÔé'U1¤4òl°'¥'À>¨î-Ž;?ù©í ¯fÔõ—Fí­ÑˆnŒé½I¹7÷ÊWÄÒPÍØ2àê˜Óâv®7#ö2ÉW3VC=ËM4î’ }—åíÏlÙ˜ši<5HuxšZ¬±Ê–bC•§$T ·!b‘ŸI'ðŠÚ#â$ ÑGDײ›Wòàîíõ”ß?)?—Ç}õ/te+&«ÜÔ½qØGaà;7æh%›sâ²T›~²|ìPGKdÒÀÒM!rK —nG–7©†åºì!ïbj“ Å—RCØ,ăD5pÉ#¹š=J§ãõçäÄv“_Šªf Ùïæ‘—ùYÖ¸_Œ:Ÿñ#âú}ÍOkm¼õ>Sznê*ªŠ™j°»—;ŒŒÑRãkæ\€€Îù¨‘gšdBŽæÏqÛn;vÕk:ˆ!X†Ò8ë¡F@ÀЇV4Ш[9@ÊBàŒaª+ŠŠ5<øŠÐ ƒ^ŽÃÞ8.¯Ø¸µ†®üIï:ý»4QX"ÕOÉIBÈbW" Òê$•e÷‹ÜËÍ7›ŒÄ9d”±f •bX%5ÑP”u$BÑ#”ÖÉá¬C«i£Y>™H=Ú©PFARº»ÃGBk¥‰ÒKØÆmõ&~в ÕkUU”4îî3ù%‘á•¢ˆ«»ëDöRu.– ƒsgŽõd•¨i-R*2 SRƒBÕ=¡In›Ý#6ÑF5Ô¸¢Š.¬T… $­k_Z–èÉVgê$¤”‚RdIcÆ© #+¨w‘R«È¡=l]e½Ø˜‹Ï$"4‰!@T¨I ¹¨×­HQ ÃÃmd†¬ïS@@ÅH qÕëÅjFIÔ»²‚<Þ9²øù gvæUfH¡ñG+…y$u¨¦5Eˆ@tñÌB­þ»ú±$k7ˆå­P¤€IbØbº¸‚G *µ0é|w @)LãQ 4óÁ-¤€§Q,@=k9üÙ¶œøÞçÀïCÅèÀý½Af4´õ<(Ž"yd!]ÉIú’}È{òÉ-БJø¨²R„P–`Àñ‚€jIT)‚Îð-˜Œ•3§â\áT*ºR…*Z¡C$Œ@zOÈw\xõeyý·6õé õ%>™«qQîz¨“‰|Uêš50S1}@Xgaï9?z]«›…›ÉH™Î1R(¸Ò¾€žåâiǧ~š†]-¤þþ9¥<Ë`Šú¼‹4Ô¨²Cî£Ö‚6ÀfBÒE*Ä‚4¿ ¨kå$äKЦ¬ÚÍ(xÔ“Ük¬wV%…E{tî›ê1žñ].`­¤é&&‘Dºɤ~¯QÓ{ò=¹l’˜ŸÄ‘qÇ£@àHŒð&¸*äjÄ3i¨~UôÉ ?gqë%æ&;} ^$RÀH$Ñ£Z€§R²€D\p ± ‘б¨"º– T vŠRš«E=˜Õ •~ U%¢8"})ZÓˆÊÔ÷`AT®Ð)‰´OŒLt"™µk‘IéÐÃRÌž ¢7$ú‰Ô¡­ÊÔTÅ®6c€{Hì®4µIÊBH)dZp¤ŸŸå\åÃ-W# |k } Uk§í\~€¡ 2‹ )À—’BÒj†„9¿`¦F ô#R˜é<ɪ¦¿äùt¡ •jR Y¨ê±&)Áñ?&ÿ[sì1u†ftS«âo§Eþ CW×¥m<õT/ŽÈÂÉ M$ñÓTIa,x€½–Dàr²)£I|xY{ Ô~|zjg+"•È­*8‡?-dÔù$Xã¢ÈS}­bßHz,ˆÌn.¦“ /ýVþÁQ,°I%¡jµIRxç^”:¢¶—aJ~ÓëÕÀÿ)îím£Øù.´ÜyL>õ‚lL 4€,¯-:Ø€¿H@ýMíþY¾ƒhæ'µy<;Kµ¨¯ _ñuòèëe¼©’ÖQÃíêä{ógŸvýLâÕ”¾UqnQ£ú¸à[ýos ¡) áš}¾uJˆÊøêŽ7ÕÛOs=R†)¦pá¤9¶üþÛÚ‹G '…ÃXÏåÑ<¥cURµêFGxÃUyAYayí¤r¾°­¡ü¨öûÆŠÍJŸ.©¬PƒçŽªƒ½·‚Rn¸k¢™I† IpÄ‚‰ •+Éßþ¿²6·i|TD5ò= i4=sƒåÑ»éïÇdpT°š¸\„o‘C¡ útž ëûŒ¹ópš¶‘ qÓóÎ’B<'«‰ÇÊ-ÍOžÝË,£Áeœ)ÔŽÊÜcp}§ö»m6[dÓËF$~dúô…¡QFÔséÑSPZËd7{ÿV¸!­À>­7Aý}Ë {‰Ï˜Q¤È b¼zsˆú‘A]@‚},A Hk_ëí#­#Ñ5ó2ÊäÊGíèYÚ'DÑ×<»zJ“À<}OüO°nô;#5(¡ÍÕùt(çr,LŒ5Ñ€ÌX SÈŸQ Hÿcì#·[¼Ðôuf]b -OÏ¢1|–âD1z.ÄÞÀJö$aôãñîiŒ }°úèÇÛN”B”'Víñ¿fÍS6š8X°†ô ŒB‹ƒù[õŸqþîî¶ÞâÀô'³ZžÜJN¨í£Ýå¾×û«Ø[73Y%ˆ™Ú(òž€!ż ß€>ñÓ|²ð·ûyBÑ^¨Çò?Ê´él/"ÜÂÌ@Zõw½©Š0E˜£žÚ–†·%MJcê’f¨§éb5FÐÌ#“kx¡¼Û}ésn‹¯“³Ñíò!¡#' S`Öyp˜R /ÈÒÎ-úˆN¯é±ŽjÈEÀ½½£²ÄZHÀmkÒ(MT‘ðפ/jG#"Ò³šÉ)Ò²hå_Õ,tY,nã§¹ ÊKPW0üñÇ<ûó#³F}|ºjàp5óè®÷™*šƒ‰(«|NŸ¥eD9(Ê[‚ÌøXÃ_è±>϶w>¡’JFt· Â×_ÀCcêúû~‚§¸pùüþ]lùu*L’úú˜ÿ`i¿«ëí‰@¢w/_AòëOöôí 0€YþÛUÒÖÐEÿ]íþÂþÒH£Æ®±]?_³­SÓˆcaûn=q›“6•x¶¿¯´šEOê×Ðüºõ>}8T;}ºƒ÷b䘿œq%ù·´±*øÞ8_CòéÃî6i0²ƒ2‚íÛüÄÂÜHMÿ?ì=¬Û•DÒ÷Ž?QòëÀ‡ ÕXê_I6 nWët'óìAA¥»‡ëóùt–˜9èWÙÓ7ØÔ¨‰ÞÆ/ÒbyœÜê•~¤û)½QàȺÅ+óù|ºYödtg?âó—ü¹<‡?õU/±é ’Ôãéž9Ç[?ûzi¹ÿRäßø¯µ^#ÿÊ;þÕÿ ºõ>}ÿ×+½o“ßu[ÓS–›$¢læª Ég±ÔõmO V=Þø‡ÉÃTÖ¥¦´ká×F‘¦Ãß÷] Âªa*¬ÁNA©ž`T× R1ž£è‘üX¥™™Ƶ'æ´øA$’4Š•íàjúÞ]Ó;ùk*çc.'6P ÅŽ–#/ðZèiæÒ™gHãk€]ãxÁ±*u_w°6²šÃUib)×£IaRr‘–ˆ1‘ƒSçZWæU”Ž‡Ý›>æÆTÖÔGW4Œ”P#LÕ4‹ªÎ,¼d%c•QJª‘cͬ·7¶OõˆßªW½jN´­EN¨óÒH'¥6 G‰#‰^f…q׿ÍKàÏÃüæn¿ùo. ÀÝ陬—ˆï¯“½™ùÉí„ÈÔÏO—“ Œ­Èåw`¨½Hu‚š®”ÄVEe]Ÿë+òõ»\m[lqJ-WeÀ(¸¥^ÙJƒ‹‰¡·gŽÀmDHι­8:ÓŽ:¨ìæçù+ò“¼÷ïÈo‘ûƳ{v†ùÇnªÌÖf«umô¢¡‚¥œƒlà¶î2‹1 màÑÒž†–š5¦£E'ŸÖ!ŽyçDÜä`³I*Ihß:]j*(8pR(I5Üï3°Ô¬ºÿ„PBFO¨ÉÁêëá.xìåóBîµËK4À|ì„ùŠ<’›÷ÇÆ³0Òd«ÄêY™‡êýGܹìì±ÈdÓ§P·l+“"WŠ©<ê3ž&Rº±W^–­xü^|sÔŸ™?ÍW®7Ìߘÿ˜¯Âí½òŸª:Cä_jíž‹í}‹¸¨ºÛ¾úÛeÓïõ0m©w5=U4Ù½¹Ž¦eûHü”Ó©S®ÀÄT÷zݶ—¹¹·ßm¢¸ežEŽ£C"‰$|J0eìøJâ¼HÀ]$ ¹ŠDªŸ‡ XPq¦hXqiÄŽŒïÆæçðg¡vþJ‡àÀÅ…í¬å?ðUÞ=¿¼qõßh¯©é¿Œfiò¹ÍÍ•Â@±±jJŠ‹-À,Å)μ›Ê–Ò~åÚ’9š­šbxÐP3œS·‡mHRH´3C¥ô- œ ㈡ ‚3Zð­:¬ïž}aò'·; òƒ´3ÕÛ‹°»[›¥ÉÖ¾FŸG‰Ìíd «ÛX W¦Çb)pÑL”T´ÿ¶ßèæW÷ Ëîæa¾ŠÿT³° €.Qä¨)š˜ŠFߨ+á€S}SHÏ 3&x’§ÂÙ¡©&´88¥ÿð§çŸÅƒuÝqÜóÿ/^Ïí¯“˜-“–ÄW÷”=ˆ‹íw5~r–²³níÜÔ5¸ý½"í¼‰ÆUO³¼PN‚-4òç3rÞÙ¥’Ô}r ñîv¾HÝúHe aÅV+ Ð@Ë-xLÓ ž5­iÄãHoæüƾüæß;“|g¿—kõÿÉ̶ÝÄu¼|íÚLv(æi(ëö¾[ví,D8¸7h£Æ `¥4p•ÒСîaæ^ÞažaRñö¸µ‚ø~@°-… £6 4±R¯ÄF+Q\*šœÓ'çÕUcxì®ÀÂn Ñ’ËÑõÇpep›E¹qÑŠ®½Ý9,ñoâM]@æ:ºˆ `4kÔ=Ä{›QŸoKˆ• ’Þ%e(; P (TŠ€Yœ·}(ƨ"¢É’*\ƒR­+á¯È:ØágóŽø]ð#u÷7Mü\þX=¿²r›®¶ƒvïZúktf7¤¸ nA°EU¸(ª²k£‡+Y-*E<uPàƒ"«ÎÛW2ì›=¢µ•¢¬R\ÌXùüu $«PɨèÊ7PÅb¿*Pœf@5p«gä_wü\ïÜ®v‹ã/Á®ÊøÙ—‡~ä7GmÑU÷-.ãÅî¼VñžÉ/ia1°ÇÎ÷ÒK¨ErF…ÔŒß'åÛ§‚X!HψÌk!jîQ¢Š«“¤p  oÄÔXò™5¦*1ÇòôÈÅm“â·ó¡ø—ð¯oî8þ?->ÛÚt½§šÛY çš›¼6¦åÌæêè¥ÊañÃ-šÉÐVÏ<8,…}\t´É3*š¹ J¡ŠNÛÍ»Ñ %•–æ”2c¥´Œè5˜ƒžÓ¨œM}úa'Ì‘JO·Ž +éÇ¢uß©Ñݹ¸h7ÆO‡ýƒñ‹zŽÍܹþÌ9NÁ¤Þx<Õ죫Iè±ø V¡À´99G‡H²€AîëËW9m¬’9pÒÁè‚Jjî*ªŒX8Õ¤3tú¦£Wm#ME|Í  ¨'I©N®ÐÊî¤ùõñ+àgu{öòþì.éùu&ÔÏÖ7{Ñö+™JœÖÕ¯ŸoìÜý ]ßÜÝ“T0óÔFŒõZ¦*Ê* ÷~XßùG•ކ°Ñ¹FZ¬\„"Ff]@,lTÝ:^EÑ#jEJ¡zƒJR¢šAÆW† zV|§þdÿ?˜žyv]wòúí £ß/ו»+jvî H ]GMöÍfs ˆÄR®å¦Áer2汃 ¼ÐÇ s8r1A2ÜíŽ÷L‚5‘%RÕÒXR¬ªkR™C) C*X®B5&T%MAj"ŸE· 1ÒÁN¬.ÿÉ_~|Íè]•Û"7'oC՟˃¨²µÙîà§Þ˜(÷T»ëzÓŒ},»S¤pÕ‹C>7ug¥“AYJˆh̳Ó@#yË´'~ÜÝn6›\û›Ü,·q¥ ,iZ+j 4 ÔÄdðÝàÆ*ŒL€Ejph*x“‚ G—F†çéÖ‰Y˜§ü¶1[»agrµPãêFwfä3ñaeËzíÅâÚKFYiš9eŠžTt=2’nMîÇ/dŠ÷lŒÆhFT‘RÔÔhs@MV¤È XY]VU,ˆÈf+¯$šj5ZÐð cA¤—m¡òÓù |…Îcv‡`t–Câ&üÍÖÓâ¨÷}NÜ©ØtTÕuŽi)cìÚªÜu$(ÌJ¸#¡Šá¤”B\…î~ÚóR5”Ö‚2æµÒW椰ûI@îüC¦Ú+›Z–M4ò88­*F’iBE †£¢‘üÇzuÿ/‘]c¶é7îO}tßríÜÞg­ó9¢‘ç1Ò휶6Ûµ22Q@ô¹„ƒtbZ’²%Wš’¿Aâw8ýï¶V¼±/ï &Õ·J¥ÀÅkK!,ÔÓ¥‰¨©c •g‘¿,î*ñ¼t2é0©P5$)]%Fh‡6;ð«sÕËÖØÜ›ùâX¥Òó ¥Yk5˜ÜE¡‰Ñ¯’ŒH#nqB[É­“êeeªÊR h(šXPS»¾…cQ½ÝÃK(–*µN¨%t×zV´'çP l#Êk&©ºcûå’529_¸a ME‰ÌeÊžTÞ_ ]ܾ–HЋ†P*(+©°! *4þ†¿ I¦"†‡JÒ•>`V¼Oé`0r@Ø2UX®Å«ÇTÈ~×=< !ŒP“o*–g!˜i*8DŸgÖ27Ô2«š DúÖ€´9c¤i©'ãUÖV!¨EŽ–4lAÀ¾Ôh)NÓTÍï`ÿê ½¼)à¦Úúzzš‚¢ëE\~ÌÈOŒ& ;èb ¡Ò¤±Q!òåÜowh≩¤ˆÒŒX©αACVX"½êE{lΩ"°%Xj4PjÔA*ê‰Ub&’) ÑWGÅ4;%u1*iÙÐÄѲí#ªñûª@ Jòl¹Þ¨ibR™áö’éÚ}x5ÅkLפwÒ©£V>(­(s«KŠ`×O@Ü;†-¿3mø dTòÑÉ©UZFP[öU°»7¯RÙ®,¾Ì"Uä &¡>G ƒçQ@E5¦xôÀiT1Õ¨@'­1@((OÅšiQÑ>ÜTÇŸ¨^,“¬ È…ÊÊRÀ¬±•ب³[‘Í›ÚiQÍÜøZ Oðªž5 âŽâ8“¦”Æ"‘Ú‘êp¸üU ƒZ ÔÔN#ò:‚žÔj؇’aBR4ShÕ¼:âuŽ5§‰ Ò" ˆ¢$ðVÁNíØF‘»2—¤Žá¤ë(CTz öëXP†T+t ;=?Q@GÅ]YÔ€ÝÁ…F V‚˜7˜2UI¨²Ç9‰dÕ!²(ñJAO"D¯$FêÌ>–úîiÛ'Gµ·m†M)Nêš°€ÒrxÕ‰¨ µ1$†SJg®()J0ÍjIôãVÌm\”uôÕQÈàž6Ht"!cå,X‚ƒÔ@ç’"ÀÞ»¤)wa{¹!’•§ šðÉÔ„¨ tÄŠ^7QÆ„ñôÿ'Ú|²GW›ñ·ìó[k•#î1õÐ=-b³®‰cª¥hêF´‰nÚc¯32ؾvó•ô›5›Å¯€hJ€(Xp¯ð¨jWªÖÒ%×Y)åZ~MCJO?CLƒÕböÎÖ¨Ø}…½6}Dn¿Â³õÐÀ Ä'-Æ#ã±–õ7Òx c©sS“÷ˆwÎVÚw(d]RFµ#%…)@U@+U CƒU+¦Œê|Zyy~_äò#áṖӭJêFyú“¨ K8Ò½ì {Å ŠDr ¡¯§‘ŸJ4=yM+¨T|¨åZÓý^½C•àõ¬ˆ©éŠH5BTO1¦6ÐÈHmL#é#IÁÒh¸$бQçÚÎ(HÈP¼X ¤ö«Q ÐÊÄæŒ3Ä1>b äA^'òÆÈñOã”GƒÊCh—Ò<1Ä/¤¼K”ª;è ¡¾E1=À ƒSRH­H¡8 RN¥PËF¬¥ÙrOærséPxĨÅTUM÷±5E™Z¢_+ o •UÀ)¤ßê ?¯°õŒKnæ0p5f¹>d_–ôé+ÓE'¥e ñÖ< Í¢pbR¶!yד•ýxÀ—HLzÿ šž‹Z3¯V’K8ž¢x´ª¿zO*©ý5Ô?¢O«i,ûa÷T™Jêj>Æê²×á:6–Z Ì2-YANJ9»QU^Â4Ü#RT*¸#éþÁ»­”‘]²Âµš½¸àÃ#ò#ª,¤o Yxt/ì-ÛÙ›·mîÜuSE<5´•pÕÄå yÝ·… 8àtı8¤ˆ£@â:3¹jœ¬[RæI§PI—Òþ†7ènl/ì·ZÃg [B€*ÿ«X± Š#:º`¦Pó¡'NIÑȽÅùàž=¬–«#z¡Öì¡ëž¦€Í,„ÙJ‡Øþl¿U¸½þ¶öâô–Ml̤] ÛL²¼&ÿên¬B¨]\•AÉ7›ÀXõyõKa\°¡$ô±ß•iKƒt'Ôö貞EÀ¿Ô{"åØkðþDôsR’¸5ýe@ùåHŒ¾D3‰ Åõ.±þ«$ý@úû”7vXìà„a‰óél(µ„\kÖÄÿ¶RTÏHˆ2CF@Sm"ü€Ãêã½éÙ®6âŸåèIoAáwäöÖøú™iÐû9‘Z;­£*pÇŸ§¸£šlÙdK…_ÅþZõ§.±9QQûz¸¡¸áÞ½m°·¤,´Ûã­¶&ïF‘ƒ2Tg6 dÇÒѰÊRLæþñ'Ü‹ckÌûƒ*€Q¿Þ¸ô)¼Ä0µrTåÐ3³*ã¦Ïî\cüš®*‡…›‹4I-l`?ÔTª/õ#`¸äÑ©?¯òt_ 2W¦>ÑÆ™ñ”r†o[b[Ø;&J Ý¿RòY,±D(¢`Aý@‡»L£È¤ÐtÍÒ1¡=øŸ}…ÅV+ᆛ畬YãRÒV3:Aûj*¡sϨÿ±0Û\¬ÖŒFIÏ—‘§óé=ÂR'+ñtJw&6jh©R «¥¤­ Œê"Õ8Êl¥,D¦ظàÜ~O¹+k•~¦x\v3j?+Oö¬iöüº#}JñH¿ŸÚ:6œ”¹½ó_ŠÔ«íþûbÔ!AGÙ[wâ™?¦jÓn›\{¼‹éÒ d©$3à;FßÉóùtº6WPe¿Í^—XjƒšÁÑSÇæË,áÝådйÜ3-¡â³œÆÔ¯ûI'‹Ÿ`›Ø¡·žPeïéJ G¯£´õa”Ô‚+ùõ&Z9ó{rQ:Ez·‚ÎR+ÌêÒK‰Ž“[#’‡‘5DàðMÅõö³gmw8fÔÝÕƒÔ4‘ŸJ>œ¶V…kÕbwÞ6EÁî:BˆWWT ?ö©(²ˆ€Ós!¿Öü¼¸äiã{»IÞËÈ=xôÅâS¢wÖÉ<³R„Fhj•¢V•‘ ?ÖÑ1Pßpà~~†u¾DÔ N“òþƒ|úfÔ„=ùMU6߯ŠJjUò¤î¡j唳¦:¸sª†=#@&üò-ù¸/Ùü¸Ô%zãðø×úGϧ¤ZÆÃË¢ %c Yn‹QÏÕeO¯íðn=Ì#Æ„©áò?>‹Àí§ŸXÁ}N4­ô?Ïú¨îo£ê=Þ‰¤PšTy}¿>¼8¡1câ°Pt}dq®KXèúûQD²xú|‡Ï­ù õ‡×âJñ4ƒõõ Çéþžîtêâ~åó?>­LÔˆ yM•y O¬ÿª7çAöÔ¡4äŸ//ùõV§Xõ}²zRÞγ{i<‘¢×ÿhßOŽ{uú|þÞ¶8Œôâž‹ª[Éû°ž|‰kþØàŸi{3ÜkCåò?>­AÔùÌN„–>|Œyò%®¶hW¬•^VÄT)HÀÔ¤ZF&þ‡ÐÅÀµÿØûQc \=ðôùŸV±¾Îƒ$•6_ÒßÚ<þoéü{:Oqâ<¾ßŸHÍ;½:öSKöõʉ[Á}R2Úþkhž÷?ë{*¿Ó¡cçåö|úWoð|çü^rÿ÷'çþª¥ö=4Z‚¼}3Ç8êçâ?oM7?êOü›ÿö«ÄùGÚ¿ô^§Ï¯ÿЮ=·*öö÷ÚSå·&ÙJ™·Ih$ÊÖd2˜2T‚8¡–‡ÇOQQ(ˆýÐ_R‰2Ž‘S‹{Ëy<˜øÏAÄæƒã^£Àš¤j¨ –%I§£¢ j&àPÉtÕu"l<1Ï[‡«ª’oº(#¢§ÎFÌLX×›S ‹rQˆ'H×?[:BÞ*ˆÙ{´Œ/ÁPÁÁV Bž ¤&’Ñ©Ww†ñQ‡ªšI4 >jrtÐi’hkJÅ×ÔÇlÐ(Îí¨h¤Îîj·ž¦|šE寠ڑÍGY|”ÆŠî¢ne²_M2—R*¤TŒdŸ:V£UB±<=z,¸*»H+R<ÅH4 à×Z †'¢e½z÷)vŒC?²é‘6ÕdKS6iRpûÇvÔ ©š=²ÏöÅ,€²¬«({(@ Iûnï/‡%YÙ‹T*~5lqù-M+Ñl’xžç4© @1ÄüêÁ'âè<ßÝo„ªÍÓÜû…Wkìò¶lЕ¤‹h`©ZS;n¥+Ñ0“SBÈî”A6×¾ßÃn—~+Vbÿ‰°I5&€h 2^-#¾•fV ÷ðŽ= q<{@¼3Òƒ±ðÎêqmöbJ¸¥—/\ªîÆðãÖ#¶×&MJ Óˆ‹‹ÒnÕ¿Üî®v´ŒC7ö¥*˜] šÈH¨Ë8\üDÑ×ÇVfY‰×4Z±¥r@¦8ÔtÎ14»j¦»#Cº¶dë6ÖÞtÒE¨Ë™ •{K9EQ#vÔÁÎZ_ÏÁ›‚šÎ·¯¤Ìââ,‘NÒêp P`zc!¤XäwRÔ­hF¼ÔP)Ljò8$W­?á=ÿ sÿ~Hýñò[á½Âí¿‰²v6ÕÚ]û…ÎïŸ'aïn©í *ÍÛŽËãv­&×—·öA§«¥Y+¤5u6ò 4™ÈÛM®Á4—ðéh82–ÒĨš‚ k¦œ4ú l-E¸pT-1\ù“Ÿ/³Vókø¼úßäwÌo›=ññC±:;º;¢«ríÌfÉî|~{µ1òv>ð ÏF3‡ÀÏÐájÄÔóÕÁ_3Hå)û¬È网åŽ}ÂÛp‰À»‘ÀÔ¾™5ÒƒUj ÀÑtÖÀ/á•¢˜ëM=O ðµ¥ <³O#Ÿ¯Ÿ¦úad¶éÏuž3©~u7ʑۯû»²7UNóßáÙ;?Õ»cQ—Û”Y|&è­Ù£±é0Æž¦ã¹,Q4µÒ±wõrÊócŠÞáæ‰þ†7˜.YÜ«­:‰]KB§¶6‘A_úQj‘Áj„…ðÁ¯I5óAøq\š ŒXïmv7\ïÿû‹¯†g+ýêë΀Ù?=p‹!‹Çýžßëšé¶ÎçØ{rË.”Þ}‡Ö»ë©¤£7™§ÆŠwpìc¸½ŸŠb¹Ü Ý& ¶8cdò¯ƒŒHÒ´GT„ˆHÚH>HôT5mA¸Š Ð×Aɨ#^‚|¿V|q¥Þ¹Î¯Ãné–ݸ_•Ý{ñ&Š \6Ñ–}ÑØÄ›«3Øø Q“qøJ~ŽÞTˬ©¬J¸'’¯GŽ) ªAýß Y,¦!wtÁn#ŒR¬¯ÆJë FPÌÕZ©T*ªGš8Çb± ¶“æj@ÆxJ’)@ô;­þ-v÷ia«÷¶>»|ußܹÝß.».mÏ·~6ìÜ·j ûæj°u©ŠÛùí´ò 4ÐçšÃ/“ƾÃ\»µHyŒØnrO%´FI©@®[€ÅŒ”¢Ê €dì1©…|â·†sè“\ŸžIC$ç Jš‹©ûsaüh£Î-Ãß?!óŸ3~OU&gmlvìÇt‡Díª¸¶öíí}ÙUŒ£#µönëè}öOIKI-{ÔËâhE:ÔŽ[”­¤Ù-öÆI‘ HuÔjXÄzUYÕµRª“@ui ðÔlør/ PÄœS p©¡Á4¥<†ú³at·Od¾-|’ížÃÇíþÓÞŸ6¶ýÊí]³“Âî ,ö3{ìê ÃÔ”5;R‡ ]º*ßtu–é¢ÉWej«°˜ÜR×VÔž ‚ɹrx,&IîdQ&Q¥T -©bp|BÍ ^ù&ªHI£CïK7‡+ND¥@Qòódñ$“QçOQ‚\ÇGôÆèÜý›Øy ÁÖØžÛÄປ¯>Ebúö›²¶G_vÔdÝôø=×±æÈmɲÇtììí7޶’ª*ülRýªË•>ÎK²˜\_&çhWD´‰€Y)cœÔx‡ÍI ª¡E¢’<‚ƒbœðÉ9 RqJ‘áR§ª°•[Ç©¶WmÓu®&_“¯¶¾=õ$ßptglö¹½‡Òý¯ùšÄåi¡“ N;äÓÈ×b$J±UQU暔һH"ÝyFÏsk` ¬ñÀ‚ !íVIZ«Ú& NÉYLŠ1J*ˆ´R¤ž&‰ rµÎ¹R–,jAa©üÀÕ›¨rÕÛBš’º³$2{Oäpçé1˜”Àm=³Õ9íµ1ÙzÊe´—ººÎ¢gÝ<®,¾-à`“¯Œ3/"ÒæÖc}<†HešfW©¸5®u:š;3²"•ülæ¥u!ˆñ8 b§à2xPÒ¹'!ù±¾?w/[tNJ¯vg6ÞäÅt7m|£ÞÐíì}E>Êèý´›ÛsîøòÐM×d³Œ'XËSÒè©W‘¥ûçJvfB{Ïlb½úorºñ¤³àd)=±œÈˆ¢ÝK$‘)Z©M9WSÊ AÕJZ p ©¢Lñú‡ãý7AOÞ´Ûþ¯Òû«)·öLX­ý‘ÛûGvc»Rµ·„Û› Û–}µ‘Çn}£¶¶ÖÛÇd%ˆÀWÖÔÉ™+H­ª˜•Yûbí*ncx™m_Ll¬ZÊ\‡mLËÚ #‘r“,‹+$¬£ê|[8âên9v¨ÊéJ@ 5= èVÆ:7äGÃO– ÷Çò§ìNèƒã–åØ]Ÿ»ªº?¹wÎÞ«Ú;7²àÂööèß[{xn¼vG+.×Ëä¡­š<Æ/[DYM=Q©ŒæÝ¶ëgÜ9v^F¸Ü ¬ÐÕ!”ökÈt>Mu w &€mª¬& ‚*|À$f¸§PáJ×=˜¿å{ò‹ŠMµ¿>önÏE;s`þBmÜ}>A5'’—#‰545µMŠ)ê•¢bË(“W¸pöO˜n%‘ìw;Œ±£,ÿÂBéeÐFÒ„ 2•!URÝÛÔ3# W ¤5Õ¨€€G)Ý_ËC¥p¹J-Õó×çÆ.œë||´õ›cô·bÉÛ]³¸éL†GÄcÆVÝJºuñK[6¨ƒäUe ³¨¿—}¼‡—æúýÿ™mJÄ舉I«TT*âšt¿i ¨Ôž¨×M"}<(J¶@ ¨b(Ô îˆ'5îÁ _ó/þ`Øÿæ-òw­äêݵ™ÚŸþ9íÜ–Íêš}ÃL Ìn Üív}å¼+¨âj„ÂÓåhvöŠ’ŠI'+>9ÃÌéGÞŽy±Þm£ƒoeú8„y5:¨¤ñ®{E+U VÁèãf·xGêSSºˆĨyšƒŽQN­³âÞMð½·1¾iâƒ!‚R4!ž(„%Ò/Ý'$0dEÚ÷½ËaŽí­ž‚d6Ó‚Úh '⨠AÝá¶0  Ò¦;™ƒ)‘I¯Ä§UG˜«qBP“¨èlÑAêŰ[˜ÍŽÆUÕ ©öÌcfiA Åë“Ó{é*…Ãz¸:€U‚ ‰üo×,R †À šg‰ >¤^–U"•?>9$gøh}1ÐÚõ2ãsctǨK[Ç4¤¸ŽUU"PìŠdŽ JÅ€?_éìòÂiÜ#¢¤€NcäA§šŠ„ eN©'ÄÚ™DMAÇM*(!ƒh:NµE@R ƒæžÃNÌøû½èà…k>ÿ=R3³²A1¡•âr«$*öa ]osøm2³ qÉŠëÒ4t©)¦\ü±ÔAÐ¥« ¥X³°ì9øª|FŽÕ T ƒ/E!õyøåL*wÔF±ÉH§ñ²¤Nޤji<Ú:Èž­JÊ>„é2¦I-ä-‡vú2B¹¡¢€*‚à \ëÌÌÌj«ÄWý—¥0¤€OÆIn­“FŽ– ¥=!¹YJÚal5«$¡>Ìc¢¡hÔÎI§Œ•â(8ég…:I´ª­+=Ì>ÑŠÐwQI$R†¤ðÁb}ÜÁ)·Jš%þÓ:èfiÖHãTB±iT‡C“éQôöÓfÔJ‘÷ÕXŒ‚8äSI¨@ ««€©éÕÉ,±!íRxÐ×"ƒÒ˜H Xð÷•:fö<Ð -<4µT*–†(53Ë—C9VÒ,bRÎ >­@æ&7vâmR2SMª%jʪI¡%üVÓ¤T°'Si*•$%¤ü4 çÄ ã“J’j‚+N©G±¨Ö‡rdbV7†i`ÐÚž"¢yšF Jê(ÍoPI¹?_r·-Ê͵ÆÈ£NMI¥Ÿ‡áà ;€ŠIðr´ ä+ŸÙä>uÉÀ­ lÅKZÌ,ꯡÊz•Ô9@X1ñ¤³ CÙíÈfIT‘V¨­8…À9RýÕaÖ©_õ«ý^\¯ÀíÀ›‡I‹˜»TÃzIɪ6E“ÕÌÆyiÆ™[€Y1ý7÷ϯ¼>ÊvÝêêñ‹sš2pÅMTN'Póî\²V4q¢šÔhöŠð§­G ÿ1>´8Mɵ;މ“vc—’œAvÈáo`èYzvŽáÕ¤Û‚}ÈŸv>cmßcm®îbd†€+ø¨A¨UÔu2œdÐipЀuà ZääÖ´ I$'Ž+eb<ѬÑ1duÕø*bŠË)ýJtÜ+献¸±h]`Œ #¸S#5¡mlªÑÂUŒ¨¢¡ˆÈ4=0ÖнY[É‘Ö@£Éõy%})ëǤ–7*LI¦àX9„Pkˆ ,­U 0Q§… ³BŠ€ïE5iT…Q¹e$3–á®<€"¾uà?ˆ‚8i鉪š)ÄŒC0@‘ef)åÄvh4ø‰ÇØxÅô¨‚©¤¢¤­Œq2Ó>‘`Üê§”‘nH#Øp·Hå–Õ£'Ìþ}Ü6N :[ÐUyá’6[}Ú­l p¾›‰SPäAøö º…a•%ÈÑÛŸá>} iÈeü,ömtt¹)(êª)àj·‚0 œus zÅ È-¤7?ÒþÊ·XkW÷kÑ_éQüºuY|u¡:= iž¿ÎãYë±r¸|)ó$Q‘qþä(-þ»`ÝËÂYä÷Ô+cð>+ó¡ýyÖ­4g*GÚ:·o‡½Õ¸3?û`ãªNs­¢‹¶¶N8jº·!û}銦[MoÝ?JÜû÷/\Ë·Ü]Ù ögæiéæNš„;UÓInèzô÷ÌœvåÛsF¹2jc˜#\HNžHVçJ“cîkÚwE¼·«-j^¸šPtTõCÝËÚu¹ÜåcÃ9M4žB„éÐÏs¨oÕîCå­…Ms:`œŸ¢õF%Üàà<ƒë»bÀràÞââÀA~ ûKj± ðÖ‰N”šé­:^lÚy2ªm6+ÚüúÐqo@Á<Ë"ÛmÓÁš£ì§Ižª3ÐýV"§ê³iúl [ŸHAù÷F£Q`¸¯Iµ…ÿ~­qÔœ]0žG!µÈ[ýRÀðmÇ?“kXûM{)\Ž“\ÈëgÍN>]e–âbª4¸$éÔ¢üƒÇÓ“k[ÛBžôè6ì –_‹Ìt¿ÚìþHÎl,Ú‡$&ÜZÇ›ñøöÝ©¥ºSmúP1ÖNέÓD!B…ä“À~¼{¯)À}mŒôs+ÊBIÇRþ8`¾ÿrýËÄÆWGÒî¥Oà›{o–{hD” j>ÑÇ£;E螺wu³7Ä\$4ȪEåˆrß[6ç‘î;ÜY¤¿–S%Wü=ÄA]CáÿV:»óm¶WZ‹¸1H5X/$àýH¿7üÛØO~´ú»7JTñê’H¢•9èÏ|CÎÔn¿‰qOZŠköûãªëL†ììÍÐÙ ¹m?À7TJ„ýU}â»6®—{uñ_Ž"¿˜ÆÏЊíÁÁ©UÓù£Óù1[ÛÕm•a+qàªPºØåo´†N!È÷ &'YÁÃóéGD£VNûúŽLžÖ©HiÝš’*êI\ú\5<´YJE$Ýž’©Ðÿþ¾×(%Xyç¦îM"•|ëÑ_ÏãáŸoä)£¨×LÕÕôaxk ¼‘TPÈ8úÌ–…~²:Es©sû)ÒPk'â=Ýá tËY$Š#4YT­” >šy"ÇfêF±Ã\½B>œû‘6¹ ][²äIúcUäè¦`†•9=7áòÃoeöÆoG±”»;!$мØ;Ò»feGÔiòa*¢oø!ÓØšx|ThªE^EÏŸŒ‹(üµ¥:r"Úâ(@ì¥?ót“¨Æ¤~i“ÃÕHéJ–BS]@éó$ªÊãöûË3Óïí—æð’&”QWçè.›ýÕDj?¥‡ôö† *V`§M¸ðÓ­[ºýT€š`õ[ ¨§æÆ¸I¬¤ŠU&[:ÐæqÓiS-®L*Äóþ¾Vr ñˆl%¡ª•óÄ¿.µqF |º ½hf¥Ý2RëEû‚š DÍ¿» ”Q*³F ä\-¸½ÆIJñÉRi¡‡è?ˤ¶†ºÁãÐź ¬šªi$I¶VŽeÒ[]bÁ«ßPÒHK ø±'°{tšR±¸Àü@þ5þŽ?ŸJ[ Ž«µ£’,…u+• ]Rò„}d[‹k¸¿¹¤25¬2€hU|þGåÑw› yõݤÖÀ”ÿ5'ÑÒñ“Æ¿ëï]š8ˆyý¿.´ÏMä5Ö̼qúOú·°¶¿jjºN >ßùu¾u„‡Þ¥â¥ôŸíF¿í\ ~=¹ÚJ`ü¿3òêþ@ƒŽ³ÀÈ9^Q¿²múïg\{nRºMTùyü¾ÎªÙòÇNÑkûU7[x›ÿ§úëµíù·´o£Ç=¦º½~g^®zŸi¬—hÿ\î¶YßîÃùö”êÔSZ?‘ùu±æ)ÓŒË(¦>´?¹ ‡7‘,oåàí4e µÒx1è~]Xðë3¬­¨Rèn·Ä×E/?çMø¿·¬ÌPÔSÃ׿>]m~öºßÕÉSþ©G>¯b#£I44¨óû~]%n Ð…²]uñ«Æ ŽõFÍTŠ-iRÄ_üoì²ÿN…:M3çö|ºSnxŽ‚ çü^rÿ÷'çþª¥ö<4Z‚¼}3Ç8éÃñ·¦›Ÿõ'þMÿŠûUâ?ü£¿í_ú ¯Sç×ÿÑ%Ößm›Û5f¶õ=u&åÅUÇJÚúº™eLÌrE3ãñ“PÏ-j! Ë:G©×QWGvËÙD¦c*ƒðÀUAÀâXŸ3ÐÁh$†Ga¯WZüDדªÂ’v:zÀScs.§víš tÄñÒϸŒ¨Ïµó ²•©Û´ ÅH­ìu,KuVm*Nw¹eŠGAV ÐPf ƒšÐW"¡½ Ì%¹CUZ“\ÔPøAò#5ürÇü²H3˜³¯)Š%§“%$†“6¥C>6&”Íä[…[Iè/´+l²¸„‹.:^€‚¾ycø¨NDY#uŽãOzN1CSLúŒgP”èÏõ®ù£ßÛ''´39Œ]UCZÓ=QŽ:‚™Š"ÕxêV%¾ØY—ÉßÔtª™ÿ”ïRûiŽ %/2‚Ç´kÔùH¥Xª€Xë>l ÚºËlˆrNšJÔGµÎjÔÒµþ@õ|Xßl×ept´Òf÷n>j¹r1Ç¢ª‡’S¨¦ÅÔ¨eŽ–ÏéüâΊ ¬ÝàwV¨e'1Ç#Iò!{té5W ÌjY^êkJÐP-MNkñi'W GI=VGhìÈbƒmEýèÛtòPíêÈ!&lã ãþõî:ؤáÛõ ñ^¡RìO,L”†yGeºV ¤•4§á"•"†µ¢æµj`–â2#!:IÏ’@ÈóÍ1NÚF ·Îß§«¯§î­¯&ÜÙèéW&⌿ÛíL^vû}»RÏ JBdŠìÄêJ†à ¬§  ‹i*kJh¯83&¿,ãËä$L¥´«éP­)Ç V•ZçM8kž« ÷'ñHw6Ö/eŒ‚ãL¹ã‘?ïè€ÛòÐýÓº„:j„E¹i±*â¸S¶²<2ˆÄºˆW åI¥8|è `¡E*ªÔ hùQê+Bš€ ­HfÁí ,ÛVÓ Ñµ«mÝÙ Zz­ÌZ9›jeciG—mÁxb!ž^Z]´Ý¬¥£vö,ñÛÊŒ*‡ ÁHsBiE Z y"IV*‚sÃÏ È$Ð Œã иšÌµjM»°•2E‡Ü®ñG_¹¦teÁeeIüm‚Ž:Zjm +„j|cZ…#ùyþHmbúXdHÚDâ`ö³jííjTäa4v;Ö ¨È<0A4Ô?Â)ZŠTV”àM:{ÚW°ö¤›†¿u»o]¸›rª¬~×ÝÙœNªÌŽŸ•‹+’ÚuÑÄ1yF†@’ÒUE+Dc•ïknw}ÂîÄnjþv¨¢Ö†7S䪀 éqLj+ÿ«4ŠÈ4\X|ø ô¯Ý9nËײַwo­Ë¾0Û/ Ü›³cTï¿ÚõÛžƒ`ŅؘÜí?Xlç lueEv7¯0xø)± ÔʱQ“$¾RÏ1®ûî ZNðÙ£Ëò*N¤ ÖA SrM@Sq~ ™c Jñ#‰¥E=(h ùã£íñÛooýû²ö¿[eûëq˳°RljÄ`!Ý[°˜z-·49¬U*–«‰vþ_pO]IаÒÔOu‹i]{«ºY!· !pµU? µ(aâ(  …ÖMiéË;é^ šû‡¨9áÃ×´Á9 Zý§ð÷·!Ý»U¨;ËrIº6¯|oÎÇ¢ÍWnœÚWÃÚ›ò·–·qÙ) +Þ¶}“Ž«"ÇÈõt‘0ÿ7ö4Ú½ÍmÒÒÞáíäq ƒÄH¦°¬šˆߺ…w§¥ñɪ’ψ*i\T€*qáó§V¯B­oÆÞøëª]ý”Ú‰S„ܹÌ=fÿÙ[®pä¨óÙxÛuX®ÆÚóÍL“9¶+ò´•Ò[ËKÄP,ŠªK<\G{ãàÈ“#8r¤¡`ÕŒÔ @&•FrAí W*G昆iBk_:p¥(xŠ_AòÓ\Û¤;Ûbv¦~«Þ;ªïÕ{v9ºß;M¸· 6ã øÅÝë¸h³O S ¢nUg7žà¤®ÆÄÒR¼yJß1gÔ(Ü?ÂÒu·!Œ¡ ¨ B(r”uo ‡«jd¨øª š2‚ijU…H8À9©àW®º£¸»seöRîn÷ÜÛ§…ézåÖû{#žÜÕ¸Ú\N2ª·9_‹Ä œ]$qb¢Ê‰jã§V•’m^%XÞ÷œðòÀd†Éâ‘$U54M:Á¦G0J¨Ug¨ÇO^ñ¤xfR Ð=)çSR|¸úùðèûf1]·¿þufúê~ØÍmÚ ^žmå‡ÛùÊê Îð댶އ?5tRGO=MNØÅÀ¢V†FcK d­¬®.ošÁè!“蜊(e¡Ò”^Ø£Z?†È†§P)J€¡åºÞ*œ£TɧÜ|-ŒiÀ·í/ýà˜LÀÃw—aÒã{#qç2¹H0»·?KW!¸öÌ“PerNÒ@Ñ䲘J q¥“ÆE$b&IBªÉyýÕÑ#ŽUb€3 ¥3@uäå™MMxÖ†âXÐbt¶MOiŽÐXS‡áÀ:uП·~1÷ÖÏØéýÕï¾Ö§Áõ“ã°8üN'tf((1½]ºéeÊÅAŘÒ½½Vc%£œÔÓ‚ÌGŒŸM[ÜR|32J³x€T8N¦®;èÔ+ªŸgíZ oÛøD*¨p3@H4Ç öäœÔ/«Pž–Y¿„ý£Ø=×¼0Ý«º¨ûO­:s_Ô[»ȦäÂ콓µ©6å.ÑÛõQÍ,”[v>¿‘ñ)Dš©ÅXuï>äO î6ñ¸xeˆ>©A¬L4 î4–¦ŽÕ:¨b(«ÁÒ×ûñc*Ÿ i¥ExPÝÕ5MÕ˜Žì“vÁOzv%úÊíïÇVaÎTà…mÕš¶šy~Öª§ O_,TM%ük+¯¨P›Ýû«D”+0®­Y©: k'RN²´é$iª{g2HDñÑèj25@uŽ‘F$=›FÌü/Ú­­jÄ£¨È2Å[_QTËU,ÑUKU´2J%š¡&,˜òäÜŽïÜíÒçzú’ê!ƒBÊ+BÃü:TЊB„=Ƥ:$M)RÃA ƒ¸5ßN­ÊA­ÅðÓÌIOMS‚’®ža0dëcY)oçXU"«‡E;9bUÈRÅmv4³÷Wq:cÀªéŽ’ÃH hœT4Ê"¯hnÚ¼*ÅaPä)\*Ê©M$9]E˜ÇF!º 7'Æ=¯·ð55µ™²T²ˆ­R“TÉPÒP ¾]j­ &«#¹í»ßq÷¨ÃFòêfj–'Q*‚¸ ÀE;€@hº à‘Pª9 sðQÚu*¨T¡Á@U5ÔHg£ övÖÇã³TôÔpÅ©kž8^2¾i•ˆ¥†iyZvèKPcÔI ë î{¬÷Ѿ³R*)Bx䊖u@U «£Pé O+WX Rx¡Óyò ð‚ň:N[«µé}Û.ÖÅCä+ü-Ò ´extËi’¡@/G, Ë’Af •ÃÙÇœ!]T¥ SP4p´:c ¤„Ö|1«R ›€²4¯&™ªÂ‹Ú ¾FAÔ½ ¨ tW=ût«QVR»ÊšJ~hÿ'•?Lˆt¼-ª-{Úì÷˜¢Tx(– ’h~*ejr(€.Cäê -ZPJŸ:†&šh)¨’"nº¡œÚ¨@% ðTˆy‡\¡U«ªDß©ã7_Ô¨åWmrÄï®ÄÛF?¶¾2Àº<>:*Œ“šQöìªB)™B”:n­oÓêìïí •Öº•87pÔ)«:ΪЌ2©4Æ*Ñ´­“5$!U¨Ø Iñm] ¤…+’šµE‹ÐVùq€ óDŽ÷c¢4‘ui7‰F¦^>…O,ÜÜ1墚ʣ ÄNš~!¨Šöš¯mEé‰fÛ<%I_ÅëO!¤@ F£$à•Îï g¤ž¡QÜ„•B„/+,Ô–ý²Y%’32iÒ¤¨6Ä[Ú¨ÉhŒU‡P2¬'ŽMK…´œT’^æ—É©Œ€)ÃÌàpÏÄH<@†ªLަžs®IQ å%ñÑ*ÆÒðO6¸¤аÈĨfÚe 5´ ©ã ébîaU2h£#15,©‚H-Ó øƒR¨Õ~CÌf§Ð×UqCÄ‘TÝý‡lnìªò¦‡2‹§„,‘Ü– *\¬`‰•‰@ ?§JØ$òd„x1:CPð+@4ãýTt‰±*ú• ×8S…qé¤QÑ{P éÒU.FÔ¥ƒEÉ$8ü{Æ¡™RƒA P~Â4é5‚™$–¢¸¯NŸ_>¬'àë“ØÓâ%œ¥=`YiB¢k‘åf-cno¦Çð}ãgÞ[–[qåÕÜÒ L•³MJ+Q]$¨ÒB±ª£5&‰¬KEE(FjÌ==+ä(N“Çd‹¦ùÔ­Ùw E3KUµª†ETi¡Ž44Ù(ÖdŽUQ%ªòÜX H=ßß—yôYËp½ÊSN4ù<ò8äÐ@, ]CÄ®¢kÄùÐ GÈ W$“Ju­çA!¬¾xFkÆn¾’/Á ÚßK›Ž¯< '€öÒ§…ƒÀAVŒ®šPHOá£++F•麵©Ú4ŒI#*,„_@]>¡}®T” §WÕEØWHG†ÐäŒð#J­4öÔé«:´hSãÈþ#V §Û_:PаœüÍI*ˆV@Ž[B4¬®Ìµ5C,ï<¨LˆZ&° °EK—!ÀTÉxRj:5ŠT•/ÄÂ…‰¡jº*‰CÒÀºN‡N£Ç'ÏÊ”83:AÉH±ÒTÅ?˜K9”y.âf&CûŠŽty7¸öO}b÷×2'‘0 Šz‚(A##éÉiRÒ‡$çóüýs^„LŽ9f¡éP„Eû„¢¿ùÈ$U·ê?Oð÷î1;Aõ9\Šzb•éDd×5éE…ª•5E'ùúwû…RMË#i¨‰mÅÊHö Ü­p£C þ|?ŸDWŽÍ-Àô©¦©L}h«§rE,‚bAoÜÅW 1·øÃ!¸üdÒD·Þ¼^£ìuàGÚ8ôË© døGŸC>6®8d¥¯†®HØxXH’z%Œ>XõAÇ3/ôo`û¤s’•jGôN3þ”秤>3Ž#£añǶÏI÷ŽßÜЪ¾Þ†¦ºÊ9hrÛwF¸ýÓ‹ž?¤ñCC¾‘ô+ì;ª{°Ý¢?ãq¶–†µàOúe$tõ›¥•ìA ð[&¿?/Ë ççGKÓ¿»°¸…oîÆFtÝ»*ª'&ŽÍ܉üS UO"ú%Š8ª \]mîXå=ÆÖ+ùl•ÿAÈhý¡Z°Ôtiqo$rê±>GU¹ÒAQ+\/¬¿ê"÷P¤ŸöÞògfuè #‡ZLA^’pͧõR¯ÒÃIQÈçÙ¬ð™éAÕ§Mh>·>§…¤žj‚Ieú0 *.OøÏ$ûˆù邈mÙ¨óé 䣣¸Ž†ËK,¤(`€éP@»0'S_ñ¨ÿ­î8¢ Ãqè½duÔq.¶µ&Šie ¼\_ÓvQržBþ?ÇØkyÄÑ¢zExlzôœªe޶e+ÀsúMô©-À°þ׳(AkxóštDŒ5Vµ4éµ—[¹±§­%O6oñüqì;»TSÏ£+(õ1§Ò3Ï4ÓË\Žn/` °úÿ‡ãóìû–íÕÄÓÑj0#â sѵø‘¶5¬•rBõEi µÆ«†Ö"íb=½tVKéæ"¡Tþ]ÚH[Gˆjêü:/pÁŒ¢¦¦Ô±XÐ úZà·úÖö¹¡šD?=,ÉDEàíèÕîzh3˜fäo G Ò§†[«'óô>ÑK’7­­U9ž Ïm2ÌGû°ŸÉöÜâTT¦:×9 ÇHÿy=’Ë%ƒ\õÜÕ盥¯¥’:͵³©#x›Dy\SŒŽ“á ¼†‡A‹ëì†Ø€)ˆ|&£>L´óáž›—JÜ)Ç¢-ß’6O#Nõ憣3B[] ¥@]B.n²¿Öüï&9%Ì{m»xb½§ÏÔ|úzu(>«m¤”{ê… ’#KR# z”™£Ô4E5·äqȵǼ˜¶•dÛƒúÿ|ëÑ}ªég‡CFj™ÄÔѽ}cêª\ÇCuo±­ä¢^x· ‹ÅìA|2¢™Ï€˜AæßÆ¿Òék tA7]¢Þyªo#ÿÀ™$ Â0ÇS-Í•9¿às×7³Û9AÀ?ŸÎ½6$S¦],% dcª99²_ê‚ߢÖ>Õ†_ ¶Äzüþ}V ytÞêTÛ[\0ôþKÿ´‡µ ‚ªtçòùõ¿!ް•ôOwoMBŸìst^G×Ûš…b¢Œ©õõ?>­Ä užœ6¸ˆv±I?ÔþÿªŸmÌÃKvŠã×ÓíëÌ@òéÎ F”omÓdÓú§U¿ØßÚIñé |\sëöõ¡ÇåÓšÈ<¯Ì‘‹Óȼ‹GøöŒîý1ÀúúŸ[¨gNFM9>Y žb"ÿŽˆ/Äcéøö|ZxkÀúúŸW¨¡êDhíK:™dæ9-Ä_ˆ¥7ˆ~öõ«¨4AÃçê>}mMAÇArƒæeÔßWÿSøuÿi·±#á×HãóùüúHç'¥ÖÌÕ÷Õ‘‰]5S)¸ñ’@ñê‡çÙeémÌyúŸOÛÓ» £9ÿœ¿ãýÉä9ÿª©}Ž„– ¯LñÎ?oOˆý½4Üÿ©?òoüWÚ¯ÿåÿjÿÐ]zŸ>¿ÿÒèvv²xdiªê¡ÍcçŒcðòý›LrJ‘STUWÒ×8šá]¤¥ä,–V<{°Úo%·¸¹”~˜šcÊ¢€µ+\~52@°È‹Óüùà|ǯDn·màöÖ›9™–:¼óÕâÚɈäÛ9´–XgŽF%4Žè…ÐÌ êSËYÍÍ´ÑJ€Ü!T€­ZsRâj5S*¦ óF –XäSASóôZD`W‰[W~¤ÜøJuÎ¥6áÌ?û‰¦Šq& ž™!†Lîb•Õ7-gÜ^­b©¡Ë†%J?5l‘4UE i¤[Ô•‹Ü M/L ‰B°hˆô Ð(nìJiL¢‡Ïeæ°õ»n¹bÊWÔFµ˜É ’báI"”Reõ(…ó“k×#30i‘QTž«Þ:ï[z[ÈéF™V¸]D aH¿„ùÜB×…n9£V ITúƒÃ$šð"´´]II·µ']dçÊÕÊ%ÍáR±áÆDÌV*|ªÀ<‘e©¢š'IÜXãNÈG¹‘¤f‹Jƒ¬Šd|%±AÜH,5ð¡Ó¬ƒ;[¿ R²3²’;hž8y×,ÃKR?w…¸z— »±¹Z¾Çµ\õ3Ð㩦¨ ;[¤1×€,)ãy©8°Ô¡mîGwiz;[E !ÒGñWÍTq5 ­üUèâøëe¸†M1 ¯“qŠžÁ@ƘR.!Aê {{š—4Ù\Ä& \ðFm@ó0þðææêaþñF)¿riQT<„„Ô-eì3”)¥@ŒŠqãåJðÉn+Lƒ^ŠnË)EK>œ*kZ•=ø%©P*| >õÇíÔËÃ÷;ƒ3>kÆ4mÚIØSG¶±>òÑ Á,Ñ•wT#jE,Ì‹dÌcÄiPÄбã_0õ8¨­:@Ê#/Þ” Œ‚Fh+Æ…Nj8š¡Ì›i;RI$Íä…ZïÅ™éßmÄ`i¹½'Ý.à»Rµô}Á€±­â¸šÂ³±#§èà«äv`ü"„6H е È*R%f+«WÊŸgñ¯Øuy¾É;z1Sî<ÄÂl.爧÷^‘Vm¯–YÌ»‘©Ý쌕ô«Fò*Ò%¶Ô`Ž¡×:Ï“­ 4 ü¼ÆM+ƒjifÓ5Z‡ðÐR‡‰©À¦Ï9Pàé6ÈÉOUKÊIþýýغkÓSF"“meÄÓš„Ü“éXéδQœ®–eR锨€ªxž"qsäÃdž—O1’7‰Jª’ù,=˜99Ír§©@;j¥)Aêsëå‚)_JðÇÓm¸ö¾ZóÙQ gvÌòJv½+4Óã7[@”ð>C@ñÉ34—Œ§‰@R•¼ž+NµE5WüMœ¨5í㟟­j:ó(’¥þ!J€8ÔÔwR†ž£Ó5èOëÍÙŒÙmWÑçrÉOà΀ë·)áZ—zM®e Üki¢È²#Éä ÁQ–r]ÒÐ]Ç6ºUâ$ŠÕqTâaNÖ´éëWHJ•%ŽJÔà@5$€=8ù®#¥»#nöZ“Ù:ʪٱŒKQŒÚMö³¹lþÔÈJ_0éI\¹w‚ »0>hØßÙ—!Éq…ÞØfXÏŒúB„{Î5¹ )`qS ŽÖU2+ÐPWδ I¥+AZŸˆŒÖk O`vJd+1;—C¸±”ÃD°Ñ^Š*lÞÜÌ„¬3}êÖAQNéÊKê½”9:ð‰,fÕî9QÙ«‚‹AñÚÅœ0.Xe$êY†‚<Š“æ4†ÈÎsL ŠžýÚû[hv~"«+™¥§ÎõžôÌõlÔÙÊ:\ïèÿÓÓn“F“­CQÔWm×Z±,‡I€B”XÝ4{s@aUñVEPAJ€ô!Šš!ʹ.½€€zd*’õCæ´ù~X?žž˪òèüä½9Ý»’Èfÿ»ûGuo}Ÿ”Ç×bé’š NàÇäª))h2?Ä+1Y EœÀ$$y´ÈçÙ”oq|˲Ä.‹"×PÒF¢Ä$ š“¡+\PôÂ02ªë‡ååO01šS Ž9'ã>ÑÇí9¾[|Sͽ]V/ —¶v`©¤–˜G±7—ŽŸ'O†F©•'ûZJÁ,¦8¹qu®¤"»kÓgm•YT2Xå0úh +¯†ÊÈ¿† Rà”½² ŠÁ¦NE8*(Mi@=Néúzœ~ÎËlLŽk'U¸úÖº| •tï-mFS¯òc;·jbŠ*å5Qevmf‡}`•RîJ1âøºH€øÕÁ®3A\Šâ§}I§ÊÅU‚«¬¥®þðcwnÄÈQ•0È%¢‚‡ymô`Ï?ÜÓ˪—Å{–znŸnø^(XÐw°¦sCN Ô¨øiN4 *¦Ýª ‚28S5§—ì^œï×qÅ>[­áÈ}µf/%†ÎõÖjšµüõTÉA_ŽZlž¥jbÒD Êÿ¤~ŸewÖ‚þÎú×ý àe¡Å Š€ÅhÃP,(­FuÁ¡Œ4RÅúšFºb¤ ‚žiZW&ƒµ±d·¯`oÍ͵ê5G‘Ø;×qmóıH©¶óµ´tOŽ'‰þΙ[–H$zìb öH¬tË’ $Ú…Iàš‘ô󹼡©ª…™EIR2X?sPžàþ%kOÚÞ†êpu¶+®‰*ñ”ÑÉ:ÊekKBt†ù‹ipT~N¢êÀ»”q4&ï­@]4ù‚hºII¡©Z«‘$‰¥UU#U;>eB€ 5XŽà„Ò¯¨iÓO5¹³ŽšòE%4nÓTFåÀ’ ©$‰ S+k‹K›V¹þÒA$‘JÍâU U "º‹”5 @4 ŠŠ Üž&2+ª°c%LÖ™ v…`tŒg¸ªrcÜ{šDÍœd•a£!%M KÆÀÊ#+«L,•J‡Õ31Qcû8…ÂFÑwV„Ó:ªËLú¶ªÕu‚ WUÇpñDá°ÜrÀÖ =M4¯S>¤Q!V2ì¸å—?MTa-:8ÞT”EåŽXôÂ]þâmlèêH  RVæê¶I*šz¡ÕA“AÜH …ZÔ¹ª†¨m&•­¾ªY™tˆ´¥ÓËXBUK.ê,ÍŸ­·D0ÔWR$ÊDÐÃUó¥8Ò¿*ðÿ èí©ZŽºª…á±ÕÞ$.„ô™]"@ä)w²²‹jfí® ßå.uFr@­{‚Ô<ªª¢ÕXÂøa4l”׃_´xV¾@ŒþYß•˜\•El~¸¤ 0Õ¬Ldx–Y¡‰*²$Ò£Ú÷µ‘Ç,ËànôÔUd¦´IýŠNAÕöÔ˦BÊ@j‚sÄyŠp¢ÖµùéÑX›^—Ršm¨0*yµ…ˆ-~=ÍV%ÜŠÁÁ€R¦¸9¥d㯘§^Pj:z+r6Õí ±’¼0ýЧœ©m&9ŒTuº)kb@c§Õ`C^íí#täëûXÐj ^*¤ª«k…{•:°¡º¤ŒÊµBqÉ ¨ÈþcË#—[~ôêPv[AIUÕÁ’Å=Qâ%àÈSyŒµ1¡[Ò@e&çKqŸu{ŽZæÓt’$Wd êâUˆ,iOEÃUu)¡‘Dj]‹• 5^áR5T PÓQ*A¡ó¢U{ﮪú£¸7þë†H€î,„«$NM “¼´l"aéMÁZðþÛó\ÓÉ».탪 ¦„UÔFOw­NKeY WqÇù@4ó“¢Ë ‘ºyÙôbñhÉè¾°8c ›jãØà vb0GJV `ðó ÈÅ0â?Õþªdyg¤†Ni"ªY58Õ#«Ãç„IÁ^)d3K3Be„•%cpª÷¶­ÈÓ)’p­¯ˆ¯L°R4©¥ Ëá3¨Piúhµôû1äH ¨SñPôÛ¡údPP*À 6‹[‘ú~¼ÿ‡·d)(mQf¦jM{@­Mu;uC•Ô>.Ÿa§·]Gä)“ä8zÓˆ­<ºWQÖT :ib(g§e…Ø‚H“`ß[ý>ãæÊ?h[á9™é,Êé U§K8«D5V E “1™+v=jGV¥M_´7˜æŒ‘‹©Ô¦à‘qôöGyeY®­K§ºC§ÑfûX|úvI?A%4b”ýŸ—VÝT|‹øsµ7¹ÑU¾>=eÓ­7ELƒ]VK®óñÍ‘‘%Iy?ì3ý=¥Ø¯ZXfcYìÜ-=csBÇΨÀ=ëú›$žôüµèì,¸ì•m,Ñ:43J[‚X¼êµÂ¯¼²äÝÍ/¶ø¦­OÛÒx¥Ô‘•õè”ø¥°ek=¸Sn´’Ö¿ö½Èáu*‡‡öô©˜šjcZth:š… ÀIRS÷]™õ¨%JÜ’ÿªÃêocî çéÖMÑa\ƃ'Ïþ/¤S4Œ­Úò>c¡F îé¥YÇ:I67$$¨½øóì @Ì(Äô™´°ÕL޲Rê}AË-…µÅ͹"Ö·¶çÙšE{¦^ß.‹¯ €+2éÒT5,Ѫökñê[ßWÖãP¿ôöÄ(PxmÀt‘©â)æ?oB¦Ø¤ÓDe ¨N²‚’?› 5þŸŸ¯°¾èIŸExžY9#›¡ VM!U÷t ¨‡fSÁ76$}9ãØËfC“¹8½9$è]£FbëŠúõf¿öéÆí¸*J*ƒµípñkÛƒ§ú{Gàøˆí_ˆ×¡±D@£iŽ¿ÞéA¸)›öÕ´¸$êÔ]QM¾üûÞB"¸.pÿŠé¶ºd bV;´÷U¸À¯ +$[Õ¨ \~×öœ YK…ªÃʽ.[€@4èJøÅœ¦¥í]烆DY·'_e"ÒKU¶2t9Øô 2%ÎIÿQ«ðO¸wÜÝ¿êö]Þ%_Ô [†{A?ˣ͎QãM2V½ Ý»g?´WMN=dr®æ ^=p‹zJš´asô¿¼=‘@.GÇçO>ž¼¨.Gú½zï7ßmŒESúÚ|^C$†ÊVJº¨T<LÄÀ@žµ80ÆkS×µƒž õ59ÜFR<|’ ŒÅ|ŸÄé ÎRêú)HeQÍÖæ×çÝB¨–´É颊àôQwýµu=,H‘BôÕ4FFb KQEQ ,‡èDsíÔ7“ôö&Û›ü^|åOåçþ‹. †S¢”ÿWù¼º!i¨©së±ÒíÌÚ2ÜýßÞK]¥ SêÅïŒxº cëE[‹h£QÝ"²×Ò±ãö"ÖúEh°ÿ³ÐÃûŒv'cå¢78ª¾Û”ù$Ô$Ø}‹xÓõéàsåGüÛp=†·žò#’æ¶2 $ª!äÃåÒÖ–±­=:®¦¦oŠ œ×=Ï–@À4£ôÈ2‘®à‹óõ÷‘\ÌÛc „ôÂÞTÿÙÑ}³“5Ï¡“#A’…µUþåT‹¨××1ÒØú¹Fj‚Q®¿QÉ} »+<„JÚRGà_ã_—øÃуùôD{B”Ðoêå>@’@´²³:»»³“þÇÜ·Ë’øÛ*œjÐ_*t†\JÕùt”ôýÌ ådùüüêãëþÇÙO…! ÁCçòéºrzƒ* r‹·¦HÏêíy?:¯Å½¾ŽtFM2ù|ºÝqÔvQj  ~¨êʯמ~¾ÝÔ@ãò§«Wf…Gù9õŽeSgqôwÖ>Û•ˆñ08!è:Ñ5éÊjO«éþ­íú/úuZÜ}=¥‘Ž+è=zð9=;4@*¯—ŠÇÉ!úÊ£òÇÚ%rX‚(|‡¡ùuºÔüºph×À@/ËÃþ픋ð\‹óõü{L®|JÐp>CÐüº°8êT 2]’qþv_ §™¸õð}?ۻxàÐpô£åÕ”î‚Òšj¥RH³Iý¦'†ã{û>Àòò>’¾ WK žªÙY—±¤?¦Ið×ú£‚GOh/X‹t4Oô.·øº 3ŸñyÌ~?ÜžCý‡ùTÞÇ‚BKPW¦xç>~#öôÓsþ¤ÿÉ¿ñ_j¼Gÿ”wý«ÿAuê|úÿÓXcq8(*è©©Ö¾¦C]H¢eû h ¤Þ2qòÒd¤qƒACQ%ä¶€¾E Ë`!š‚3¥hÀêá§á$º¢¤idVRU@ÒjJ¤ŽYÀñ(h Í jÇÂP×P¥¶£Ñ:íM€ûŒ­U>/.% º ?ñly‹Ã.ÞÉ+#„Àijà}#ÔÁ]®ÊáŒd9{¶—ÖÓƒ€5|Ô0¥~K¤À’XчŠ~ œ'Š€ I $ê*èmœ¶7.;p ˜«Ïš i^¸0~3SíäºÔ %äGQ€Î¬«.íîë0'µM [æq¨ è"´ –Ë$]úb© Õ“æiÚ)C TiZ§G©wöð³"G˜™L0ò¸¶ Sö™‘O/‘ðª‘*Æ^þ‡Ô¸$j÷s‡/…ú¨MEx)Z@&¼{[P¡$a¤t ãK÷xð4"šŠšÖ¤S‰f2‡´_ _´r ÔY&ÿ) "–¤)(§Ë”‘'þÆAã@ª|ŒÜ]½”òað/”äë*)œi¨ÍH?f_Ç é©Nµ®}ž!I (ÍAj•5¢åÓâïtá¿ÿqrðä'kó41Ã]˜ äX©0åÝØáà"7J¥ñ©]*ÀD¦d¾±Te:tA"Ô¸Q A¦¾…lÔ/B+K5¿†Ä×ÕøúSÔÔŒf•¨mòKiápY*`ô5çYŠ’ª‘©rp¹\”«x 0ò^ma@â= }A™’ífX¦h¤œx¡ÿ˜E{Z˜Š€ #Q–Ô‘ÕX’h*(J‚Øâ(A4âs’H>ý¢ÛË’+&;4Å18C §íÎbR­·æIŠ* f.«#¡mI{{•ö¹Ü*R@U‰Óqø°8Ó4ùy»›t#Æ1|T)h(+¤P‘C•¶•H՜ߑNÔ™e¬§Ý±N²ŒµtÑÕœ¤S‰ÒŒ`–qN*P°M*$&ÍìúÞWX%+"• ð"„ê>¹'9=¸5׎‘ÜÈ…Yë'›`gÌ'íóàkÒÛu+æ–Ÿ¸ËdžÜQ7›5Œ «&ÞÉ­DvM¸€Í,*Á © U”övÞ;FŠòÇRÊp§€`E;ø Tùü«ÓÉÇÄjžÜQ‡˜¡ü?e<‰ÍÀzÚy½;Ô¥=&l¦¾u ‘@zêJÜàpàcózS7¸aÊP5\s½&ÚÖÓ8À,5q¼HŠ=*åÃâËíÕ†F–b\2hí9©é4¨ÍOJS­ƒbbš(GŸ,)äkJã‡F« »[´;ªò@fiéWE¬ÙZY¤¤¦“qdå¥/áÂTÕÓV©uÒbQ­U`Å’maì÷ ã‰Ç‡ 5­@MKqÒ[‰­F2Aኀ ¿ó>#p`7ÆÜš§%M.4c·¾"q>ÈÞ4ÕÔÕÏ*QËŒ.kZ>§d@ܱòYD÷×ÚWNÒ¬Ñ =ú€RÔÒ¬Jⵯ èÞE Hˆô*k€N |ˆ¨>¿·€M¿6eûC‘¥yåì fK¦*·6J­ç ÝÛJy7¯[qÒÔAO^jf…¢¥]Qº½¢=D¥0Î`& Á¼Ú”5Ñ^)ŠÚ«Õ2¥UZ¬E+ZצFO•F j¨ê´{¾xp½‘Õû×+Ÿ%KØû#Ë¥e= ¦êØÔ™<%M,»ÑÖCSH²Âîãz—¹uÕ¬ÖÙ¥*$Ї±ð{àpj+C¤Ñ€ü*KB°!Ƽ~Dg~ÊžnÃì* ¹ò/ã×pUä#Z=Ù¶'éÑÉURUPUâ358ìN2*˜ j+q•U°L’›E£pÄ~k‹‰¯|{—$˜bV™Ilhq~-# çõ*è Rv© ŠÐdpòÆ*OÊ¿‘\oJš~¯î=ÕV`®zúšÜVZ´»SÕÇ&Sfå&ÙY¦Š‘éÐWbr›o'I<€‹4¿R”)EcÄpXÖ£¨2j£qÒ¸eÚ¨·,ò5rqçO:i®I4ÈÆF7j‡-‰ÉƱÄþ/3¬ NÒ&shÏ&½Õ!•£?ÄvÎ`=üqß0î.®ªÛõ’ë¨ÅÎE0–HåxâTCq(jp± Th*53ßÜw¿Xª<‰"°v$T|TSäA $´@ ±ÔWïx$éRZŠLº©Zé8QL‘VjCµ.á„ã²XIf6¦’¡iÌͲjÇ’3$Ë©"_\:A T+i7' -φ$pF ÎI Jv¨"¿&ŒµÐH¨*¢Þ$šggeUW%ÉÒµ5âµ=Ä, -hhXôM»B¾¯!¹¡¥Ò`¼=aÇŠ)ÙF„Xõ$zµX5íôà >Å›D©á\ŒU†HÕ“B@ø€Á+Q%AÍJÇg+Q£•„NWÄ\ÁëP-Z1 «5ï,(Ÿ²CÀ¯UèñyQ×IŠ&XÈ1”HñÈÍîG «ö‰FM*á‰Ý–gtá'Ë‹T0P)@2àŸ1Ò á³«°+K|:‰îuUJ’40<È ,mlýTš6fqÍ#,¯#éQ« D‚ILz¼~;€NY»f¶ Sð½4ƒM9£Žâ“F MMN— xÂ+œöö4 t±Á ÐP©!›Z†g*“ƒ±÷;Ó¼M8f¥ž§?H|o'˜Èé­Xäú,Z@úC(Ò^².¨Mu+’¬(I  £ãBOzž?Ö[šÉ#ñ@Tâµ æ Af¢ñUÁÔJP2+áî¿ÞiHÔçÇ2ÃåµÅ)”ÊC¼š?V«‘§ÒAVå‰Od¢7mÀ©VxTžÜõ$š-H :Ti¥ P´°BË -AšäփȲð«eýU˜•Tî<¥M.k”YL>àÑHìÞ? Ò1J¤X@VW*ú£°n Q IBÄÐ#…E$‚­F³‘Z9¡CË‹†—Á‚8qj(9"†‹QÚI)*¸Õ‰Rùß´¡Èn½Ÿ½©£ÖõÔUPK#'‘ü¦5­ÊŠe7XŠ€$²«ØØéº%±ž2‘Ã8QZR hR@!j*²[%X¯¨I;D¡fJéqæÜOuHŽÕAºV§¢m±ò¢/$.ÑÆ ©Wic åÕnÌÍ },åÀ Ö:®Þå¾OÜîÖ—AW²SRâA$(ÓÁs°Â4­S$ˆÏXÚ±Œ.Ö&¦¸4'9óÀ¥¼éÖ¦©òC1+Y‰’Xê„é«Å‘$‚ÇêÄéH"ä{,…_8¬f§4_B~@àš T“ŠÑÉ@÷åu/ø¯:þΈà£lfài)ËóÅ/‰õ3Dg„ÆLË:™ô¡Ñ)(¬ÉûIzÁn-®dz-<¨ð8«Qô”¨@+²6—$©/!Œ‹«‰ò­E­hsÀP‘‚kÐò3™¼+É zhÅ+ žJwf4¯âR‹B7WP¡I,/ìSdOÖYJªÄ†8:J’M  < *>]9pµhØ)'åN‰ùPf£4­+R ^øV7¨[”)1Ajý%ÒÈE¬Ü‘kòFHìñ©µG.ÅT“•ÆœÂsV C@h¬((xã‡ú¾Ïðu.‚¬Ð×ÑVjdûjˆ¦mÕ¡t‘fÇqñöæõl/vË»W 3Ââ”ÕøO §`¬–nªãR°§—ú½+öW=mÁü»wü{¯da)ä«’o.:˜4a¼e$މ m™#d èôéb~‡Ž-{ó°¾ÍÍ»„fÔ,Fbæ žµTPV¬J®¢ ¥A,Ý;z2 A ³» –ñPhiçE*:!_Î#¥“kö.Õí|m!J=ãBøìÌÑ£˜ÿQ»HŽìËE¨¥`W‹” ±Ë/¹Ï;þõØîyvi—ê!¯m@=¼Ò¤ü#'UœT1ÖYÇü¨¼I59Z€OFê”æòÏ,$ÄÈúC:”2Ék£)  ÉÀgWRèt"ùɤnY»ƒdæ´À8 ÑHÉ­CTôÏIü²SJ«4¤ êTÇá ȲÙWÒÕ-#˜¥ JÙ½aB«óE;G `Ò¦ B£ŠÄ°© ©…(Œ 9éLj^:–“JÔÀ“JRž§X^~£Ùnãn.!hŠQþ”ÿ³ÒB:JÄž} 0IMŒÜ¦¡u¾9H‹RëHq†èÇBܸ옻4û k‹.#bGüÔNµxt¥3.†J+#£õðŸychw”Ýc½¦¥m¥ÙØ\Mî±UcHµUþIvFá¨ò#…zLEbÂà{Á4v›Çˆ1ktºFpÃí®}8ô»k•ZAÖ†£öpê¹¾bôŽKbn]Ë®¤ ’Ûy\–+ ʼË% CDÕžÇQWRG©O¹ƒÛ½Ùì/n’z tQåÒ·t0@iO!óê²r¶VÖ.ê«p=^«XÜ ºßý÷¿y;op|9uh¤‚8`tõB椎þÎ¥[b‘•qÀ ?Pò¬@?«üy>ñë™nZçv¹rž'ù:G)fyôüZGJŒ˜bŸ¶nWNAPu5ÜÇ#Ù¬M-ÊF£ºN¿Ù"„úôËtÜÓ9,^àn=\€K¤ÛŸ÷Çܽ&Îe@KϯMºx°ä Ðù·«º(VÊYU}*y?@Sù±ÿxúqfádÖ²>(+ÐNé'RGCÅ xq7Eµ_òTõ-rWöÀsÇ®÷>½Û2¥ z à¦ûíÑK¢2K-y9Í`ê ·úÖö5_ÓÛ(¿ëVþj3¨j×ýŽ­Ïe@›w®¬šXÅì>š ã“§ôþŸì=¡mqÛâ…òèJé´€}ŸØú·ud¢ ˜ÚR ^À:=ÉÕø:¯þ¿°ÃÆò‚Á{AèšYÌ’Gê!Àõe›7µaƒ 5I ±*²´œ“ãPO×XPyãí¨mûmJz2ŽYM+¤Ѓñï·a‹ä·Qd¥ªš ½åÛÈrG¼(k6œË"ÆÏ–F7<”öæÍ­äŽäè&7Ö¿j‘ÑþÉ/øà,ãVá½£‘±°+G2MÖc\OÜò‰i‘¶¦GZº…Å´ñcÉ÷€·1˜.'VZh.ŸÌô}xZôlii¢Á½ØÔ D” ,Còo%½îÜj…”qé,Diñè4ÝÔ²QeÚ'‚6†/Gqþã²ÿÁã—ÈEèjýKÏúä}=8ehš£é%À qƽnÑ ’‘癈ÓA,Uï¤ 2}•}©V`<‚:Š[’y½íìAµUåxχüéÒª*º ƒ^‹9†*ªìî3É’Äîu0R¡¾æ«’ª¥EÒu†Ò„ñ±ûö£*[A)VíuÕò…“t^$U’E÷óÿ›¡mOEšÙâ‰'€Ïø¥ª_#"øéûaù$j²œÎ+éþ«“ìºîÒoêR?OʼbsOΆŸË¥(KÀIª¶kó+jàÆekéb2ÒòsÖGR÷…l›i=lZµþä4{úíùöêRyÄÒ¤qâ¬ÿ/åÓ’V@ê¾å/XLjàöæRŸì¼“íÜ]MA_·ÔÏ„ÈTb¦Ñ鹊õ±$s'·7gê`oHRG5?Õë ýU®NŠŠ-ã»S˜–±ÖK˜ŒZxÖO!úi1j½øÒâþòƒf’á¬\Zôã~¥?:~tóéýBÔšçü¡>²<\oøA«÷ÊŠ+x’ޱvÜh2úñªß›{R÷‡6¯V‘O‹Ž¥áó¥*ôhF:&=õEEM»)j¨þÏÃ59¿Û˜   zA#ýcîEäÙ®šÊâ)µê 8×…¯åÑuÀ*ã' ™ iœxÀÖá¿E¯xíéÅý‰I—º´ãóé¼×¬3xDµCö¬‡§8 &™ÿͲŸìjÕ ÿ±½ý¥J&_‹M~t¥zÕMzu½>…+Ᾰþš/§Èº¯þ~¿áíê5ÕJ_Cþ^¬+Ó‡ù6ƒaõEôñÞÂTÕþÃO×ü=¦>®ít¡õô=\g©Ôj]üŸIò†ÿ5m&žkÿ vÿco~ˆÜ A:ë_QþJõ´'=U ×Ô£HytókZÜ_bJÉà¯Å\zô’RÀµ}zRm#Oüc÷<:–O×£N ÓWöšðKôâš«_Ÿ§OAP½Ïø¼æ?ígçþª¦ö38’Ôãéž9ÇOŸˆý½4Üÿ©?òoüWÚ¯ÿåÿjÿÐ]zŸ>¿ÿÔ]c+cþ7ø.Õ‘ªÍ%mdµqÂõдò;QÏ4‹S²€Ð…F°ë}\»‚9½Á±Ã éE4°¨JÔT#\Ñ?JäËR8€)^ç‡-JU²©²0q¼çÁ´U¢“ŒFsÈЌΖ„c2-5„y_xÝHK3,‚ÌŒRÝæ;¦—ÆœøZ±…9$ÂàѸÊÉ¡dq8,åxð /„­4b”øh5R®wE^,®êl63T©EJ6ãŠ9fþ9ŠGŒ}ÞM}&VGc#†Q«ò¬›lñ¼²ð3CQðæ˜´ã¤ðÒÑL­ëéEÓ¤×+^ÝB§¿†‘Pô§Ï¥Yå3kS%Û Òµø…juªÈ‘þÏ*ÂDz¬ËÔã•}KmCd*æÈö³-Äô4$1>‚º@5Ñt¸Ó•d„Ä‘¿„ ®¥Õ¦ ÔŒÕ…xž#Q¨3yšêÇÚU[†‚VzXdž¾@òš\€-G’ò„"àêi'ÒH±‰¶Ñh7-ÙMb¾C‰¦ªâ ã×Ôð"Ò°î R5ÓQéëBEk_< )˜\žR Û…“jíÚZÙÿŽå´SÒÔ䢌§Ã3èy³1SÝË(o#[R®›=ÉcTm¢—UÂ-+¨±jµi§<áB¨ô²ÑÈ™BDHÕý xp5øpx бâ:>»UŽ®ë,,›ëG…ÜKY(iêdª­šI Ueàa+çupCY§?RHäéP’êÆb,XÀ®’”L‚hÔ3‚8О„Whµ‘䔯5] Ö˜'@$©:´÷*ñà4ž«_~Öb–£Lø¬Sªãpæ7wÍ¥¥8¼{"§‹(±$) Uå@æïvö?Ú É d ’jE* Z„ä{¾Xè¢C‹Š&…¯)øø¥xŒæ¤CªÚÞâ1ÒL3±FÕRÉ’Y™Û'ŠqÊQ*(RÀ.›“u+bË`Íi %•JŒ.h)(+œŒÔàg^Ij<( O˜'¾•¯ì®>yé E_B2©O„Æþ™y%†mÀ§Ä˜L“4(³e›T2 *J`¤i!´2ˆcø0ëÔtç¹jN)¨f£ÌƒLW¥MPÍ>*‘ý!Ý_ÄióêÖÉBrUB“@ª1¹v½4»]¡Z¶ñ–ªÎ͉ÕB¹Ñ«IHm6Sz‘ø­7mEui"º…(ƒÆ”'WŸ´aS'Ãǯ¦)ç_ËÓ4¥Ô•ÔíE— D• Љ–5Ÿ8D æ±+ã.ùVÒºP+ÝWû<18$º˜IÀÆ(1Æ”©#'>BŽß¤K!ð±Çóü9ó K‘¥;{"N‰iS'IUj2­’½=yŽb§*'Õ[X:+j?ádoøá…Ãø¥xvÐ œc#ìøš„ä÷tŠŠbvÔ@Ô(b8jiZ‘8ê,•Ôƒ@Fcl®Yblц7X0$‘†É¤Žï(`Ík(àsu ¦µÖÔÓžÀjÖƒÌz+ä Nê"ÑÕ¬Ò¤Ò½¼qóý•iÒ“‘©S¶›€¡rÐù(ÐÕd5$éœÈx©à'$’éšx,YƒÈH` Cpæ}@ ^T8ZàÒºh´¨¦ª·Z·,$·Ö¡ª1ÄS¹²*Hû>uóá´Æœ†ø¬ÆtiÞx3†¬¬ê=ՌܺdÈSáúž²…&Çn=冯øFë*x%’L¤±–0Dà;°º$g±c,¡! Ò”¨Ðd*i¥Ø¤²Ôv5•× ‰ÂM2â˜ô CCèjk]4ü©Ðo¹CÅG¸!Á¼52A»ð1lúÃN+w­.âŠm™Uˆ§y|±Wå$2BÉ>…ŒfÓÉ$E¸1 ÔD…<©QêT’8Ð+4=#$é¤kœi"ž†Ÿå"¾§ÌÑ!ù…2¾ÑìƒKK,)KÞ˜ýÅÔ«+<”Y.ÍŸoN;—¯‘éêG‰¨r(Í-}JÃvr‰;?î*ë/¥€Ntë&MŠ•%@¯+Zu·8”0®>MšŽ5òâE2(+JBÝóá%øýSý墂ž¦LîÓÈõ€zŒ£WÓö@¯ Zœ;bÌÞY):2ͧ¾RŒ…œ¾ŽuÑpìêèªuÒÚÏÉ .¥,XÆØësôgjêÍßUPI]]ÙiQ_†¤+ACøjÊôëÝlAüª+7‡ðú8¤Ää¾ÁZ²ª3Å2S˜âj0é牅:ª¥ËF䟠åoÞ²-÷ñ{[¥ú¿Ž:ªhŠVž%ETè+B´5é»m:¥ÀðÁærpk^Â+æι °¯æ«Žël—Å:ßïÆ~‡og ÉÐÕl±QE]YY]¸#¥Œ\‰¢ÈËN•…¼²ºˆ©–êDk÷[ºæˆ=Ë_ÜÛkÍfOëw€ŠÚÁ« Y ö€0¡ËD½.…HôѳLqóÍ{FœŸ *MIÔŠ0F°Œ„YÃ*'ˆ^fBª’ò©C­›ýØÄÿ´ŽÁ5;KZzšðÁÈ¥=òùštŸ¬UŸ¦0ŸÀô†o-aôPSV1SJ €)ä -~¦=)BìJѽÙšüü¼¯uzÇq<Ö|Ñ´A ÏL`‹)ÿ\ÛÝ7­lâAAæM?ÉÕ+ƒUZ~]T,Ç+}+ð"1÷(Œ H¶’ðJK1µ…€¿ø[Ü}º’dR@éÿÑS®Þê³ü4éÁ|¿qV°ÿ™c«’I$ޤBªÀ\Jœº”~Hö”˜üÌ£õ‘__ø¼ôÃUõ*ìpãÐßNõ¶ñ«4>µf‘Ë«KSƒ¨Ò¹hÚI#L}~–Pþ‰¨ûÊ]ÉF¨4­+@ãá?a>žt^3?€ªü\qü¼ú6ãdÿ½ÃIœ…M* šÂÉåÇçá¨pªCižzÊ"B^U$†U7öÜM´ád"Eœ˜øÕÁø”b  äÑO‘ëÖÚ„­§.H­<•?دGGùŠ ½’¢Û}âhöïiVl¼}/kmCþ_>'vPQÃy:¬–-kp•2g(ŠHÑÁS,а´ÊDZ&ÀןW¶°Oñí $x=¬ Ž"µ¯:8Ü •ˆ•"êÃΞ¢ž}k™–‹7)T&”VÝe1Ïvø ¬ŠÃý·¼¶°}Àìá®"qwáE)O‘#‡ÏªDÍáš!­<϶½¬zÒ ¥:˜ü)gU#‹ú¸è=ÁWßîEÉzøºò=Häi a–¹ÈÇR²"qsey|-âQpÚludy7¿µP­å¸-D®Hÿc¦IeA¥K-qåþtXjš٘1yÅã³k½ÿl1®›Soñ÷?XŽ‚šxŸõqëÄ iëÐɲ^»ÍJ#†Oªkmik\[H Z×·ûϸϚÄÊÊ ç?æ§D÷"3¦¬×£USqƒÁ©Ž›z´O«›ý}ÂÉS}ú ¯TOìûHüºFuø§“yÑýó%:ùý>PÏw¹úX87ûϱ…Í´a EséÓ–¾¡¨.¯ËýUê×3£OVÚ€‰Ò^B— AÀ:›•·ÓÚ ¢âØøkV§çN„Né[=”üú¬Ý¯6áLþDSÒM2ŒŒ­@·mLJr¡µÍ®môöžU€ÚÀc‘DšF¼p5òÿ-: ©Ü5¿ýTèäbk»øz l-iB©ä"®‹… r«€¿Ó§²ÚÕFÖkóý½Câöê8ùô;u-Få‹rm‰è(gªÜPî½µ>„Í oWš‹9—De’héã’ª¹cˆ;º"êÔÌî ·šBò(–† ƒÂ‡åЛnÐ&E š‡í¨ëhŽÍZi%ÎK«|„Ršr¥¼52WSÍQL¯š&4õ­$A‘™†¥b¶>ù¥Í+j›Þì¶’‡´¶“B+œñÏÔt*¼ Buw— l4—sGL#–©ÀóÈX”VRÈYDr4Œ°Æ?Mí7?¤Ø†×ýƒ¢èôêÁé-ÙÀœŒrU;†ûj¥žV‘#ã1ÁäÖ¨W\Yh”‘~ZSaÃZ“SËâ¨é™ôëÏ‹?jŠw91x£l}gÝ$žF©¡Ê†å+¨—›]µÄ?%n!ÚÉú›lwyô†úžåÑV…êÓwa$¤„K]ü[óÀ¯ÝÚuÈîË¢«Ëi!ZÆÖ¸âÀ1·]˜GCSœzLÿ ôPYK(1UãQþ¯^”{Zbw(¢¼¢,GV5 OÜå¨ûº=»îh–9²Ø’@X(Ž1i ª‹ÓV3I«ä CXò•ʽ(‹ .œ#ö×üÝ ,±¡Ûg'–D©Û#²É,‘Tdã¥ñù…ûœ/†AªÚW†±¸÷¾ŸîŸ“OO‰Ë^Ÿû8ô_»Ü´ñ‚rV£ÝÑQµä).2õÒQÕ(ÐYSø‹2*Ó}67÷){f\_L¨ÒkÃø–¼zÔDfÁ½U>XEýó¡»XýëÇ:ÌôúɵÅÁ&ßëqï+6=_DõÒãN“EþåGéŸð„ú°¦oX/‚§Q³x¿ÞtÇþŸvbÞ,Tµÿ)ëßo§Q ÿ4œ\ùÞÜÿû×·¥øÏúQþ¶xpéÖŸþIý?ö­þÖÇ?ÝôòúÜŸïÑŒÿ¥oðœK¡¿ÝSßéå§ôûy¯þñîÑü_ÿ¶œz+´Œ¥]¹Ÿýí/ý=‰3à¯Ú?ËÒYþ#Nž¶ÿŧŸòy/ý@ÒüûbïýÆùêÿ7N[üB¼: ³ñyËÿÚÏ!ÿ¹RûR²Ðw—¥â?oM7?êOü›ÿö§ÄùGÚ¿ô^§Ï¯ÿÙlibspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/resources/images/bannerR.gif0000644000000000000000000001741511021722676024021 0ustar GIF89aøn÷·ÒlªÅhZ‚ˆ›6d‰âóŒVh7EZ 9JºÕp¢½f³Ç‹†kÑë}(7 ×ç«erKm‘›´e¨Ì1ÛòбÌköþ›‡£%ìôÑbzÚì…†¤‚œWhŒãòªÍé|ØéšÍè€äô¢hƒq”a…êõÃK\,x“ÁÜtëôËêö’â󜔭f>b޼óôñAe—ÂÃ׉äô“â칸ÕX:U ¢>Ñ逪ÅSåìÈñûÒR|ÃÜx‹£\åò»Þñ•sŠ"ÀØi~—%íóÙàï§Íæ~ÛîŠ;Y €  éõ½\{ Dj`€Ðæ|&Õê‚Êät`u=ˆª2RmZrLuåð²íø“Æáy¤À@’¿ñýÍèô´£e*B0A~•VŠi™µ^ÉåyóûÚe‹ }©Õî€ÅàtðöÛ¡¾Kt—ÊÜ£]|š·CÊå}5J ìúÅŠ¹¥­—’²<µÓFÌÑÄ´ÊzUjÑì€QsêðÕiFïøÒæñÃÉâku‹K?Q×íŠóùãÉâ|î÷Êè󬓫_=\".ÎåzßÁuÖí„ÉázXu Œ»ìû½JcUr Mj3C)5­ÏC¿ÜXž´uÖê„xŽQïöÕy’Mƒ±Íâ–Hd :G"åù»o‹ Æ&æôŽÈß}ÔèB_ Lj 8O :Lr}ZXuÒì„çõ¤Í‘¯snë÷·j€ 3QÚê€ÌÞtå÷µ2I@TùþÜÚñåùŽ8S p’nˆBÞî‡Óê‚ÍâzŸÇÒâw-=½ðùØOdìøìöž/1%7[¿Ùrwˆ1-=ËçyïóáöþÕê÷†y–5FÐèw%!+ ¿×yv™˜¡‡|œ æèâ²¹¦ÙÜÓfƒ ާ*˜«@~’0Xxt“ »}œðú–f‡®9ÓæŒØìjfjPÀÞnm†M‡·Ž¼Ùíx¯Xí÷ªçðÊàñ‰ç÷’ðøÁ“¿ÿÿÿ1C!ù,ønÿÿ H° Áƒ*\Ȱ¡Ã‡#Jœ(pÅAIT¹ˆÁ±I«l•c DɆ åÌá@„K›ptáBT"Àµ!Ñ¡'-$"t @”@ ŠH“*]Ê´©S‚$Q¤J¦¥«Øº@Ò䆔+[^)S&ÍÛÊéÚ3PZC‡ð´®Ý»xó&deñÆ$49b)²«’r`Y:¹SðÙiuòl×!‚[¶EéêÝ̹³ç…ýf<3䀮'¨€Â Ÿ˜29*B«¶ -”ÝíÙsîçßÀƒÛİЫR¥h™­m Ò¥ÃFdÀÊsB˜xtL³ùÍ Øx–ÿ(A€–ùžíÚÕ,¼½û÷ CûM¾q¦Ö‘%7lP½²õ¬±ÅàÂlåä \TTê%è|FŸ|£Õƒ*÷18úñÇšv‘Fà6è„`y;EP‚zC±'á‹0r6ȃøuÃr*RÅ匱¡ðwA0 (àˆ%ÚW)’×S .Æ(å”MɇM ¸Š#mØájÁ SiîH¢7<ñæV 6%•pƉԌ5þE•r³‘Ó£—åx¦‘– ÙhöVYÞ0XÔ›r6ê(h}Ù©‘ Ë%±J)]æççkXq§ã …v “lRF£¦ªê?tÞpœ"1ÿë*¬3-ÓU‡Ã9çÃX 4ɺÊD¬s^ NPfÞmí@)«Fë(…ŠÐ7`V”Â8&õ¹Z)œ’vdÚJBQí¢ƒãE)í»0ÎhãTÖÂzE)hÈ¡·œC§v—íJ éà¡A-*€»ð6 @àóˆ bƒ%›´Î| ÒÏN%ö%ð„ Aqâ‡=Oë ‰~,ø=Å©.P4ÜDØ×U( ¢Aÿ ‡"ÆO4IœPp«`îp¶È@b ,ç6Y"\Úá„.:OTÈÊœ…HÆ‚¨P`›ßŒN`€)øÁSˆ£¬[D㈠Ÿ*ÈT[A‡¦â¡¡t”2ž0ˆÌ›"÷ÆÆNˆ_øÁ¾Ð‚YXr’˜Ç  =¬B&{œ MDa‹uèð‹kÊ kgH"2ŠÄ ü J~a pÃPƒ¡—»tÃfÁ1ÀqT(IùG4©(.W[å[y·Wªp ˜ä,r¹ƒ|üÁ½0ƒ8•Áƒ?(ã&0A „ILø™É ”s¶±Ž@€±S% MHÿM÷ecSÃZ° 7Bk(ÂZ„†6´íÃT€âÃLÄ=„q`ÐGƒÊ=‡"H²ŸÒˆjù…<  ½PF ±Ð„:´žÀ€NûPQ@Âs E(!Dˆa 5zÆ2 ³g¢rA´pÂóƃÒèýÓ“ÜD À‰ÐBTC¡kð„XÇšSRTù€@ŠI!ŽØÄ:qVܯÁ½˜žfuÑ L@‡æªº9•BrnXƒ50Яö!ÕëƪS³¢*8ÄÖJ ]<® À 0+Ð3Qª‚‚U“¶°Sè€`?ÿ˜¡…hh5ÖPOüá·¨lEU@Ü´úK‚°à7t£Àq‚„‡© a4OEÕ×v XEl¬a 38t·çüC9ÿp³‚¸éŒ¯Z×Z, F4*]£ž€ € ´»›Av×»BV j ˜A¦ù¨zyÐ….¼7³Ä=Ä!â›Îä®õ—XÀ¯<„2$ P8p‚J¨gÀ^P¹{R; ¼³ØÄj[Ójø °!<0‰.ð€š=’Úá%x8ÄPö€ŒÀXh!ûî'NP' #„)JíTklãweÃ-p„¬á‰›Vãÿ2 ƒ$$Ac K ð!~:,aNö”Cì)OY„@…RD·¨D$œGgŠy=d.s´¦PÉ5·¡d½=^@jIЃ¦°¬±a'/¡¤ð‚ ÁÜBOyÊ*-y ´D*Ár¤ç¯™C‡²5 / Ô ]øD1S ÷Âõ©·M:ÈÀ5ðó«kQ / âÜ….´¨ÜˆF¼C²`„Ô0„_K` ¬@Gåd,Uî2[Z'à@ 0áêTÃsè‚d íms[2€¹Ë-ës#BÝ" 6înxË;jp´~`U¼AABÿð3ýo9eã÷pĤ½ Ûá‡0EÃîp:dµ µÅc‘ñŒs<A DŽƒ'ÌŽ^1—pž¨|<,o9œ „¢à}ÈÇ!øÁátò ;ç9·MшYÇâíE×8  #©xB1Š¡†F€ ÂÆÔ'æËe]ëRB€$à]ÌaÝd² ~šÎCØ@í˜Gu#ÎMô¸oœîI'FòÎF@‚Ñ)&9%ÞàD%¬P¬Çéu H%ÙÀ ày h½äK¤k²¶„ü0بF$h‚4@PH…À ,ø‚KZ°_#w”P o€=D?ø"pC8‚†½ÄV±†KtÆð„PÍ@…UHú… \è‚y!†)àh-à9ÿø•°"í²†1~ P3@kP溠 wnµ ý ‡íG°ͰXúðŠƒHˆú—ˆˆˆZr@?€”ð ]†u‡G‰ÁÀ:y0évqËе`tÐÁWú°Öx ØèŠú0 ƒˆ œ@ àX‹`uxh ”3 Œ'™˜Œé6#¶Œ` Ñ(jGpØx WXÃÀ„Ø‚9@‹!ðe ÐÕóÐ ”°zÀÈŽ@™Ø 3Pwk ŧ ù¨<' wþ˜¯H…Ø|{e@o° bðËéÿŒù ÝÐ ÀEwk‡ ÀpÛfj§F’€’+ð¹,.ù’Ô )]0­p¢0l•P ;ùÄ(„”¨A€|·F”, w0’‡ #|’0ì`þx…+É\H { ðG`P÷`­À |ðéX–îƒð –»& „`‚,k°q±Éàpô þà…0y©v{Ù—~™Ú¨±ø…¹°pZ@}Œ9rÐ U€Ð}”ù– @‰ †G@mÙn¡)œ ”¥V5šþ`£Ö~&ÉP•9›Uÿ¹Äp˜ºéQ7—Ð –}ÄYœáŽÈ †€ˆGМHA` ­I>škÀŸP¨ ÞùáùŠÛ¨ Q€› Ðý‡ž  »` ‘ùžð©aœö“)`˜!YHwxéš\p  Ph •R¹’H   úŠbÖ‡—@ ª“Za  jPÔðiÎGš`ЦÖmÒqÌÀÞ¹(9£ÛX£¦†I‹º‰b ƒð£Á©¡CzEŠf?™¤ð Mº…H ¥é𧦇ÉЧ~* š`‚:¨Þ©’¯ˆ€¨v·{ÿðã˜bhºž”° ئñ) p )PsÚuŠÚ@<×C€ ¡à„ÛÖ§ô hЪ­jC«²:¸Àðû°œP C Mz˜ePbˆ¦Èp–€“Bj©LQ¤Gº©sºžúQà¢%9Ø™¢/ ’à s±0 ƒuÃé­ l©0:T°ÁPpð«@ a©ƒP¬ÇJ9ÊÊÌÚ? °¤ °iðs©—™€ýªhà­ÞÚû°+=@C@ Ûpv¯e0¯gŠÈÀ ÷𬠑 a²œ²¡² Á²0R¤ï˜‰ô)¢RÿÀTj©Yyš­Þ€±ß*g0´D;´Ý*l° WÐK»0=°±ip˜`h¦!Ûžøš¯* ƒÐui©qðI¨ª—CšùÀsm´Þ ¦p p·¹p v´p`vp û´i­G5 àȲ½˜µZ‹E: ˜Y àŃ9p³( :ë5 ¶@‹Æp ƒ*¨ZÊl´làû`îзvPž ¸58¡SàW‹¬·¸yQ¤ÿ ˜˜Ð°wÅð6г—¹›»”?+±h ¥Yð¼YÀ§P· Ã+0û@¬+zOp€žÑÿe‹€ _¹ Æ»Œ+ Ò0½û»{÷™p¥«¹< m0[м1ª¥¹ ½Þj§€½þû´9pŒð¨€‰0 Èp Æ*™$‹¾Q¤Ò`>©©¹Pzœ€vXÖê€ÀsÉÀ¨¦½Ñ«pP@Û T™½¬›ZJb ‡K :ȦŒ|™ýªÚð|¥¦š@¼ø¹À¥ÏËÀ·@+vÃIl9¯e°ˆç´«¦¬Á?üE¼ ¹Dܰ  L¬v2PªI¼£Ì½æzÛÇÛ0®8 ‚¨Å3¸aøk‰pÿp »¤“yÆOQ¤˜à ò ÚÐÔÀ—Û€š [jt  YÀ Ì`ÃÀÐÂÁ p 4:ˆ„,±v°t† ûµbÙ°Èìù ùŽìEê'€™R  Ü~É€šþP¶¨¸¦œ6€-,p Y˜@P솼˜‰ ÆÈ° 쉬ÀÌË*  ŸpÁ·¨£Ô ªûx¶þ0Ñ( ýP«Y€ ÛÂlWÈ H ‰¦âÜ·î`þ‡bºxP°È¼  ”:–îÜ Ï\—™Ð KúÆÚ|ô0¿°w H gÐÂg úp 4ÿ0Áp:ð -±}z0¡€  ™úæÃ Ã, ‹÷“>¶ˆ¨ ýК¥&ùàž þ¼¨@0}Å}¹ؘ«)ðÒWÀÀÓãÑ)–Èã» p¾œ5Iý΀ Åœ™ °©KJ ÀšOHМ ôp©À·ÞzlàÐ0«²ªsqÖ0Î4]dð ðL¾”`r>ÔÎu ÄÃŒ = ¢Z°¤O@ G  y8gÛvÒ0à¡ ŒPº [E›Ûgà,=àÊ”=ÀT»c8¾— ²–ÀzEÚK1Ú£d`ÉR@ qobK š` ý ÝÖm*à*ÿ` ©@½ ˰};Þ  ÓÀbaŒ ã ‘UÐeEÚÊ=|×S  `Éj †pbÛ@Œ`` ý@™+ Ú@WðàáþàBk°ð’ ´LK @¸b0 Ä-²¾˜5DQßIÑÑîÍÔí›>ðß­Mº|Oš`àk€èª<Þã>þã<> ÚLglÀp€‰#gP°m¬c RN–&Äê‹ Ü~PÇÜ ÊyÚ¤QÀ €[šY¸Ìð lþ áWHr¾Ó/yŸŒ¬)@¸?à‹â÷êb¸aU.Úð¼ÜPÌ>ÿ ¹) œæi•Cž @„h¾à à :ˆ…àX˜doY)CÐ~ ]Üe8xú&%0ßð '@'ð €ë³þ±Þë¾îë»ë¿þë´>ì½Î`Ânìß0Pë·ž¹nìc°ëQëÌëPÀÃ>É~'ÐíÖž÷mèð Èå‹°úÄ ò ð[—®éÒ:æa*­¢wµh óVoÑ% þÞ<Üê_¶(xšÛ>šx0ñ /عñïÿð¿ñ1ñ!âP _òx@Ÿš®€uPòØÿiñ/ó©ù 16Oó!ñ !ÉÀ Üàl^»×Jº¤`NÃŒJ CN QЖ>°aÚ‚8ê¤/ކ€ Œæwd€ð}¾_‰µ ÒðEò@ÿ$ïáîÑòr±ís/÷áòw¿÷#Ÿšá°÷)òøxP×¾ñáÀóþ€?.ß÷lOøxàì=ßø€Ÿš–?)ïñ ÑÑ`èEŸëžIÊ©`ΨŒŠàh˜öФòõ„°]ŒˆhAI})vÁÖç´+â>ÔfOh/ù© ›Ïëo ÍÏ$ó‚ïÓÏ>ïÒ_ÿoÑ/ùÛ¯¿òPqó÷AÁîMôÎVú‹Ìy´ê†)°Mš¢˨Ž‰Çªn òP¨Ó¨E‹\ºDé•“v4¢+A ]»xüùƒðÏä?#Çô'îä·‘%OžéoæÌštêtÓdJß|Ö¼IÔçLW#¿ ‚1ò„Ï‘x|ÀóMæÏ‘âvB0pôŸ+qufŽi꯫O˜$½ #MšƒEP œøÑBA R Òb¨`ˆ Ž †šù²Œ2ÔP#…+ÐA{„<¹„AK,0‚h™°Â ÄJ­N˜ÑŸk£)Dmúÿ®·ßÊ ÇªDû†»“NHQ7ælŒÎ'`À£6 „:ò›²>ýgžŽúðÈ’t`In¦b”yÔ @J*S°²/CȤ†Ì# ÄL4°¬†ÈãL ˆHN^°ä•Jh!<;  »ÅðÏ«€¬ÎPNQìB5É€²ÄIÕ6t½T)MWüSÔ{q4@¹å(ÍqUýdÕU¸˜ä=(×k/¼ÞƒO2Éàó¡›n@¶ÀÄDÖE¤A¦Цu"JÆ3‚(ì–€osô$ØXº*¼ðˆ¢9¼r£ã‘Ç“Â5ŒugÇ€›Ã¨©hš“Šn+”6‹få<ÝyÆ1pvÿyÇ‹«:¼At‡Ç•`úEnËË3ïà)~ Cõ¤`Jcž»‚ à– …/:avÀ¡9¤­âÚaÂä“SîVÛ–5<±,rÿ1JÞy© ¹·ƒ÷¨äü£ê¸ñŸ çé]—UÇÅy]B«l³Ýzu&ÇäA8øA‚¸ÙÃï[oU …:™b”X—Õl–áåð70¢Å ÆQN¹#ã7"M:ü£Æÿ&ü±~óê{IÛÇ7Ðß DÒwÙ?ÊÃojôi~òOeßýo˜H|”ÔUÌG@°.CýcxÄ£$µ™GV˜„ü †$¢ö–ÿˆÂ'`žóœç, `ËM$^A'İ43TjxCæP‡;äa}س›½%"ÿ)—Ûäf7sH¸]ÊAœãl¦/ · =D«A'°‚–ÑÌ]ÜBžÏ˜ç3V1‚mL–ƒlÃ5 P >•À›%hAg’]fcœ •Ã.þŒ¸Ó” Ä2â![T! §|FG;zƒg¸À øÔ'ãHÐE0þse5hK]jK].¬`0l ŒšCV°E)ôð†7¼Â¶°Å2n¤©K]F„P rà 3Œ¡ gˆÔ #5•xiW½ŠF]ÊA¡9Æ nPÖ$øQØx…¶Ú1†m¬2ŠˆA \PW$Á"-ŦéÅ“tŸ†œe·¾zXÄî0¦â¤iYZVEèaêDXG:€­1”£äX…*šÐ„ºÚU¯1°B_ÿêÊ“–°ÐXšXØÆv:`Å8YqV³&IP…d)Ë„th$³›m‚g›àÐÆ@¯|-Ç_·˜ZWê ‘Úêˆl­{ݓЖpr¸­cu›„Tâ•ÅPŽ 8¡¸Ÿýì]GÍæ²ò¹Nlž¹Rìæ7¶´­­{ÔÜVVP%6˜­ó¦w½íu/]ß~j$$ ¦+·…_ýfø«aåncÉzÛeðt˜*2{&,ø®{½* ‰‚r(A¾yš0}¯Õ¸H´ce;libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/resources/images/NamingException.png0000644000000000000000000017642211021722676025545 0ustar ‰PNG  IHDR ©2‹o+€IDATxÚì½ÙºãÔ¶ëÂ×]ÿíSûÔûdƒiE[**”€€èLgªˆ“AˆóÑ”ˆFÁ€Rh‘0öl$Y²-ÙkÕ*ªYßû±É2˜ À¥îÔ§ƒ>õz:ùçì×÷èX¯GWIØç”Löy4OÎsñ}ÒX>Ǽdës*{Îl<—’¥ôÈð’ç­³4{C¡yz1¼×ú»ˆp.$3R G7t†ˆ˜è=ÒÆAËù&rògùg3)úÜÄsî’Wù¨G¿ÙI,x¢ž«bA–ñ bÁd8õ( CZ,ìˆèÂÄRVmV±ÎÀÖ˜PPIg-ìžbQR]×—­å¾N§N6Ͻ4¥±®‘å84*¾›²Öìd¨Ó8Ø“­væˆGÎŒ U~OÑMZ”¾+ hØWس…˜È4TعŸ®åÍõF¹4Päµ¾VO§.d™lwN¶Þ/ò´(Ìv 9y£N=ͦRætåÍŸ·6„dÏ¢>³ëØ/óKXÙÒm_V7öÈ`çe=µâzk^EݬÙf{®Û¬þ.X~ÑœFZ¿Š~˜NÐHw£Í …4äŽjR27„£˜„¹t!!sZ}î4Mrç>}üAó<ÉS² §¥[r½s·{tìŠÒùÖî›SrK:âC"‡tÅy×ÎWóNöîW ‡¢È'C‘él VéHGc–§)>¼+d›X(º)´ñœâЧÙÌ—‚¬;oUÔß¡ùÜ%—9r?L—NXãeÑÈg§ºe¢‹¢H“wý8þ‚žK3/êÎk‹=×l–×ÞE™Ÿj’E4ŸŒD:#7î¶b€Ô3…ós)¼5kÌËf3ÙÌY)–ßr.ûûUË«¥Ø <²0˜.»6|Keù Hè‘UçÝ8oæ%ËÙc­ôâ8¢™ÁZä}SFAVÅÿž1kˆÅôZÅ‚U‰y_M)JWmÔž·Z´æû}Ù*/#²N؆¾Œ Œfq#M;È6¼–¼¶Ùsíý,ß…L·_K‘ј •GO:l€XGœ¦ƒ">Ð` S¿híùR ,Æú9w*¦Ÿ¶Š…Õ1 ÁX_Ü –›y¥¾½2ˆ°ÖM°"šeª¥³Q,$1 Át´ì0g"²°-o‘¦ß>.#œèÕwJiú–i+¡þμ¶ÙsíýÔÄ‚ÈO¡úð‘€ !D:l€XGœÄâ@7lÛ6Ùö˜ÆÖ°ÖÞM,4®‹³æ›·„GÉftÑߟVåQÚÄBÑ2v7EÆ7ˆ…e™šb‹Õª šÌe×C£YB®5¨ZþÛò–en Uwƒ<좮e¡ìòiFZòÚfÏ.± Òeb![ E>RŽ3é°bmäÀÆaáhš-í*<Í?§”ä9цómbAô…k&ù1K-öD7GoT„»ó…8×,—⨸ÇÅC­ £Ê«˜ÙÓmZ$)eiL¿(Æl }áø29† ?¤¹ègÈÈ/" NÌói6ó(a‰&ÁxÙM°%o9§( ) å‘È›Ò!‹Ö{ñ¹§ÉÖ}™¦jÏÊ’Dy~Ü×6{®½ŸÚ»HæBÔ¨†#¢±?‘Bq²Øb3Ä8ÂÄdÔFà× §CѺåÁ…`2l¬Ð<¯õ÷×ÄÂɺXàôTuRWÍÆ(û¹¥U÷ôÑH8°²›`5ïtáHGZ¢UL+ë,¬–©WQÎ@˜ËA€µt†“"ÒP:êâP†“jfHWÞëë,Èü#g(Ê^ SÏ ç®Od÷F0­Æ;ˆüÊ(J[^;سi³ú»`oÜ/gzðw_‡m6@,°•õâÍ·ó˜Ë Á`@#Ë¥ jˆp)òÝwßÑõ×_¿Ãº M}êõtòÏÙëíѱ^®:SlÍ>Î÷^ÕέfåÛZ±íuºÏDå¦M=c¾¡^|{oUììhŽm2ÌÓbφòÞ¹ÓÌëÜlR?äîžC¨bo¿ý6Çãí&³jëâ¡6DÄDï‘6ZÎ76¹ÉŸ9äŸÍ*‡kxñP»äUúu¯ÚÒy0­—?¤aqÝô’}ço+=êÛF7ë•ÓTç÷ü ÷èêz®éñ$=±ýõpêQ†´X,Ø] Èy¨bÏ<ó =ÿüó[Ÿ Dë[%9ÇžbQR]×—­Ò¾N§N6Ͻ4¥±®‘å84*¾›²Vãd¨Ó8ØbÁbbaäÌÈPå÷ݤEé#²€†}…=[ˆ‰|AC…ûéZÞ\od‘KE^ëkõt–b¡§ò2·«4¬B,äÑœFZ¿ji›ÎRŒdá2}u0i*•XXÖ+(¢½~Ÿú=^þÏjuæ=ºRå­Ù¾p˜®¹¬“¢ä'›íì¥{ÍôZË,ío»s²õ~a_‹ÂLÚ„ @kC¨(ñ,Vn•Ù¹|Ó KG!Ýö;Êßaÿ¢Öló{>/õ@,€ÃÁ¶mÑ¢ìF¶¾5Ö"Oæ†øAž„rñ¦”;OŠgŽÁûôñÍó$OÉ.œƒnMÈõ¬Í¸GÇ®àÑÙ QÝ7§ä:–Œ` Ê‹ˆ€Roõ×ÎWóNöVW ‡¢È'C‘éÔ[уÑ@äåD²ü΀=?‰{"L¦ÑSMò£ˆæ“‘x~äÆB¨ˆ{Ìႜ±«5±PÖ+ gBHô6+›GaZ«s™GO'Çg­yÏ¥™ [LM“fìZèOE=Eg­®ù†ô6•™‹±Ò9ÆÌ¾¦ølð¾˜Â&ºåÐ|î’˹¦K'¬ÉnŸ™*œêB,Š.жògößòžÏKý àÜáã®»î:úïÿÛù\ê™ÂQø¹î«~zŠW,¿åœý˜³sÕòj)6Å,Ô»|‹÷õHè‘lE,4ΛyÉröXk8¤8Žhf°–oß”Q²=Ÿ á£Ú¼eê‹kߎ]‘F¿ÖoŸÑ˜;#Õ¦Ï|s¥O?uS6ˆ…ªlU7DMHå´ƒ¶æoNY’©tÙy5½ÍeN û+Ƭz¼ÛG”¹ " З­ò2r “)Æ4ôea4‹v^-§ý·½çóQ?Ä8w’$¡Ûn»mËS9ME¨y0 Á@§~Ѫ ò¥Xþ8¯ŸóoÓO[ÅÂꘅ`¬/ò±PEVòªw)T‡fË.‡R, y¦tbsgÈž±(e-×2ÍÔ·DÞõ!wjìù×î¥b¡ýžÌCÝ0P4¡©Qt_ôú+Q‹mém.s²fÿZ:¥mýöñ"áD¯ìX·­üößöžÏGý àÜy÷Ýw顇Ú¢(\!tæ±m“mil k-ÍÝÄ‚Ñ<¸.̚瑳FÉæjѯžVåQÚÄBÑu7E +ÇÈòYŒ+g¦OXK7÷—]žŒxÙR,ñw|¬Ågk÷V[±;Š…¢^vå”ÄîH¤? åÉq§]WÓÛ\ætÍþÄBÛàÒª»AvñÚÊßiÿmïù|Ô±Î×ué/ùKç3r Þ°øA_¶€Å”Á2 Ì?§”ˆM¨ÖÏ·‰Ñ笙äÇ,µØÝ½QVÎâ\³\Š£â^5q%¯Ì—ƒu›IJYSà/d‹¸á£bDáØêÑ‹d.>«†#Zı?‘bi² <œÊ‹éP/h<ì·ŽYèŒ:”åT ò£”’( Ï‹V¼ÊÄBB‘7ù*†Kyév­¥×Qfjq¦ýZ7ÄpêS…†òH¤Á¤C­÷âsO“­û–òwÚÛ{>õ@,€sçôéÓôÆot<‹µ´z?vA8 g˃ Ádؘ£ß<—N`U,œ\qª=U]†®U³1š}niËHÀh$EÙ-±šwºp–³zeëséàÊEÌi6_HGÌv̵RKC+œdzÕõþÀ ¡áo¬ÐW Ë{ìn0­Æ ôÊÌ)êµÆPm ÖkÖµ™^{™Wí_Ž!ñ[ÖYÏF¢‹F¡Y¹Þ{V8w}"œÿÆòS‡ýwxχ^?Ä8wîºë.úä“O%­;—ùsËosòŽrîÓj"¬‘G&ÒΫz”Ÿw±k{™Ï›ÊßfÿZ7DžµÚïâªbˆ•·Í„àpHE”jˆ)@,€K.n¸áüJä-ŠRD€X— ¼ûáî»ï†!@,€Íø¾O?þøÚu¾öß…òÊ+¯Äã²8 à€lš6Éw ä?®ÿ÷ÿþßv¡±.kþøÇ?ÒË/¿Ü¸vÿý÷Óïÿ{Ä zðÁéý÷߯Î?úè#:~ü8ýüóÏ0ˆ@tâÄ :{öluþè£Ò«¯¾ ÀX¾ÛdV,šÃÇ*ði”?þø# býðÃtÍ5×Tç<¢0™L` @òÅ_ˆñ %ãñ˜Þ~ûmÄ|øá‡bæç§Ÿ~¢k¯½–¾ÿþûí_ÌRŠ£˜â8Áúü"£ùĦ©Ãˆpqóæ›oÒOó-‰ù†RÝ$äúÚî„=ͦôBWfmçÄ> L‡.ÎäfJ=cÞRöå=:ÆÊsÕìå€X8’¼øâ‹ôôÓO‹ÏÿûßéÙgŸíl OtéȬY@iž‹ þŒìñœ²_½ô²<Ú8(N=±UòpêS45åÒ#÷bl½gd+=ê—ÛVWe÷XÙCZ,ìˆ.€M7Ø•rògùg3ü‡@,Ežyæzá…Äç‡zˆ‚ hw!‹±p¾C'ju2®¹Œ:(šA~²lIulwN¶Þ—÷u‹ÂlÛ=檢9´~ÕÚ6YÆÀ®E8ú:y±GJo}\6Çá€áe–ãЈ9éžb‰HH[Ú"_–ž¡+UšíËZF. y­¯™´¨ùÐÎ{áòž:’V•MŠ^vË_wȉgQ¿§Ò¸2fÂê¢^”gÿå,l1›‘¡ïJ_Þ_³kºG“¡Nã`¯ó}l{ˆp‰rêÔ)zã7ÄgÃ0(MÛãÞ±kçàµ>’²Ö¼I3A¡?Îoà„Õ=«tL£1¹Ž)>b›âŽ{Y ÃóªI~Ñ|2ª¢)w¾<”Ï¡;÷)Ù+Å‚ôNᬙ‡]ä¡[r½åiWùötrX}žK3/ª®+†CQä“ÁñÀ)~ǽ|!ÓcÎ3ä¢J]‰,è–Có¹K.sä~˜.°ÆË¢‘Ÿ³zMùwUÙEqrÖmaN™½-a7~Ÿ>Y³k¾GÇ®`vôºßG÷;@,€K–x€>øàúúë¯éÖ[oí|Ö3U᤼­ýè9eYH&³—}òÜ‘(ÜyͪsÞg_¶úÛ)Æ,ûî3s‡¤ò12”¯X~ÃáöE:?Þ¢LŠ1 2Õò–Ò¦#íÏ<éèì Ù,N‹ëc?¤8Žhf°}ßytÞóÍ•1™¬óŠXeîËVy9÷‹1 }AÍâFyöSNa fßÁ4¬ž÷-þnæ²l »ÒR,t¿®w €X—,wÜq}þùç¢ûwCt‘xÒá¹­ Å„¦†V .l´œ DZì"Hkβý^ê[kÑŒ€;6áøÒW3Æ4:ä-âFÔ£™u¦ý±¸§Òj¯@êÛ­ƒ;»ï­æµ^öfÊ:áD¯ÒÌuØ_9K[µŠc½&fVÊV [ÞGû;@,€K–›o¾Yt=lÜÈ#éÙ'nmþñÝ‘p$3ÑIÓ¸á(J•´Š…M÷ÒB xÙ2j!YŠ1mwS'ùjÔ™vY˜„ù†{£`Ú~¯ž×J«»,{[ئên‡]8äôå\ §¥›GFѱ°å}´¿cĸd¹êª«Äú ?þ8½õÖ[[ž^ΆØ.ÅY&fCó ‡z{"ûÒgaB‘7¦¾è3w)ï ý± î%sáDUÃ­âØŸˆtõÉ‚Êpzo8¥$Ïk7ÙI,t¦ùbbO5ÈRJ¢€ÿö·¿ÝÛ‰i2ÒÖBÜš1£œ9½6ŠÞªÍAŒ‰*úŻðPy9ÕšÁd¸\“ –²M,X«baKÚi0­Æôj3Ò…#qy3+¶ÝóìAu½?0hX«ãæudy#g(#6e¯ {V8w}"œÿþË)íÛSÕå=ÕlÌZhØ5Ý£“W,m×n³î÷€X— _~ù%Ý~ûíôË/¿ÐÕW_½¯Í£ò”9±X®àØ\À1£„µd奜Òêó¹’‰î’M«EæYzŽ«H¶§-êÀîek÷xÝøê•Ùæï´Üãeåö9|öSÎZ7Džµ–§Û®]6@,€Ë†?þ˜î¾ûnæ,’­3!ÀåDJïòÀ”FÄØÆ{ï½'6Žzÿý÷éÁ„AŽ 9E‹€¢QÄØÂ믿N§OŸ¦—_~™þøÇ? @“—^zIì Q_ò¹ÎW_}E–eÑ•W^‰Ç¡ˆp‰1›ÍÈu]zôÑGéí·ßnÜûöÛoÅ;¿Ï@ G?ýéOôüCDêÓ&ùº 'Ož¤ù|#€X8Ê<ñÄäû¾Ø@ê»ï¾«®ó± ÷Ýw bá¨Ãg@¼óÎ;b…:<ªÀgH G¾Æ,?~¼ºöÉ'ŸÐ‰'` €Ä꯽öšØ¦º„ÏŽøÛßþã€XD7Ýt“ÄÈ×Z(¹í¶Ûè‹/¾€q@,cê[Ss‘°ó²ÏYJq$÷†Àþ±.CøôH¾=õSO=UM‘äÓ(ÿð‡?lùfBŽ¡¯íŽØÓlJ/) ìÑ1Vî«Î$Ozwžä»>^Žö@,€‹>U’O™|ì±ÇÄŒÎã?No¾ùf—7£‰.˜5 (ÍsÊÒ„þŒìñœ²KÊ9ù3‡ü³-µ´…6)=ž¤'¶šN=ŠÂ‹;¢ d×óP?ĸ´àK9›¦I¿ûÝïèßÿþ·¸vóÍ7‹([ÝÇb,„ÂЉÚ]p4§‘Ö¯ZŦS:›”ƺF–ë’YÜWG%±Gþ š1¥d¿Ïf»¦Ð8(šßù‚† ;÷Ó*Û“­ËtÝ¢0“-åÉPgßÛ“_ciºRµè5ÛÓ5—QE3È/ÌصèJ_'/]Io‹6–‰‰… 1Ý!'žEýžÊê•Tž1+¯.ÊÙV~–däÒ@‘×úšI‹*éÂÆ³jQ?}yÿ¼Ô±.->ûì3ºóÎ;…`øòË/é›o¾b¡‹Ø5„cðÚÂâÌq‹0ºj’E4ŸŒ„³¹±p"Vá”4sJ³©Q9£íÐL8§>ÍÚß³©t°¦W8ÑÆù2e4&×1ÅgClͼGÇ®`Ÿùse¹{:9>kÍ{.ͼH|Êì3c×B*Ò8¡Ì&dN˜ æ€Ý¹OI¾!½-vX+SYÐ-‡æs—\æÈý0]:aO#?' §Üªì¢h+q]1Š"Ÿ .N•ž]”Cg6vKÔßÏÏWý àÒâÃ?$Û¶éÚk¯¥ï¿ÿž‚ ÛUwᙪpPmb!õLáÄ—}ì¹ãPùxæD˜³Rm¯¸%ú`²(Î}qn”N~×g³±­ˆ…;ËYå MæÓkˆYîÙA[ó7§, ÉdiõyU7›§mùÅùjzÝvØX¦B,ˆ(@_¶ÊËÈAYoá¤û2‚0šÅ5»¯—¿¼>öCŠãˆfû^߬¢7Ëw0 «ç}‹¿ß…ùyªb\Z¼ûî»ôÐCU«7òµ¶­¯'¡ÛÒHL}k-òp$”t¦ŸVN;ÆúyÝÉïüì± ¶¥S:²U± Ê­Òzô?¡©¡Q¢;¤rzõ´hCz;Ú¡žNY¿}Dc8Ñ«¥YÃîëåO}»c ª,‡Q+d0Ök*ÏCý àÒ‚d|øá‡Åº þ™GºÈÙ5`y‘æD²e‹\ ˆT,Ñâ”ÎiS`³XØéÙ´ìç/œSâ¶§Ó&Šø$lNÝ‘¨ÏLt¸ç4n8½gº;l m¡›ª»AvQç¶ò—€Íâ®têK…Ø<²0¢è|Õ±.-^~ùe±55·À9v옻ÐÍr6ÄÀv)Î21"˜Oh8œPšÌ…³S G´^cB}JÝçI,ä ÃÊyⳘ­Ñ!ú+b‡÷5Ño¥”Dy~\´âU&м±¨‹b¸”—iñ>ýá”’¨¡Ö ‘Ë:nLñ¢ªbüª8Ž#Æ)ðùΓ|A&p”HÉà]˜Ò€XmL§S1Âu]±?Äl6ƒQŽ9E‹€¢QÄha2™Ðý÷ß/:ò®ˆ×_F±–ð˜î¹çzë­·Ä’ÏüñÚ3gÏž¥“'OÒ•W^‰Ç¡ˆp‰ÀWoäÓ&ùfE7Ýt}ûí·kBÿ°ó)w›%b\Vp¡pûí·‹M¤F£ýòË/Õ½,ËÄbMï½÷ bá¨râÄ ºå–[Ä|3©:|Z% @,an½õVºîºëèwÞ¡x ºÎhâÝ| kbásà 7ˆ1 žçÑ“O>Y]ç{FlÛ}Ä8ðåydauexûí·a  G>˜‘GxWÄþðzå•WÄu>°ñÚk¯]ÄÂæ‡~ k®¹F¬¡À»þõ¯‰ë|Í…» ²”âHî q({ä19–AƒÁ€F–K^@,€ Çwß}'Æ,Ü{ï½B0|öÙgâúïÿ{±¢c7 9†¾¶3bO³)=‡2¶*v74Ç6æi±oÁUg.ä¾{tì\˰qI¾ƒãÅðWpõ@,€Ë—¯¿þš ÃQ>óïÈ9vìÅqÜåýh¢K§gÍJó\ìö¸ðgdçç ÈiÊÒí›~uîÏòÏþšñY7m^Š­´‡S¢0 `-ÑŠšœ‡ú Àå 7ß|³Ø⪫®+4òo¼ñÆnw³ ¡0t¢v·Íi¤õ«V´é”Î)¥±®‘íÎÉÖå}E·(ÌxTA“Ï÷ûÔgߟÑd¨³÷d¾áŒŠ)ê`DU¡á„¥›4ìó狦z¾ ¡ÂÎý´ÊÏrñï*»’‘k.£"ŠfŸ”‘Z´¤¯“—î5Êpzq± paå¯;äijX]UV֤ШŒu…t[ ¦<öÈ`çe™´âz¹•-úšI‹*颾³jQ?}yÿ¼Ô±._¢(ƒù”IYàðõ¶Wˆ]C8¯-ŒÎœ·»«&ù,ùd$œËÈ…Ó±J'6“ë˜â³1O(eb@ãÎo`“;÷(dŽìØìž—ˆP¾V¦ÉZç3k Ó0=–¤tƦW8ÜÆyJv‘ŸnMÈõ¬-ÒÔ4iæ/(ô§âÙʯ†Ì ÷ywŠÉÊàS’×Ëp°z•‘Ýrh>wÉeŽÜÓ¥Öø÷4òs¢pʹ*»(Êüz:9¬¬ Ï¥™U×ÃaïÐ'ƒ‹†S¥WÕל²rX¢~ü~~¾ê€X—/|‰g¾œ3£pÇwˆkÏ>û¬˜FÙ…gªÂ¡µ‰…Ô㎤_ë“ÏhÌÊÇ30§£pG7«œ›Ù/œ>{Îæ÷ªnˆ¥#+Ót“ešòY¯j¹Wb!kŠžŸjy›â”e!™ì~ߘ7ÓµÚ˰ïzbADú²U^Fd2؆¾Œ ŒfqÍŽ=²ƒlƒ}{4öCŠãˆfû^ߤ¤È×bù¦aõ¼oñ÷5 0?Oõ@,€ËÞwÎÇ'p±À·©æðùõ.áT”šã^ ¾µy¸ÃM:Ó_¶¬­Òé7>¯8²µ4ÓN± ÖÄB3?QšE—GO:oµÊs?eر^eùüöáD¯ˆf ;ª´Ú{‘úvÇÀRY£VÈ`¬×Tž‡ú ÀåKB,œ>}šžxâ qx,:¶‘/&²ÿÜò:" Ìéd˼)Æ ”Î,ÙŸX(Ò¬Z½|\ÂJ7„U:²ÄmDšùñn”‘Hk&:Üs7òÜ^†}׫3-v­ºäaõ(#“0ß¹Ù,ÖJ§¾Tr†Éˆ¢óU?ĸ|áë)p±À8:ŽC{{{B,lg9b`»g™˜ Ì'4N(MæÂ9ª†#Z»±?¡>½Oœ·t:ý-bÒ¹ å+CV^[Ž_(#L8 „xae‰<ñYÌÔh ²¯2±PäEÙÃ¥¼,ïÓN)ÉófZ¯j6„OQRÊ#Éj¶­÷Ò®šlÝWã4 ò£”’( Ï—×u›IÊlSà/ŠˆD1¶@3É™‹ {Œ–݇^?ĸ|yíµ×Ę…G}”žþyúàƒªîˆíÄ4ikáp͘ §3'¬4®;U˜ÜÚàtTч.çÕÅÂÉ+–Ϧ GÌ€£ôgb`_Ù7?·–eÑG#áäª1 +b;E½6#ÀªÁzÁdX[ ¡Y†Õkã: òÙÈÊ(G9S•=+œ»>Î? ¦Õx‡j@ga ­žžhý/óí©êòžj6f-zý àò…/¼ÄgC<ôÐCôꫯÒ|>§?ýéOûJ#O™Ã‹å Žë 8f¢KãPVväsÒZ:ñL8³ú8Ýh<³%:’°Vy^¦]}.r˺Ê}˜õÚµî)ekùñró•3ëƒjݹ¬ãÆ/ªú ÀEËK/½$ÖY°m[L™äB †‹“D¬æÈ[ÚZ¬; Zã5® ; 1¥±ƒçž{N,ÀtçwÒG}$º xWÄEë£ÍÝ™_áú!¡Ý»9 -ŠRX±¾%5ßâøñãtöìYÑ%‘$h‘€XÏ<óŒØŠš¯ÞøÍ7ßÐh4K>¯òé§ŸÒoû[±5mb\†<õÔSB ðã?ÿù™¦¹ö ï–àŽ€€Ü$$@,€Ë¾r#×\s ½ÿþûôàƒ6îóM¥øº Ÿþ9Œbá(òøã‹¨ŸÁ#Óé´qÿÔ©Sb$±pDá»Kò1 |<Â_ÿú׆0øòË/ÅL‰ü†±pTáS%ùlˆ{ï½WDÞxãêÞ_þòq G˜ßýîw"zÀ# |a&¾Öç—_~3$0ÄÂçäÉ“b¼*ð™¼ëÃ79â÷ˆ…#Îí·ßN·Ür‹Xæùꫯ®Æ'<ýôÓäºîn‰d)Å‘Ü{ ĸÌàÛSó]'¹8¸þúë«ë|À#_ˆ©›„C_ÛI±§Ù”^l-v}ì&ÔØrÉ7ÅÖÐéÓkÖïàxaëwÑ”§Ácå¹ê º´€X—$¼ ‚ ¾’ã‰'äOûÞžôÈÇ-tx'šèÒ)Y³€Ò<;>.üÙãyÃ!ïÓë‰tµqp®Þ³™NæUÛó„Ò9(îP™srç>%{2Åp(Š|2¸ó8Kç¢IçïçDá”;)U„Þ×Ó‘-o‹µp¼\ƒ©Ø±2õjb¡£Ìméé–Có¹K.sœ~˜Vå*ë§™SšMÊyl‡f™öi–ÈgíâY=ë:–pú¼Ž¢|+ù>õÿq':¤°Èi1ÖÄy”u—§ÍNU{:9þ‚žK3/ª®·Ù}?eNò=:v{¿^r࿠ĸ€ð™øN“|åF.8|:å¿ÿýïÎïy¦*N›XN¸_ë3ÏhÌÊÇ30§ pG4«œÉœ‹bzâ9›ß³üZ:=Ö*)Ž#šŠcP¹²¯¾¯] q•_=¦-ï £ÄN(¥<°*±Ð]æõôÊn~_¶‚Ë–:õSm¯‘÷`²¨ÊÌÏ…óäϲº¦ae;ßâ¶P˜¯×#_Ld×Ï ÓˆG-x¸¿³<ív*íkÙ†÷×f÷ý•YŒY(ÄÂÁÿ. à‚Ág@ðÙO<ñ=ÿüób£(¾OÄ?üÐù½Düè+ä¶4úRßZ‹<Ü¡‡#€é§ ç*Bý3OÇÞ:€2œèÕõ¥Ëk¦S:lS(+ZÚrÝåÇmeÞ˜ž¿I-­Ô¯päõsY–¤zÖ¨eŒõÚàÄ•|YIøó½‘K©è êËwÐYžv;É:«´Ú{Ñm÷ý–¹&üw€XŒ«®ºJ räc^{í5:{ö¬˜N¹²…«Y^Gd9…Ê år@¤b‰¤t6Év±P´DÛDÉ2Œ.»ÍÑ44o”Ïdè¼W–i{™ÛÅÇf±PÕo5ï bÁ¬yëÀæ­ôE-s1‘ŽYã]ºìNé.O»ÊÂ$Ì7F†6Û}¿e^,äï±.|ÇI¾«ä}÷ÝGï¾û.ù¾/6—ÚÎr6ÄÀv)Î21"˜Oh8œPšÌ…óR G8âØŸPŸ‡ÆE(~³Sè—b·œ‡SJò\„ÏÅÀDݦE’²–N¯H:˼žÞúºÍqK±àËn¯Ù-!Ë"ëÞSÕe:ªÙ˜°jÞw½Æ@ÇÍë,È2l³SL+ñ!–Q»ï¿Ì{tòŠ¥=úw€X>.wCðq |ú$ßâ‘G¡ ØßyÊR,Wp\_À1£4M÷½²cž­~'§4á+Dfç˜Î.´—ù`éuQ éç{éõˆÉè¶ÍE³µºm²ûAÊ|8ˆð+ó¿ÿýOˆ]àS(3æŽ?Μ~ ãüj¤dðîƒ}LŒg²Õ>‹/2 À% _©q4‰ƒ‹Þ-Á£ ü_ðk‘S´(Jwoa§ñ‚‚E|I•±.Q¾ùæ!øÒÎ|%G¾ã$ïŽ €à«¯¾b >]ò_ÿú=ôÐCŸ}óÍ7Å3¼ËŽ u À¯ ›P.ÊtÏ=÷Ð?þñúãÿ¸öß+‚¯ôÈgKðE›ˆ…#ÂçŸ.Äß‚Gø6Õ«{B|üñÇ¢E‡A Ž Q‰Á¦iÒ©S§è±Ç£wÞy§ºÏ·¨æë/¼þúë0ˆ…£p±ÀÇ"<õÔStçwÒ§Ÿ~ZÝçÂo*@,Q>úè#1e’‹…¿ýíob #ŸNYbÛ6½ýöÛ0ˆ…£Êb±báĉôâ‹/Š(ïzà|ýõ×bÏ h±p„áS%ËÈ‚ëºbìBÉsÏ=GŽãÀH Ž2|>Ó/ñÌ7âÓ'Kîºë.úðÃ/\áò˜Ë Á`@#Ë¥lõ¯ Àù‡¯ŸÀÅ(ðÝ&Ë­©¿ûî;±ªcgD±…ñ1ïüìترÐÛd˜½Ú8?-ö&¸êLWÞ{tlë3ûdmgÇ> ­¥—ãÇÆ],Ë]//4çáÝ ÀfÞxã !n½õVÑåPv;¼õÖ[ôðÃoq&ý漉…œ¦zú¦ßzîÏòÏfilf«Ç¤ ËWUùVÎéOQÐÄÐ…mn{}¹ˆ…²®«k(Æ·,ъ謼‡Cy·ˆ°¯¼òŠ 7ÝtM§ÓjA&¾Šã™3gö!RëÙîœl½/¨¢[fò‡Ý›¤”­SÍ–-ñ, a_¡qP8Ú|AC…3ÇØš|¶ß§>kÍÞtÝÿiœƒÏh2ÔÙ¿ræF{dèJÕÖl_´>ëÏd‘KEÞïk&-*?Ó^öÀÖ—­ê¾Nˇ×Ã,ÅAî±ò°óš`jϧÅüN4§‘Ö¯Zï¦SŠ“v•嶘ÀñüK¤·Ù(W&ëjùë9ñ,Vo••£¬wÂÊ¢^äµÿ2u™ÍÈP{Å;XÞ_{ióݶگóï±v⥗^ùöÔ|A¦rñ¥ßþö·bÁ¦ýˆ«ü‘ÉuLñÙà[g¾h¡jã9Å¡O³™/[§iáxKG[;OÙèâèlrç½ývóÜa œÊ¡´•= ™sësj²|}Jödk[”9OhfI'6)½OW>mv(˯šä3›Ï'#‘æÈ;mÄËmåÖ­ ¹Þ‚ò6[¨\²®ºåÐ|î’˹¦K'¬ñ|4òs¢pÊí Ê.Šƒ”¡^sÊÞ%Å »Ï÷µ\{ù†÷¿É~]—ˆ°Ï?ÿ¼ |Éçûî»Þÿ}úþûïéšk®Ù>erU,(Ü̪“ý¸+¦WµP•Ñ”¢´ùý†#lœgdóôªn‡Õó¥³H=éì`µ¹¸þÌØ)Ž#š¬ÕÛ7))ÅB[ÙË|-¿*£¶ÒoΗË`wæÓbù~m,@FcîàTÖÂï´‘,·jykù¯Úâ å*Å‚ˆôe«¼Œ”"C8龌 ŒfñÁËÀëÂl>˜†Õó¾ÅǨ (Ìiý=¬½Ûûu¾[ÄØ ¾ ¼+âäÉ“ôÙgŸ‰÷Þ{ïö/¯ˆþ#\…çËéâG9˜Ž–!isVµ\W¡ºâ—?ê«ç5gá[¢U»-¯?c¯ Ô«wt•}%ߢŒ#' 2”ãj]Ýùl¶ƒ,¿B^ÍQÜQrGºÅFÍrS«-R®êýtŒÇ'z•VvNeu1jFÆzm@å¶÷ßb¿-—ˆ°Ï>û¬ <’póÍ7Sš¦¢kâÏþóÄ‚Q9Î ?ÊYB®5X¶:Ó²O¼ø!OܵVóNb¡h±Nd´#²Ð'wcô¹«ìëbA:ÐL¶v‹P|騺óÙlùæìjcø`>1a‹šå¦V[¤\K1×"ªîyØEV†Ò©/†œ 3¢h§÷ßb¿]þ.  ¾Ë$ |™g¾zãO?ýD§OŸ¦×^{íPÄB_tC„4›y¬•Ì|]0^:£|AÞ’µ\Š#O|^¶Ôw åΞj¥”Dy~¼ùݦE’R–Æø‹¢5ÜQö"<ÞN)ÉóõhH,wO­ñŽ|ÚìÌEªáˆVvìOÄ I}²Øj£U±Ðj‹ƒ”«>ó# ) å‘È/I‡,ZïÅçR4¤ åØÍ$?f.>.ê:Zv4ÞCýÝvÙ¯óÝ ÀNüéObá–[n¡ë®»N\+»#¶‹…ú: òÇ|õGYå}Ì¥“(e8¡ò©¹¥U×u&Vú+ƒ÷êb¡y¾G'¯Xæ—Óª]ä!ž[yfá4dz:ËÎ[¸Ewƒ‰Ç².õÙáTÞ9Qw>vˆ½ñr6…ãÛf#kU,´Úâåڸ΂Ì/r†Â³xù· œ»>‘]+û-Caóžª.ï©fcÖBã=¤ÍwÛn¿îw €X;ðûßÿ^ˆ…cÇŽ‰…™ø¾|°ã?þxÈ9å¬%ÉZŒi¾®9ÒdãõƒäÁ»Q²,ï~&aùeû›;—g¬ìY¾¿²ļݼµÎË¿)ŸýÛ¨Í)×a¿Me¨uCä%Iz€÷Ðn?Ä8N:Uí Á·¢þꫯè¶ÛnƒaÀ¯L*VäbJ# àâƒ/ïÌÅÂwÜA=ô½÷Þ{4að+“S´(Jb\t<òÈ#bÚ¤eY"ʰóLbáhÀ£\,ÜyçB$ðÿøÇ?6>Ë—†æãøó8p\.blá¨ÄߢúÁ«8n ¼»‚Ï’àƒ ˆ…#‚mÛU7Ä|>§ãÇÓ_|ÑxæÕW_Ïdvß±pä¸çž{„àù&R|a¦<_2ûïÿ+lŠãƱpáÝ\,œ8qBˆ¾äs¾4Ç@,QxD‹>pñå—_¦»îº«ºÇfºá†èÛo¿…¡@,UxD¡\î™O›|ì±Çª{|>µ€X8Âð\,†!¶«v§ºwÿý÷ÓÛo¿ #€X8Êð¥Ë-ªŸzê)zñÅÅu>°‘o,Åw¡u2šOlšzð  G„[o½Uˆ>na2™Ð›o¾)®û¾¿½ ¢±ëäQAnxÔ3æ• øÎŒýÁ„Û"ù¦Ø¾9=Ô¼÷èËëª3ç`ï;Iò]/ÛBý àð᳸X¸öÚkÅš ~ø¡¸~úôiò| .nºé&±ód¹ ðÈw Ü],¤4Ö5²Ý9Ùz_8OE·(d¿û­/[±}<æA³È¥"¯õ5“Ù²åÎÓ±‡Fü¾b±+®e û ƒÂç *ìÜO—iÌfd¨½¢,Ë<öWv/\ÞSCMQjbA«ZèšHk],däšË<Í ?Y©¯ë’©I»©#‡’Øcõ“ÏkÆ”’¢å=ê¬Î{ö–ežÕÊ<¢ªÐpˆò*ìšå¯;äij¨ßS™ ËÂ%,…tÛ—&fe2ØyY­¸¾õ]îüêõcùEs6áÑÓ é¶Õ±>°‘‹…cÇŽ‰1 |•Æ$IÖÖ[ØE,X¥CÉuLñÙ˜'”rgËs$îܧd/¡pÅp(Š|2¸£8•#°‹ttkB®·`íÍ ×RéôÌ2ªÑ8¯=oNYY,qçÁ—›ÚWy˜a{挂pANáôÕ•È‚ÅZÄ‘ÇTæáÕÅBJSÓ¤™¿ ÐŸŠ² œ°ªoi7•u65*:°š ‡Ú§Y"ű+˜M·Ø»ìê©&ùaH3k Ÿãe.Ê«[Íç.¹Ì‘ûaºtš=>«D8åy«²‹" Šî V…çÒÌ‹ªë[ßå.ï!¯Õ¯Ì×!Šh>Éèw×±Ÿë¯¿¾ZÁ‘¯ÞÈyë­·ÄÖÕû w³ÊQð¾}Ù—¡{Åò ¿.ÜÇ~HqÑÌPDÿ~R:Oö¬jÕ»@6\ËVÄBÖ Ë{0 «Ç}Key(Ìi_å‘‚zŸ~&ëY ¢¥0‘åŽ §•RXº!r&ÆB2y7F9桬›ÝLo0Yç¾8—aE,´Ø[Ö§On²,³­4Å‚ˆôe«¼Œ”ù 'ÝWŠ®•¸a#;h6ß·¾Ë}¼‡zýÊ:Ôí>æAµE¤©ýo ±Î›Xà+9ò®Ÿ>ù /ì[,ðlÓONPþ€§ ›úöÊ;Þº´«Vx3–kÄ‚Z üyÃ[>ŒõšÓß½<©o‰ï-“J7ŠS<-ó¹n}€cBSC+Òî7#«u+ëQ;_Ö³)Ú콩Ìu± ôVíÛ$œè• Ji ÓTiµ÷b—w¹ë{hˆ…µ:°ïr¡!„H×ßb:|`# ÷Þ{oµz#ß/" É£ìØ!ÖZ¾´& ŒÆ É ×Ò²ï½p‰Ûˆ,Hg²ôlÍ[´#Š68—®òÈ{Ìie´¹»*Zâ™ µ÷Êñì’ˆ8(4ê9Žm¥n“u±°ÉÞe™«V9ÏÑ[ ^‹X¨ºäaö-#“0ß`Ÿîw¹ë{X,Ôíž‹Áå–ö¿5Ä8¯boOÍ·Ÿæ×vÚar±Ð/Åï›N)á›T•}êºM‹$¥,)ðE+vG±À # Y.Å‘'Ç pñPïÏ×LòcæZââþh¶ÞµBÎ"˜‰‡bìÀÆud:‘3”xù~…s×åi0­Æ;ôj3B:ßå¾ÞC½~ÌŠLX)µtµB8l«;b2|P# |>VáÝwߥ‡~ø¼ä•g¬u™ÕÃØ9¥I®|Î[–²ï§ùÊÕZø;ç³;Òs.¶-K*¾ŸWù”ŸÏ‹¥›6‰gÂÙvSØ_Ú)eY¾~}Ív}M»ñüÚï Ày§\½‘wC¸®KÏ?ÿ<=óÌ3—x­R2x¨ýÈN¥KDýyk]S•ªK$Æ{@,€s wß}7½òÊ+ôä“OÒ믿~‰×*§hP”ÝÖh-hîÎD´ÈõCÊñ à p¡ÀƒeYôÏþSˆ†ÿûß0 ˆÐ 'Nœ >ø@¬è¸···öŸ%Á»(øJü;8p\Ìb²Xàƒ¹àSèø’Ï›„Ÿ-ÁŸ;{ö¬8 Ž˜XàIñ™|ÙçU¡0NE÷Dˆ…#,xDá7ÞX›6É·¬æQ‡üƱpTÅB9#⥗^¢?ÿùÏû| è·ß~†±pÔÅ,<ýôÓtæÌ™êÞG}D·ß~;º@,@,\E7ß|3=öØcbúd ߦúÕW_…‘@,u±ÀAàƒ?þøcqo$Å·¯þþûïa$ G•¿ýíoo¹åúöÛoÅ=¾Šã£>zK—Ñ™‰Mn”m}nΞ›zñ¯V®ùNå:ÿe8ïuÎcr,ƒƒ,—2ü—@,=~þùç*²pÿý÷ áðÓO?‰{<òùþ–]ü»N6{tŒ¥}Õ™dåó*r³¢ž1_s¨ÓßNZ'?;̲°üØçÑùÞï Ó¶mu>Ìz¶*w­Ûd˜§Å>›ßÁöº¬ït)wû¼ðtým åy^‰.n¼ñÆJDðÿýï·8~s>ÅBµ]qNþÌ!ÿl¶±•m+=êÛ%W$³j{ã¡6žŸè=ÒÆAËùFKÕò—ŽÚðâévÉkÛ¶ÔùœËS¯gNSçáo¸·ßlä6ÛéGQÒb±`Gt"]u@,€5øÚ u±pòäIqï Á§LîÏ¡¥4Ö5²Ý9Ùz_8iE·(Ìb²4…Fu‡¸¤õ5rãŒ\S¯Z›ŠfŸl {4ê4ä2ÔYèÒ@‘ßQCÑWVg`kì¾J:N±(©®/óëõu:u²y–ãШønÚÈ?%‹‰…‘3#C-Ê­›´(}Mа¯°g 1‘/h¨°s?]Ë›ë,ZÖ¥¯ÕÓiŠ…munM§õ½Ð†ò,ë)íǯ÷©ßãõù¬ù¶ä×°« nÖ†OâY,}•Ù§|C û¾Bº-EJ{dèJUN­¸¾5ÿÙæ÷ÓUg‘_4§‘Ö¯¢¦lµ# ಆ^,gCðñ <ð€¸Î·ªæÓ(÷+¬òÇy4&×1Ågcž;b?®}³æ°yxÛ ˜}gjš4óúSáP•¨hŠ…ê3s¾"¤Í~¨ƒpAN!6Ô†XiÈË4¤dnˆû“Pî|˜r§ËCøÌÁ¸sŸ>þ yžä)ÙE=tkB®·`mÏzYj÷Í)«§%#Gîì˜JÇh–ÚùjÞÉ^ ê¢E‘O†"ÓY³í¶:gét¼—µòäËz¦áL’þÀf÷< Óš ¶ä·f¿"² [Íç.¹Ì‘ûaºtÂ^#Ÿ0œêBä‰.Š"Þ•ä°¿‘…çÒÌ‹vÏÃûéªs•Ÿj’E4ŸŒD:#7î´# ಆÏx(Å,œ:uJ\Çû •³S…ÿ€Ïªm®ç­ßl1®9ìH8r}²¨%”³²„dòÐzÕ¿Y,¤¾¹ÒßÉ|kb!õLápü\ ‡A¯ž® á+–ßr.ë¡ZuñÑ <²0˜.#%¾ÅÅÏ€Dõ²±Ð8oæ%ËÙc­êâ8¢™¡,EUͶÛêÜ™NÇ{Y¯{½žÅ=sýÞ.ù5ìWˆèËVy9÷‹1 }AÍâF½ì Ù|ßš×û騳L·ß°ó˜ Õf©vÙˆpÃÇ$”Ë=sPFn¸á†;On üÇÓôÓ†Ó•?¦±§XvÍñ%45Špw¯¿!h –øþrÈ@º"ršŠõ`@ƒNý¢u䛞_?oÖc],¬ŽYÆú²NÄ‚Z7óJ}{eÐoñrÇ´*ºëÜ™Nç{Y­ûŠ(j¹·¿üj6ñÛÇy„½J§”²ÞêÚÕ]òo}?õZµ3û.BˆtÙˆpóÝwßUbwA¼ð ”$‰˜B¹[hb],Õ€¼æ©ì×i¨-C±;?γP¨·:®ÕÖûA¯õQ7Zx‰+ÄnØ4¶m²í1­a­Åº›X0 ×Å‚Yó`²[eD‘löýóiU¥M,-Y7é¶í¶:w¦Óù^(ö•_]@µˆ…ª»Ava»2‚Pv!5# Ýù·¾Ÿ­õªÛ9ƒ!帕î¿o ÀeKš¦B,\}õÕtï½÷Òk¯½Fï¼óŽè’8,±PØgE éHekReb!¡È‹ûŠáʾÿ±‡S50Šâ‡Íˆ„%ÃÂ1”$rªaN柇SJòœhÃù6± ú®5“ü˜¥{¢›£7*ÂÓùBœk–KqTÜãu®uaTyÓ#{ºM‹$¥,)ð²e]³í¶:w¦Óù^Vë¾›XØ_~T› áS…b+t~$²¢Ò!‹Ö{ñ¹§ÉÖ}™j¥”Dy~¼5ÿÎ÷ÓUçd.Dj8"Jû)9C]Š—Ï ç®O„óOƒi5Þ¡W›Ò™ÿ–÷Ó^göÄD«RKW+„Ãö¿o ÀeÊ×_-ÄÂ5×\#–{æK=ó¨Â¯»ËdF kÊhBNiõ¹›ÿüój6_káìÙ³¢;€X‚O?ý´Z”‰GøÇ‡zhã³|µÇgŸ}VtW”KDãÀcy±.Kø€Æò‡Ž‹€3gÎã8kÏñ=$î¸ãšN§ôÕW_Ñ/¿üã€X8 |ôÑG•Xà›H=õÔSB0Ôáãø}tO€X8‚ð­‚K±`ÛöÆ=!øš wß}7Œbá(òÞ{ïUbï:É»þóŸÿT÷¿ùæ±O_€X8‚ð(B9ÀñÉ'Ÿ¤ë®»NìDYò§?ýI¬è@,QøJåÔÉ?þñtíµ×V÷¸hØy÷I àòÄ÷ýjoˆ?üátâĉêÞ«¯¾J=öŒbá(óúë¯W+8r±pÿý÷W÷ø€G>¦á‘љ‰Mn”m}nΞ›zñ¯V®ùNåˆpðÊ+¯±À»ø˜…Ó§O‹ëÿýïÅ"MÕ†I­~³¹3âá²GÇXÚWIV>¯"7êó5§>ð­œuò³Ã, Ë}]¨½6îà(w°¼ðt½'ĸ$™Ïç•XxüñÇé/ù‹¸þæ›oîÖ‘yô›ó)ª­ƒsògùg³-}[éQ¿ÚJ¹ ™U[ °ñüDï‘6ZÎ7QÏ_ŠÃ;ˆwÞ%¯í6ç[6§Ea(¦¿.]˜8Çj}ºÞb\’¼øâ‹B,ðY?üpµ 0ð¨ÃþÄBJc]#Û“­÷…“Vt‹Â,&KShTw؉KZ_#7ÎÈ5õª…¬hùÉ&±°G“¡Nã@¶ÌB—ŠüŽ:Šè†²"[c÷UÒùsŠEIu}™_¯¯Ó©“Ís/•õ°‡FÅwÓFþ)YL,ŒœjQnݤEé³€†}…=[ˆ‰|AC…ûéZÞ\odѲ.}­–s¼ÞĨOO³)-lίYÂ%‰gQŸÕy\1auQH·}™bì‘ÁÎË2hÅõö2¶˜m®ëz}šï)æ4ÒúUôÃt‚Fºë+ø? ĸèxî¹çªÈÂ}÷Ý'ó„Üs}³æ°UvÏ ˜}gjš4óúSᕨhŠ…ê3s¾" ÏœK.È)ĆÚ ! ¹3œ†”Ì qÊ.•” ÞmÁœ¢;÷éãšçIž’]ÔC·&äz æ¶ëe©Ý7§¬ž–tè‡D©tæfm©¯æì¢.ŠáPùd(2i[_D´ñœâЧÙ̗у"² [Íç.¹Ì‘ûaºtÂ/›F>+L8Õ…`]YPt_èä0{/<—f^T]ßX†-u]«O^³S™Ÿj’E4ŸŒD:#7îü[@,€‹ ¾†B)î¼óNúàƒè믿¦›nºi·VÅ‚Âάr4<\Ï[üÙb\sØ‘päúdQK(§, ÉäÝ ÕØƒÍb!õÍ•>úLæ[ ©g 'éçR8 zõte·…bù-粪UM±À# ƒé2Râ[\ü HT/[ óf^²œ=û!ÅqD3CYŠªâ{ÊhJQÚ´¹Z´æû}Ù*/#¥ÈNº/#£YÜÈËšÍ÷Î2l«ëšíjïI¤Ûo¼§1*´ÿ­ ÀEÆ_ÿú×j6ÄñãÇ™³ˆé­·ÞÚ}ÊäŠXà?ø¦Ÿ6œ®t1ÜñYvÍÙ'45´"LÝ_‰´‰K|9d ] 9ME˜}0 Á@§~Ñ¢òMϯŸ7ë±.VÇ,c}Y§ bA­Î›y¥¾½2P±ÖÝÀÓŽ–]權,ˆôýö1áD¯Ò*¥´›º6س» [êºf»®÷ľ˅†"]+ˆpQñÌ3ÏTë,†!`zúé§éùçŸ?°X0ªÁŽM Çè4Ô–aìØ ‡2Õ9[Ïz‹•9¡Z¿z£Uš¸Bè†McÛ&ÛÓØÖZÙ»‰£1hs],˜5¯+»UFɦz1¦ ­Ê£´‰…¢õívEß³„\k°Œ Tb¤E,TÝ ò°‹r”„²;¦Yh+Öºv‰…µ÷”‹Ár H÷ß b\DüùÏ®–{æÇÏ?ÿ,ÖWøðÃM,T³âYÑÂ_:RÙV™XH(òÆâ¾b¸²ï¿E,äá´hi;Å › )J†…3+IäôÊ2Î?§”ˆ©¡ëçÛÄ‚èo×Lòc–Zì‰nŽÞ¨©ç q®Y.ÅQq×¹Ö…QåUL=íé6-’”²4¦À_„f3v’ã†X³!|Š¢ÂP‰ü’tÈ¢õ^|îi²u_æ¥äG)%Q@žw—a[]×lW³S2¢F5¥ˆý‰q¢ûiËß b\<ð½ʤøÒÎ>3‚¯³°›X¨¯³ ǪPkcÄà»þhéÈ™CÑk£é¡Zè¶G'kbaù™È³U˹?0hXå#»;´z~A8Š4.“ac}‚æùj=h%Y¯žª.ÃöªÙÉ?·´êž> 'YvK¬æ.é¬ËC´¼kνœ)2œc6­³ Ë9C©‰—ïG8w}"œL«ñ½Ú ’Ö2ìP×f}šï)fP©¥«Âaûß b\4L§ÓJ,;vLì2yË-·üÊ¥È(a-ZMÈ)­>w“g©øÞAáßO³¼õ¼ó»åbUeÈÒ„Ò4ß)oYoö|¶:w0g餭é°æ,½”²µºn*C­"ÏZëÚm»Lä·«m à"ƒ¯§PvCðÙï¿ÿ~cÉgpÔIE¤fˆ)ˆ…£ _µ±Üuò‹29ŽÀ*Ú-ŠRD G>E²œ:É…ߦúå—_†a@,Éx<®eâB¯âÈ÷Øïwæ"o¾ùæjœçë@,€‹„|°Ú‚/ÐÄ—yæ+8®Â>òq Ï>û¬øüË/¿Àx Ž|0# |;j¾»À×Z¨óÙgŸ‰gø¦SÄÂãÞ{ï­ÖXøûßÿ.¦OÖáSo¿ývzýõ×a, G‘{î¹§ ¼buÚ$6<úè£0ˆ…£ÊÝwß]‰>e’¯»PòÃ?Ð7Þ¸ÛVÕ Àå‰eYÕ˜¾š#ß²ºd>Ÿ‹é”ÄÂæŽ;î¨Ä_s¡¾ÆÂ‰'èã?†‘@,eø¶Ôå: |ÇwÞyG\¢ˆŽ?~K—Ñ™‰Mn”m}nΞ›zñ¯V®ùNåºl ` \p±põÕW‹.‰O>ùD\çƒù±Ý'Õwþ yžäEwÔÖ„\oÁÚ±õ²Ôî›SVOKF0Žì2H¥“5ËV}í|5ïd/uQ ‡¢È'C‘é”­ggÈ#·“ÄåçÚ¸hÝïh»Žòp!ÑšYÐ-‡æs—\æÈý0]:aÛ@#ŸU:œêB˜‰.Š"MÞýã°²-<—f^Ô×›®Ù-oŠ!‘Ÿj’E4ŸŒD:#7îü›@,€¹é¦›ªŽå€Æßÿþ÷ôÊ+¯L,(ÜÌ*ÀÃõ¼ÅŸ-Æ5‡½)”žS–…dòî„jìÁf±úæJßy&ó­‰…Ô3…óòs)½zº²ÛB±ü–sYÕª‹¦Xà‘…Át)ñ-.~$ª—­8çÆy3/YÎk¡‡ÇÍ ¥!ªRß’÷,á<éiwÛu”§3ÿB,ˆ(@_¶ÊËÈL§ÓЗ„Ñ,nÔÉšÍ÷îºn±éÚ;ªý=ˆtû¿‡1ªÍRmÿ›@,€áÑ„rêäï~÷;q/ïüŸÿüç@bÿ›~Úpºò‡9&ƒ·î¬€ »æìšZ>î¯DÚÄ‚%¾¿2®ˆ…œ¦ƒ"ü=Ð` S¿héù¦ç×Ï›õX «c‚±¾¬Óç¬VçͼRß^@È[Ïvmð¢V|Ò€X8¢bÿ{êÔ)zýõ×÷ÿõ¯ !ñ¿ÿýƱpÔÅ‚mÛbÇ’~øn½õV±j±pD)yñ]'MÓ¤/¿ü²ºÇÇ)L& ÄÄ•b†ìX®LÈÿåÓ)ëâ€X8Âbá–[n‚¡„]xä‘G`   R,;vŒ~ûÛßV×ï½÷^zï½÷.pé2:3±É²­ÏÍÙsS/Æ ˆp¾ÄÂñãÇéþûï×¾ýö[±uõO?ý´ƒ?¯ï:yØìÑ1–öUg’•Ï«ÈMˆzƼ*“.v£œ4¶zN}Sl©ü«Mݸk£ÜiòÂÓeOþöÞåÙm*ëõ?s™µgÌ?hBÕøŽn—&=1#Ê·.u ÔáÝPx&tH+Dˆ›à¤Aã>AG€@ jXw¯½õ´-ùŸgÎY¿*Õ9¶¤ýX[Öú­µ×^›@ ²@X@î½÷^ž™ë’3Í+Ä üÏv’…|âËçJ¼Ð³`HŒ¤Û c›²í‘û–_% ­$ ¢½Ñ|σétÊâ]é†J :7ýÜ$O@ ²@X@î»ï>ž” ñÔSOÁÛo¿½Yˆ` tÀ°Ç`(m®¬%E/@ïHÐ7KK0C:íØA ¶¦ä–·ÔQÁ ‘…5ö¸k¢Zφ®$î‘»=îÝJd¡“[ò˜D‹ÈBS½¢ºmƒÖýû&„Ázmq}GAvyìmiw4˜Æ…l$öîÌ+äp¢C»%à ¯4duJ ŽPå¬.•}ÎÚ×I¿¯­+k³e*§}RŠó®QôµÕV˜LªòLü1ôÓ¾¢÷C3ÝJ¹ócJ¿@dá@z^ýuøå—_xêçï¿ÿ~%² gŠª?ÛÔøÿê8»ßæS™jt ™S!`÷Œ4 ,g ž3âʵ›“Š*YÈÿO¦Â½Ï”–ëMÁL•¾<ãYЙåÜÅëº#À5ѤLšê-úÑÑF`Ô\Ñv ,®xÛ`a³b—·ERMð}TTä]³ÒE7a<¶ÁfŠÜñ¢B w™qXã¼–)‹)Š´ÌVK“µo:±ÁšøÍu±òŒ´Í k³mê¼Oxž÷ÉF0ì±aR’gVŸ¬ãû0ö…WÆÇ”@ ˆ,0²€1 /^dJȇ£G®¿€Y² ¡2³r†±hñÇÓW2CU—=TjÃi© âØ §²Øƒ² <å¹ÿXÔ[" Ü¢wcí~ªÜ"H\}Á4Ä¢zE?d£Z^7koìðϼ-¡<ŽAàƒ¥J)*M‡´ÛÂ*Ï<Y9\I·¥tÊDhfenÕ|o¬ ÛÌdÝÞGGBÖ.òtªFÒ9ÙŠrÛy È+µ~L ÈÂ# ¸Âu]fá¹çž[™, "Ñœ¨¢t…b @EëTwq0JÊ>„‘ÚI-÷vÕCPKt~ÿ$WnÑB² ñ âÔ‚ï‚m—›êéGªôËŸEùØc&€­wCÔ‘]çÔGIxC%¿'£¢2ÌÎ^4Ö•¶Y-„î@)ÉyFFòd÷"ÑàD¤iL ÈÂ" ˜gáÓO?åAŽèaØ YPó`Ǫbqw­÷:…{<à–¿ŸO`P£Ðæ-a¦ÜJóõk·¤Ì9K¸äñt®\›ëéÇlye²Zåv¸X6iYtÞ­¬–0R…œy„fÖ³PSW®Ô †!¦zúàò0'Ï„C Y5)@ Y8@d2AÀS>ùå—[JòU Li·SŨ§ŠQXÖ2SÚ!ø“?/©6$ d!ñFi< ~0…A¯=³PQî ÓAjÁË‚,4×»~²-m)LÃâ(×™ /A¾Âß÷øx„â¤PÈÜzOÿÏ‚1³2e?‚ÐwaâÍue± œ€©ø`"â5úÅôNS´z#y–Î’lÃ1﬚‚H9C.1M´dL ÈÂÁ! ¸u†|‡É_ýud¡œgA(¤YÅ"çóäiP_;³v+*¥¥¯öäRÝ-‘… ÑÍ-òvW…^¹ž´MzÅýešzšëé+O.{²ÊÌ05K«/Ju,̳ ÊõÍžðl…¹rWDnˆÈåñ­ÒJÚºRY·d¹8'k•U î°WÊõP•gÀ“T*·“‡åcJ D YÀ]'/_¾ º®ïB+bFT¢ÔªO ÊÿoFGü¾®·¦5ìþ¢x+ײ2£â8YG]¥iˆ$®• Ê,Š“Zy`}õç ÈÂ& ‡â± ëNÆDØcˆxi–4" „í" ˜Þ“2a®ÂÕˆü© ~D^@d°Mdá®»îâ»L¾ÿþû$@ Y Ì“Üqÿûß ¯ÃM¥0ôc=ƽÙ}tÐA DYx衇xÜÂO?ý4wÍÚÚ<ðÀ|Ûjô<üøã$8@ Y8hd‰ÀwÜ1wÉžþùçIX@ ²pЀS Y0 î¿ÿþ9¢€K)qê@ " ?ÿüsNŽ?ÎËxùå—a8’ @dá â?ÿùOųpêÔ©ü¦|VU~øá@ ˆ,T` b9Àñܹsù¹ÑhgÏž%!ÈÂA®rÈÈÆ+\ºt)ÿ—GÒª@ Y8àøæ›or²pß}÷ÁG}Ä¿GÃsÏ=·ZÃù¡¶/½nÌ®M‚ê·aÀwÒÜÙ½D[–¶9Ž ð±}áØ‹a½r&" —PÎàøùçŸóïÿô§?ñ­”×§gÊ»Nn5Öà+ûæóáÌÿ³›(µÔqú9€AOªìô˜ï¹í`maõõk÷hÁT•¹([¢]{šd[Œóüš¸{å^x’×Ñ~@d°”÷†À‘@Ü}÷Ý0J'ð?ÛIòm”p,œ+ñBËØZÐN·q'Wf'à»,N'L¼²šqQ’“†ŠP´ºåB”$G!L ŒÁVo¡(·3p·@ÎõãŒ[f÷Fð‘œN§ìðaw|³ýmz6‘¦ðÙgŸU¶¨þå—_àüù󛂨…J { †ÒæJQRtðâôŽ}³ä­mè´;`1ØZaiKœp‘[ƒaO»&ªõlèJâ¹ÛãÞ )% ¾ÕãßÝyåûÅ}íŽÓ¸P@õíýÒMúx¯¤s/@L@U FÇpøµ:’‹É +•dÀj˜øçžé׊3ñÇÐï´sË]3ÝJæe à%OE[ITÓÞÚ²«¤l2TAšõx°qÆïtg^¦áD‡vKfä,̽'&…Ë£NNMc‘¶ß²@•ÓñPŠóóý­>«È@ Y Ôàã?ÎÉÂ-·Ü¿{üñÇá½÷Þ[™,èÙ˽?Û¾:Áî³—s[ƒL¸†ÌΩ°{Fš–3Ïq…ÔÍIE•,äÿ'Ság/z×›‚™*y9% Ž9yÀﺆ•× ±Ëï“T|ßU×ÌI};"0Ò~)úìÉ’´¬VK“Ý3Ø`Müʵ³2l•+¯Ú‘¬LYÇ÷a<ìó{ûvÐ(Û‰NÃ0…k“†ö.,»$ÛØá„Î` ç€e9Â{zÝ„ñØ›)rÇ‹ %ÜÁú:à$ÞÇCSurZ2yûµë«.È ;Ñóý-·5" „|ðÁ9YÀTÏ¿þú+üþ÷¿‡8Þ€©5K$TVþÒG—wŒ†À¦vÌö Ò6È0—ˆ¥À®1dçû࢒äJ´I¶³ý¯ko]ÙÕ˜wÔ/¦ 4+÷, ‰(—9'ë¡’Ë4^"§¨q,æã>ÜRzffûÛôl¬W†Èa!&“Ie#© .ÀŸÿüçM“…"P®ú2v·ò{Â¥Ø}þr·øÄqƒ%0o=2…ú,D1åÑ…·ÞVç"eÝÜŽÙ~–±ð”Ì“…E2H¦C¡€õIƒg¡Ü¯DDò˜ƒ&Ù.& óí­+{A€c‚­w ¯@FêÜ"ùtƒ8ŒT!×É)ó,&N™Rgư>,! +Ë@ Y ,Äx<ÎÉÂO<Á‘0l5YÈV)@` +ŸÊE%kTfJ:2àç%Õ†¤,$Þ(µzMðƒ) zUO€g0°\ã’h š,< QºÌ³¥0 #ˆ£\gÊ­àævÌ+ßlÉhKVÁñ#}&N°DÅjˆ®aCÇ|5„;B¯7„(s…,«&·°gÈÛ!¦kšÊnûVoa’,nocÙåi,kÂdÇnq² VC8àû_Z‹G(Ü¢_ÜzÏúØÖ}œÆ"-èhàLÅèâµýbú ÚßRûW–!@ ²@XÛ¶s²ðì³Ïƒ>Ÿ~úéÉB9ÏBº`æe,—æÒy \;³…SJ‘íjO.­ÁÑY8Z²~'F7·bÛ]z¥z„£U‰˜·Ò÷hjæÁüHW 4·c¶_ioÜQ>ßj•¬üF0ìwæ\ðÕžFT¤Ê÷fîšo*×öJ¹··¾ì’l3%žõ‰‘˜0çù< âßì ¯LP<\¹+C®üË©a,Ò¾µd¹8'k•U ÕþVŸUeH ˆ,w•ÌÈ‚išnÜ2Ä2ëRXñ ³°³ÿ›9ð¾ús"Câ|YXfNŒ·  ÏOo0 c1%ˆöÍßó27šÙû¼üžõ”ùØ5ÑVf–¬“Ó¢±(MC$qã×÷c5" „üõ¯ÍÉÂéÓ§yGa÷ñ`Ø-i$ˆ,vùË_r²€ÛSã6ÕÂî#ê‚‘W€@ ²@Øu<óÌ3•˜Ü–š@ " „¸¢¼w›¬Ãwß}gÏž…xþð‡?ä÷ÑAÇ~:‘ Ž?^ɳ€IšfY_zé%¾ÑÆ5àj‰µµ5þ=@ Dö9p©dFþøÇ?Î-›DB0 ¸×= @ Y8`8zôhN> ß|óMåü£> ÇŽ#/@ ˆ,TÜsÏ=s[Tgxýõ×9™ ¢@ " wß}wN0&!&³QU¾úê+@ ˆ,dà¶ÔY(ï6‰Éš^|ñE@ ˆ,t 7!# <òÿîûï¿çßÿðÃ$ @ Y8èÀ½ 2²0ùwo¼ñOд7Ãù¡¶/½nÌ®M‚ê·|oˆ`‡÷mYÞæÍö™@ ˆ,v·ÜrKN^xáþÝ¢%”ͺ­¼ëäVc ް²o>Îü? ±ñPK§Ÿô¤ÊîˆÚ$Ú!©²¶°úú‹ö5X¸s£Ø5q}ýÜ(飼o/<}[ØO@d°}è÷û9Yxå•W CžqC+ â üÏv’…|ëáËçJ¼Ð7¤´Ó­Ã‰ÆãÀ øÎ„Ó‰o§,uA\ÔEä„É ·jî&à{L§Svø¬õ徕ûÃPiAgà®HêêÛ Ìö¥i< ‘ž# ¸lr<óã¹çžÛ°B*ÈB¥†=Cis…-):xqzG‚¾é÷…6tÚ°ƒlMÉ-_©£‚." k0ì)0p×Dµž ]IÜ#w{Ü»!¥dÁ·züû¡;¯ˆb¿¸¯ÝÑ`ʬ¾¢_ºiBï•t@*P•ƒÑ1~­ŽdÁb2èJ%YI­tëåRTô­è³kíiµ@þQßþmLëÓy9„Ú-™ª¬“!»_ÅY<÷mõ[¨r*C¥8?ß—êx&þúvîýÐL·Rîü3E¿_ÈaG€$!# —.]â™ß}÷ÝM‘=Sýئ°ðÕqvŸ½èÛdªÉ5dvN…€Ý3Ò4°œ)xΈ+·nN*ªd!ÿ?™ ÷:S®73UòrJ sò€ßu +¯b—ß'©&ø¾**½®™+¥úvD`¤ýRô!Ø“)$iY­–&»g:±Ášø•kgeP¶ô=Öî©;?Œkû!!Â馔í±áZsûçÛ(êSt“Al¦È/*”p¯ï€“x#”¡,¦(êú¯³~mÄú­sâyŒ™ëKRêsVŸ¬ãû0öy9};h|¦‘ œé½÷Þã« p߇M‘ •‰•+tÉ£ÅOÂÚ÷PuøÐC¥2œ– J Ž=Ðp:!=¨Q¢Ž63÷‹z3²À Sflž^q@”OOx>XªT!0õíý’õ¢ü¬,cÎ{Q/”Ug&†@´¹†¥Ó+’îTê\Üþù6fä„{ÚÂ*Ï<â|ÓЄ¾4ömiý¬ŸÝQá=rt$„]àC>Ó—ÊxòrÛ•ñ A Vjƒ< ‘ÂΑœŽ@Ï‚Æ,ë c†,à‹\s¢ªâä/öTTŽºËˆƒQRö!ŒÔNª<ÛUA-YÐùýEX@4ORx6ºÛÑ-oÀçŽ1쇖®¢˜¦vÌö Ò6È0ïáoAª¼µ¹øŽ:²PíWÔØþù6ÓõÞPÉˉ—ôm=õ—c5ÜRçÙ1jOv/ NDšž)@d°£dáÕW_…'Nl YPseX}±»F‡[ù½Nážì>WŸ„N`P£Pæ-Q¦\bX—µ)¦<ºð֛‚µx°›Û1Û¯ÂÊž’y²°P™ò^•,LêÛ¿¨E}5d!Ÿn‡‘*亾­§þr<†{|XBæÆ3áÁ"6¤ù™"D;H0°ñµ×^Û²­R€ÀV>º‹J–­Ì”tþdÀÏKª IƒM¼‘ºÓLðƒ) zUO€g0°\ã’h š,< QºÌ³¥0 #ˆ£\gÊ-êæv,RÄiY² ŽAè»0q‚f¬Bpž¿7‚0IŠ:´¿Ž,ˆ |ßÏ“HW'ë=ý¿ÕÖ}]ß–ÔÏc :8SñÁºxm¿˜>¨ô¥ÜÏpÌå"«&÷RÎË_LS-y¦‘ÂÎŒYxì±Çàý÷ß_,”ó,¤+f^ìr>OÕµ3k¸¢PJQòjO.°­ÁÑ’-þ˜ÝÜ"nwUè•êŒV%úÞJÃ磩YHW64·c¶_ioÜQPÄ4È •Õ"²P×OwØ«äG¨mÿ¢6.̳ ®ñÍžð¤ŵ\¹+C®ü÷mIýð(ËÅ9Y«¬Z¨ö¥ÚÏ€4©Tn'%ËŸ)@d°#dŒWÀl‡»ƒBf© +>(ÿ¿˜Cï«?‡Ãea!Dq¼íHøÆ[ñ6f‰Ä¾T³PÖµËk®éÛ¢úKÓIÜ8.õ5c^ßÎfÜ$Dë& 8QÞ¢š@Ø"ÀÚ£%‘Âþfi,OCà”ÂêHÀŸºàGä ˆ,ö ~úé§œ,:t|ðA @ ˆ, `ò¥Œ,à†RMË&qÛê .ðk0¶¡¼[%tìöA ˆ,¶ _~ùeþ²½õÖ[áôéÓs×Äq ¦iòÌŽ¸…5¦‚þúë¯ù÷@ YØç¸|ùrNÐS€›H•¤àÞ{ï…Ñh?üð Œ@ D>øàƒ Yxûí·ós?ÿü3>|.^¼H‚"‘…ƒŠ7ß|³B>úè#þ}’$ü»—_~™„D " ûÛß*dÁ÷ENEÜ#âøñã$ @ Y8èxþùç+«!¾ýö[¾êƒ1‹@ D8žzê©JR&ŒSxå•WàÔ©S$@ Y <ôÐC²€ï¼óN¸rå ‡pÕ#æû‚´ÏÄÖKÆCF“`‡ï%Y ì î»ï¾Jž…Ï>û t]'Á®r0èI•]65¾ïöaÿß|~{W4ìºZÙ ÷-Ü1Tì<º»†µÔñæïݳ}„­y^ˆ,öp/ˆŒ,üáà/¾ø" †pU#œh\é œ€ïp9X0áûd'àX&8W6‘P,žðm´çɪe—ï‹a¨´ 3póºp‹ðÞh¾çÁt:e‡»Ÿ-CjA;ݲ|S÷î©>ÎÈ+ž" „ý€Ûn»-' GŽcÇŽÁ¿þõ/ ᪆oõ8Yºñœ¥8ì)0pׄEË,ܶ$ÄY–A’{à¤mìÛЕ„¥Ûîh0—‘…RÙÌz(Ðm´N›—!÷Mƒ ôڢ̎:‚pæ>×P 뺭À$uéN¼€éÐnÉŒeíY(†#Ô»WU ïJ'ý¾¶_ËÎyÅ9¹ÛãÞ©DV¾7ÞÉ>¦ãbY Ê⼤ççä•Ç”Õ硟Ž'z?4Ó­”kØc0”vZ®ÞäDö)pó¨Œ,=z”¯ˆ -ª W¿ka̾´»†aI¡ùM TTôI¦Ìíñ&ãSJx½œ_Ä.wKª ¾ï€ŠŠ§k.% yÙLyè©2êh#°Fj®„º† WJm°Âê}*U$LÁÙcÂ5au+º ã1k+SrŽ ªƒevÀI¼–) ÷}Ú~ìé0K}bƒ5ñ—ô«á\2å1èzS05¡Tå\áoæÞì#+ÏHÇEaãb›:KŒ‡}^Nß*ã-õ¬\áÙRàVíDö)0¨1# <ðüéO"¡ö a`Š¢“Í+0’…^`¬uÒi ¡¤¢|à ðÁR™õÚÖéX/Y`JJ6ªÖsw8M?;ü³¸¶|ŸpÑKºSQ¤ÜBn ‹5³ª³r¸k ëºo•ö3ž•¦~5žs´™8‚˜÷/ólæÞì#Fº#/¿ÞÑev}¼æå_&r¼Üv¥$²ÁJã-©VNJ0.CZiš†Èa¢¼kßý÷ß'Ož$¡ö<[^ _êóda:S=³P ‘cÌÜ¡µ‰÷¯Ÿ, ²Ðò9 ¡ËŸ‹2æIƬ‹>¿oQÿ†JÞ¾8o¿Î-ðYÏ~S¿šÏé\áOòfTÛ¹™{w²Ù¸¨EcÀ(%23Ó¶2Y˜ë»‰'"3ã=W‘Â>" èUxã76t¿ã8tбò±Sp a=ºI•,dŠEÖÆ ¬Ó6Ø‹¼ÈµÊmž,ä¤d–`l”,Lji1ãzɺûµüS”¥¹ÿ²å¼™{w²‰‹gž>ø°„,Ìõ#áÁ-Içž…ÊxY ìg²€»K¾ÿþûDè¸êÉ‚g0°\ã’h š¼À³Ø©û»nr—µï%/l)LÃâ(×™ «6ÞwØõxž8‚x‹ÈΙ÷F&Im]¡hˆPVܲMÿou„囵_VÁñ#}&N°¤_õço”Æ_˜àSôÚ3q›¹wû˜Åt4p¦âƒ tñÚ~1}P‘ylÂ13Y5¹—"p†Üc¥ð©¥Åd¡Md°€Œe²€É˜>ÿüs" t\õdÁ5:U7t[‹‡¦¯ÁÑÜRÔçÝÕ% 7ššy$?¸ 5y0˜ír^v¦t ²àˆiˆIuZBw¢J›xÛ‡½"×@PS»Ö7{ü+ËmÄêàŠOrŹ£< UZ}PÛ¯%ç&F7ÿ¾ÝU¡‡1z1†+ßïd…oÉrqNÖ*«*òªcL" 2[}‘‡¹ñÎbVt‡ÈáêîQ& ¸âÇ$²@Ǿ˜†Àü !ÏàÂêùˆBF,â]‡mßš¬“ ßã%ž+«©_õç„L£•äµüÞèci"‰kÛÓ,ÿ˜×GYA¯B²€û|õÕWÜuõÞ{ïñm—Ïž=Ë÷7xæ™g`0€a<€]íhA«ªÊs `ÖB\>˜­ À¿ø¿Çóx^÷áýX–‡åbùXÖ‡õ~òÉ'¼Øž«˜­±L°ß)¼òq¿óÜsâìßKd@X"PqÊcL÷-Y@&‡ÊøÂ… púôixòÉ'yZbTæ¨äP™?üðÃ|c$ÜI7CÇðÎ;ïÀ|ü1ß~ùË/¿äeýðÃŒ‰ÆðÓO?A’$ynü‹Ÿñ{<×áõxÞå`yX.–õ`}'Nœàõc;°=Ø.l¶Ó4MÞn¼w/íäøü£²/Ä]wݵ:Y¸p®c?ÂOœ›QçáFöýïmƒŠ¤á>V×õsnËkáññn+¿1Üx kË oþÞ=ÛÇÍŒ)‘Ân#ê‚‘Wàª' ÿýïù¼ùd2^xgüýïÏSã¦G£ÑˆGìc *ot¥ïU?¶Û‰íÅv#™À~`°_Ø?ì'öû½Ó8sæL…,`ž…ÕÉ ¸v!Y¸'< 'Ï^Ø ")ßwî¼¾×Ý>ÊëÂyÃßÞs,Öôðœ:eÁ…=àY8tm ®¹ñÄæïÝS}œ‘ÿÊcJd@ ²°"ÐzÿðÃù~¨@ÑýÿÇ?þž}öY8þ<|úé§žGßëÀþ`¿°ØOì/öûr@yÄ;0GúØcU¦!ž~úém çáÎÿûz¸}tž[Ï·_Ütü8ÜxÝ5" éwGáÜÙðÛk„õ|Ý ÷À¹™ûF‡®/¬ëk®‡¯Šºn:9¯¬Î¸ ®iIpûɬçX×Âõ‡NòÏ—X]7°ÏYy×¥ß_°ŽCçZñÝ5×ݧ.e6ž;Sœ“:¿åÞ•kKdaå{/ìdÓqaÏß iŠÜk¯/ÎÏÉ\SVŸõ8ü.Oô~ÜxtT)÷ÐñÇáÐõפåÞg.¬N„£W½‹8ˆË}qš?åctб×" nŒsåè¾Çü‘?òÈ#|îÝôIr0ÝCØoì?ÊårAù œP^(·­†¦iÏN—lY¸ñÿhÁ '^ãÊã¦T]wã=pìžЍâCGáWJ×À±sÕûƨT‘L0wüñ“pn,¬îëo: ?~Ž3%wò̸PP×a™×ÁÉKœ¹çzÕÌÝ÷F©kÿz8z’Yê'ŽÃ±Vþýµ7Ë: 7 BíMûÕpîÒ)QS€£3§àèB©J¹Âß̽;ØGVÞ¡t\®gãrüèM|,ñü%v~Nþ—JcšÕ'Ý'- ¿ów¼œß?[ïkw;+÷Fþÿ ŸÛ0Yøè£à8#™·ß~;Ÿò{ýõ×9©þâ‹/øÔÆ Qšrá*' ¨èps"tÅ£-é—^z‰[×ô_ ” Ê= (/Œ@ù¡·Š8àtHy%Ĺsç¶Ÿ,0%%ªZÏ;Oåóôøù^Fù>ᢿö¦“EÊ-äk„ÅšYÕ•ùþk„uý»c"hp|B(«C£ªµž}ûÉ3Œ¬Ypìvß57rG㹓7ÎÄ\àý˼›¹w'ûÈÇ…‘Î=gòëOÞ$ñõìg.9óò/9^î5•~ÜŽA:ãt¼¯½áX%.£ìyY0«(ƽûî»ô¾ ö#Y¸rå w>|˜[ÉèvÿöÛoIš+å†òC9¢fãrÉ¢®Ñí×—ÈÌLÛÊda®ì^$œˆÌŒ÷\9ÎR#§ðùܘ°dà¸Z—ÞqÇð·¿ý/'$lPž(W”/Ê彊·¡LÐsKO7Mæ”ÛÈóËp{òE9£¼Qî(ÿUÉNI¬âõ)“½,ë _iÇÙ [DpÎü·÷À¹K—jë:w¡ˆÜ–múë:aù¦Ë;[Ò pÒÃ9k'Nž-¾¿þœ:7† ã³0:yJXë ç.¹'¿8 ÖÙSpûo¯™‰;ØÌ½;ØÇ,¶àºáäÙ1ŒÏžÙï~WLTä_›só1“n8ʽgOÞ ×à” ŸZZL®Y'YÀgãxÂ>! ¸D.½Ã@$ÂÎåŽòÇqÀñX +7öûý•,¸æÜÌö"ü¿3J¿ 'Å4ĉê´ÄMÜJ>_ºYºwþ¶È5ðjM]¬\ëèoù5ÇÎíâŠïú;¹bkͽ§Ž ešÜ2v–ž;q¨H+|Mçø-ÆdÜTĬ|ï…ì£Pâ-I*¥Ç½±²j¡"ÿqulΞ¸]Df«/Râ07ÞYÌJI>uÀåÄ€K öYÀ~´vpÖLï à8àxà¸4­,AoF(¬úbÞÉõþ—.0«÷Â¥-(ëO¨ua®,öý¹s¬Ž ‹ï©9‡í:wnÜ\ßÊ÷îDKÓ—.Ô¶§Yþx}Ÿ:¼üòË<š@ \ådá»ï¾ã–,f(Œw8o:¡88.8>8N‹ðÄOT< ÃápÏ“:¶/óä 8åñø¹=‘î§×0wBôc¾úÞ>00š;|/aO’L*„©q­3aï"ËÐøŸÿügî®W/7âJ " õ¸Ö©XãK{‚,à ˆU„:gRÙ‰pöTÜ™p ްÿo>¿…{¤[#çÛPçXµ®†ûîÔˆ»$îö[GlÔÔRÇ›¿wÏö¶çùÙod÷J@ƒ{0ö>0wÂÝwß kkk•ïËÁHV]†IŠ–ŽÍ’œ.ûæ›oxfF̧€Ïãæ–JÆà{S˜N=ö×>* î<ßcßMÁ К€c™à\ÙB¯(#)ÒB²°j]åûb*-è Ü !ê&¬¢_Ó©»ïãÁZÐN·ŠÞÔ½{ª3òߎçg¿‘dýs.ë”¶»ÃÊ@FŽ­¶[K·€Ñ0ÆŠË,qÜ‘œ‚@2Q®ŠÀ˜œ3ƱÆå™™Ž®aÌÇ€ œ(µ.[qೕ=‡¸½a¸‰ÛV+/Isæ~gÞw[´¥ºmƒÖió÷Ü7! &Ðk§FÕd¿ÈØ·¡›f¦lw4˜ÆËȪu÷¹†R¼«Ú LQ—îÌ+«p¢C»%ÃÀÉÚ²:%PŒ”œ±{U¥fí¤ß×ökÙ9¯8'w{Ü»"•ÈÂÊ÷Æ;ÙÇt\, T9õ@)Åù9ùGå1eõùcè§ã‰xÿ¹“|ÍIDATºD3ÝJ¹†=Ci§åêàÅûœ,`Ä=æbŸ[Yrûõ-¿JZ[M¶€Ñ0ÆŠã…ã–­TÁ-µËK&10 è¸YfÙD’`³Z{˜çqNA¡%ˆ+'hý;a+€^ô,àÒ_ô,<úè£[˜„)]ª*¯œ”ÿ¦*WììšTAt´X#5W ]Ë+Š6XxiìrCCRMð}TT<]s)YX©®Ò}*U$LÁÙcÂ5ñSt“ý~m°™’s¼¨PPÏÀé$ÞË”…1”¶¿ÕRÀtØ{obƒ5ñ—ô«á\2å1èzS05¡Tå\áoæÞì#+ÏHÇEaãb›ºXQÄÎc˜øœü“Ò˜fõÉ8¾ãa_èB;¨Œ·Ô°r5þ¿º·Èæd§p[ãEÊ·“[èƺ‘…l­`gRG…œ®È¶—±¶Ø³J¬µ]Y‚ÞÐ=ŒÇ-›:ÂÕYÀØÌ«ùòeþ§-ˆvHT7³° Y`×ÈFÕ¢í§¹'?s¥=/ûƒÚK•¸÷4ÜYXg]ÕûR‰îÌhí¶øýg見÷´-¥FœÌÚo¸ÕES¿Ïñw|Ù+Wä½™{w²|\˜®éŽŠÄtŽ.³ë»à%0/ÿ2‘ãå¶+ýà»^6X©éó§ZùóˆqÒJÓ4WYÀ@¸…[B§ƒª3‹¸ËÙØH°±I™,D0Ò4°Óóœ‘ø˜^ñƒ^m7²¶4؈³=f[zW\‡ƒt+ŽŽ_yÉ$hÍýùÏæÿãvÙÂnckWC¬,à \s¢Êû¬ü9#‘cÌMv ñŽ['YXo]‹HƬ‹>¿o¼¡’·/ν½:ŸÍÚIMýj>§s…?‰Ë{3÷îd³qQ‹Æ€;PJdfö9*‘…¹~°{‘hp"23ÞµÏã># 8¯¸ÐêÌ,uÆäB»Ÿ*­W_0 ‘@{ a K1»*Û®gmÛ³ÃÙ¹ËÉd¬8n³q8GŒ;ùáfU”’›°—°uyÖOÔLÉÏ*ý2Y˜{¯Ì¿ç•Ûju­‹,Ljin؈ÃHÛ”½«†^²à¶¸_ËÏ1EYò¤–ßC›¹w'ûX¸âÝîøžîƒKÈÂ\?>µÜ’tþž®Œ÷A! Mž…bPãÔ2ï‚m—C©Yƺvunjl»Žµ-b­e²pÐkæYÀôr2&ÚØ‹°±u·–,äKÅ€iAà:SñŽÈc¡ð}ÇúðxŸx‹Èz {#1ÙZM]¡hˆPVü=‘þŸMçWö.ð#}&N°¤_õço”z„Mðƒ) z3ïöMÝ»ƒ}Ì<µ œ€©ø`"¼äý«ȿ<6ᘙ¬šü8Ch£ÊÝÅd¡½ßÉBSÌBå¬"Ý,gWì+îqÀòIJ¥Aå¼ú¨Žµel/·Ê“)ôZ3dá1Öº˜ÜÅ’vô#ìElÍÞéïBŸ_ qtFïG+“ªñ¢gï©YŠÑ*Þq‹WY¡—õòŠu•ÛÈÞÃ^±r+¨©‹]ë›=ñ® O)W|ŠX­¹£JŠÜ Pׯ%ç&F7ÿ¾ÝU¡‡^â’¼W¾7ÞÉ>Šç¤%ËÅ9Y«Ä€UäUÇ&˜ *)Ö;)q˜ïÌ‹®ïߌÇKWCÌÎÕM©e.‹Á–ºÌÈh&Ø6Ÿã·!Ù²ÀY[4‹ÔƒáÐȹ4 qPëìjˆ³gÏV¦"p3*a¯aoï:™@2B¿ÃÙk“˜½CâdkÚ±wÕ\YMýª?‡í Ãh%y-¿w'úX2ê’¸¶=Íòy}[3>W9Y@àz}\·_•‘P–zÅ­%™17¦ø”RÔ¿Ú“Ky«²ífÖ†,W@ˆU<䱌±bty9Ï’‡òÒÉGy„4aÏI>·øœ’÷‹°½ˆ@ErL·Œ,àÜ7&ñÁ%v‡`lIÎî²ÿ·‰ùG¥Ò‹+Û¦8…ýÈXqê_¶˜y³ŒrÜ­·Þ:wž@Ø+xæ™gxþ\¹CÛÞ¶K_øSü(!QlY@à^¨h0ÛÚÞEÈ™"ZëYʧDv~‹’Ýc¬¸wæQÀDJ³@‚œ¦©Â^N¡áÊL}âÄ n¬|ðÁðÅ_p"¹BÈû@ ì1²€ÀÝ 18n/ï:ùSÛ˜¦ ¶ãÁîpÆg¬Hp\p|êvÄ)³4»GŽáË' „½ôl⊞ӧOó) ŒÅÁœ H~)9Wã±ïÉWƒI½ ‡nÜ›ž°sÀqÀñÀqI’z‚RrÄý0Å.@ [N2àšh´T|ðÁ<âž°³@¹ãàã± xÍl‚&@ ¶,dÀ$œÿFÒ€sàŒ´½@ù¢œQÞ(w”ÿFî͈¡C‡¸ —æ| °ídË0ð·žEk—YR*á­ÊåŠòE9£¼WY‹^Þ¦wšüúë¯I¸@Ø~²PÆ•+Wx Ρc°Ýùóç)½ðŠ@¹¡üPŽ(O”+Êw3(OC`ãæ³åÈŠ@«÷_ÿúŒF#¾?feÃMb>ýôSšª¨ÊåƒrBy¡ÜP~(Ç­Êh‡ÓY®Ìó@ز0K>ûì3xå•W¸•ŒKž0ƒ ºÕѲmŠàßÏÀ~cÿQ(” Êå„òÚŽ”·H@2²€S˜—@ „]' ³À ~ø!· ;Æ•$ZÒÏ>û,w»£u½(©ÐÕ ìö û‡ýÄþb¿±ÿ(”ÇNä®À5êẎ½d‹°{ˆa<4Àöc@ز0 ŒÈǬl/^„S§NqŠû 2{衇¸+þ7Þà«þ÷ÿÖÖÖö¤À°]Ø>l'¶ÛíÇ~`°_Ø?ì'öw7V"`â¦,fÉ Â~Ôõbï–òFoéS GØ÷7Ÿ_–]4]×_”…´¶ìíëËü¾.¥Ýew÷W¿NyD¶Uù~òÉ'páÂ܇{ ›£øÑ޹ã~øaž öùçŸçîûñx ï¼ó_-€.~TÞ_~ù%O‹™àÐÂÇÔÕåT±ø?ã÷x¯Ãëñ>¼ËÁò°Ü¿ÿýLëÅú± €íÂöa;±½Ønlÿ^"7/¿üreEm(µ_ÉÂü®° 8– ΕeƒÙN×SööõEì;ßó`:²Ã‡Ýñyˆ]i;wƒò$ˆ,ì p¾—¢2FKþÍ7ßä ÑrÇMhžx⠾ĕ7*sL‹>f.D‹:Ë3)MüŒßãy¼¯Çûð~,ËÃr±|¬ëÃz±~l’«˜í±¼"§C‰,¬Á°§ÀÀ]ã„` tÀ°Ç`(m±£ª¢§»£VÉB0Ö¡Ý’ÁÄ“ d!ñÇÐï´së_3ÝuœíÐ- T9ÝÙUÑ`Wû¢;ó 9œˆv œ¬-!+KÅÙe“`ª";¸¦ßǾ ]I|×î”êZÒ×P ïF[IT–çò>.–5@d°ÇPÎâ˜Å-Y8RÞî=SˆýئVÙB>ß9Õ E;pšËŽ]1] kàø>Œ‡}~_ߚϱºŒ´Š6bíÐÅí]Sìí’zÝ„ñØ›)rÇ‹ %ÜÁ{;à$ØTT沘¢Èêl)`:S˜Nl°&~þ½¤šàû߯ëÊÊkjKä1’ÁäÒbÃ;&%y.éc½¬ " „=Ü–º¼U5ZÊz€É‚„JÓÊ%I›ˆsìÿþh]®à¬bS¶š²£ *Àv)– †*HÙ€ÏÎEi]Ý‘WxÀt™]ß/)È÷´…UžyDQiLC[xúVPjO 7^ÐÎ ‚ÀKe÷µ5S4¶…µÛ@™éΜ<£e}¬•5@d°ÇPNùŒd“=}óÍ7$˜J„÷ °Ò¹BKÉBfa£;Ý ——9:¿vR •§<2%k 5ß¿BNjÈB>Ý #mWæAzÉBˆ½p`I[šÈÂ:ú¸XÖ‘Â& xàÒNÚj|’±‚Àß÷8!Ä#ˆ—“…vJø9Tš¡-æíe‚¦²¿óëdÕäVzà ¡SÃ)+£á\6ŸßÑÀ ˜Z &|ê£Õ·ûr¥,V'ë=ý¿ÕÖ}ºÄ³%«àø„¾ '(¾W ˜†ÄQ®3M=KÚ’’¨Vo!O&W’ç’>ÖËš@ ²@Øãdá±ÇƒW_}•„²ïÈ¢ÜPwŽ–c(0™ÏÇWÏÅS¡øÚ=³¡ì‚É@‹lõAª8õçD½-Y.Ê“µb¥@]}¬m¾ÙÓ$Aq-WîÊ+ÿÈåñ<¸0UÎÑÔ„!;¸õ¿Ž¶ §aØ+åzX+ÉsIkeM Y ìAdKFñÀ\Ãá„BØJ¦Âó”Dq²Îs%×Cnu¶¥„×ϵ‡}†¬-ñ†Û’Äuý[ÖÈá*A¶™YêéÝR*”R˜€ ZÅi†=±Œp/µ…@ ²@ØE`êé,ÀÉÂ-·Ü²ÚòÉmN)L)~ ð§.øQBm!ˆ,ö 0-uæYÈRhã&W' Û›R˜Rü‘Â.AÓ´œ,àÞ¸ó$¦°Þ:²°u)…)Åo¸o îQ‚{ ¾‹(¦&ÇTååX:®¾ƒ@ ²@ØSÐu=A=øàƒðÏþ“ﱕda+R SŠß}ô?~n¿ýv”úúë¯ómÍq÷R ¦Ã½I('@ ²@Ø2<ú裕¤~úé'Ç€»nn YX1¥0¥ø8yò$ßÔìÝwß%B@ ˆ,v¸{fFŽ9¿{úé§á­·ÞÚ²°©”Â8Åﯿþʧpœ²íÔ ÈaG€óÝYÀ½!ü1·^W" Û™Rø§ø}ûí·¹çI@ Y ì(Î;—“…Ûn»-ÿcÞÿý ‘…N)|RüÞwß}œÄ‘ÂŽãâÅ‹•'3 bºûî»y°ÜúÈÂ.¤> )~?ÿüs¾j…@ ˆ,vY_·dë¹çžãË)¯~\Ý)~_~ùex饗èa%D»ƒÏ>û¬BÊž„$IxÐ#n0upæÊ÷VŠ_\ñ€¹‚ Øå–Äp¾œŽ; ÀÔUèv»Ð×mØ)©DÊðÑ$ØÒò(9@dáÀã믿®LC E<«¬üqîaøê«¯€DöVŠ_\«S6§ó²iœÌr Çèðé}²,wv5­µú”@ jÅn’»MôÐ+ÔRÇy¿)9@d°À,€YÀ}!Y°èUÀÄ?˜½ —.]‚/¿ü~üñGàVS•$o¾ù†gfÄ)˜xiÓK%£IŸQÎà‰•' ê”Çf$0R08s¯m©,r`äA£”‚œ~P" „­&aÊȦ ¾|ùr㵎ãðÜ ÷Üs_=A©y·îÀ̙٦^wÜqO½2ß¼.)È®0É3=”òMè\!Æ`kE:k©£BžE»DÜÔÑj·¡Í¬é-Ms­›&ô¥b)ÿζAKï‘û&„Ází,0tYÕõ©¹Ù9¯8'w{¼ŸÒR²@)ÈËåne rÈÂ>z 2e…™1Ý3a÷€^ô,`†Fô,`†ÍM{R+¸Ûïr…`úbŠÅì2åÐíósZºZe¤i`9SðœW†]Ó›# ‘gq¥Üî`'àÍi®óôÙúìÉÃJóÔ×mÖHÍ•]×0Áâʯ-s5¥æN¦¢^¦à\o fJtäuJA¾µ)È " e²€žÂÞÁp8Ü‚˜…Ô ù´ƒl eéð½`^?8ö@C—~6ÿ_Q°iÊëtb=i®e½œO"ýΨ*õ.ÏG<@j•]-NÍ9ÚLœ@\MtE)Èw$9@dထœ†xóÍ7I {[²"# nM(¡1ÏO¡CÄ,ϳÂHM§Zíª•¾HÁf9+6”æ`.íwªxËŸ3%ß”š{¾Þh%²@)ÈWKAN Y8Àda¥í© ÛŠMçYÈÓPÓA®Œ”!³T'W¨ÝJ‘OZ'0¨Q@sdaCi®ËÊ/\¬ÔËd¡!5÷|½3–1¥ ßÖä‘…Jpéä©S§H { ›ÎàXQl~º"UL%Å,,a™‘…üÉ€gДT;u½×“…¥¹ÞYhJÍdqš ~0…A¯=³@)È·/9@dဒŒÂßôü8a[°©½!RE¤§ÖmàŽÁO `çäŒH0Å¢”¢êÕž\ x[«¤íF÷|Ù]šëß•ÛPRÄY{ëSsLŒnþ}»«B¯œB›RoplÖŸ‚œ@ ²p€ÉB¶|°÷°s»NŠ×›€é°#H6pïV¦¹®bQjîôLÕ¦åÞ»¸ºSD8YÀô΄½$ ˜ÍÇhÓK) WöV rÈÂN? :tè?{˜ ó/`\)A8Ø[)È " ؘåYÀqL)Üö2p§ÐãÇóTÐ'Nœ€sçÎÁ|À!ÑÕŒ›‘÷@ Y l)Л€dÓ7cgT:„½Üדh>}šOQ=z”çd@—y‹è c3@d7ÂZª=ô¼ÿþû$@ Y Àé$ ªªÂ“O> çÏŸ'¡È¡z,àÔÏ=÷?@ ²@È$!# /¾ø"<üðÃ$@ Y À ¸lâµ×^ƒÃ‡“P@dP1edÁ¶mîaøî»ïH0@ ²@À}2²pæÌxì±Çøº}@ ˆ,8t]Ï—NŽF#°, þö·¿íÓÞÆp~h€íÇÛ^ϘÕ3š{^WG; ‘Â®âØ±c9YÀŒ€˜!pÃJ¥»ðµ»C¨lãh|«Þßæ'†Q·,VÀ©ð‚58ÂÚyóùíγ/6ÿi©ãuÉ-ßM°-ƒnº;(§™v.ÜMw2Ü OêN@ ²@˜Ã#<’gpÄÿúé'ž¨iC)ƒÓm…Q¹ô-¿JZ»@B+ß–·gzU…ó›Ù-“·‡¬#O¥mœ›äÖ9à¹cÐ$82LvL`3íÌÛ3ßó`:²Ã‡ÝIÃPiAg‘§Ëç ¥#'ˆ,vÙn†˜&øOúSîmø×¿þµ!²ÐÉ-ÑN®ìªd![Sr‹Uê¨à„……;P: Û6h6?/÷Mƒ ôÚâúŽ:‚ìòØ·¡+‰ïÛ ¦3úÃ5:\é*x¤C¸,¤uš&ôÓë¢Æ²›ÚÏÎzÅ}r·Çå!q%€ÎúÔ8%ƒ~J[†Ñ‡opR£¥îx¢²ûÛ¹%Ÿøcè§ò@ _˼±Ëä"ÁÀÍ.œBObŸ(ï—aÁPĽ’¢ƒ/k§GlîÌ+äp¢C›Étw:dõH ¢_ +•}ÎäÓI¿¯—g*ËUNeªç]C)y\öL­Á°§°>¯5ËfIÿ ‘ ‡œ, 7áŽ;îàßáÊS§Nmس 3˯‹/ïî®Ëd!‚‘¦åLÁsF\)us«?=UmÖHÍE×0Á⊣ V(%ºÊ%Õßw@EEÔ5Kñ ‡åŒ<Ç¢œ¡—,$ FZ§¢ÁžL!i,»¡ýLYs÷=SJ®73%rª„í>*­d½:ü³_²äÝñ+nYµ„%Ÿ¶¥%kàø>Œ‡}á¹±N68ÉÈ<$•Ï…,¥þlSãÿ«¸Åñ’vfã¨è&ŒÇ6ØL‘;^T(Ꭰƒ§7R8!ãÄ&kkK“Ég:±ÁšøKƪ$6æ¶© o;ÏŸ$5HÁ°Ç„IiìšdÓÔ@d°þüç?ç[T㔈/¿üîºë.øõ×_×M¸EêÆÚýôåAâê ¦!ˆc4tçsúìÏ>ËFÕÂí§ég‡FE!H‹Y¸–*ñ¸ˆ07Ú5®ÄœD$/E=U²ÀëÔ'%ƒ¿¹ìºö Jyn?æeg{2òrunùÐGîõlú¦ÝÎÉ‘fû¥¶´+eP ÊDñ YˆgÈÖÍHG&[ŒKÀ¶,kgy:©¶)ódãÀ•t[J§œ‚ŠÜ ·j¾7Ë“µ“µ«;*¦‰]f×wAp;1E"éÎÜØ5ʦ¡ÿÈaE¼ð œ, QÀ}"0fñàƒ‡~¸!² ñù‡8µ@»`ÛåÇFj'UŠíªE›¾Ð5'ª(­òçLFŽ1€‡Ö§‘Ö‘À¨›z(º]èvh§¯›Ì“…J\é7•]ßþÈѹ.b ¢ªf÷ò@¾ ÑtÀï·ÃR¿¸Û?É ›+Ýù2\T¦¨l¹Dªý*Ú²´y{êƒ&¼¡’Ë%Îå¦ ‚6ãêo–§h§Zê ;PJdfV†%²Ð$›†þ" „)ž‘,à¶Æ¸E5zo½õ<õÔS$ ©ò ŠÃ, à ,O(ÆAåž)Žpqye²Z•ö"¯rhsr ¨  c½W²‚çÉB9ر©ì¦ö‹û˜ò*ÍÇÏZ³Ó¡P„tÅ+bš¦J²¸ÊãJ½óe&<àË3Êb ¢¼ßÒ Y(úU" ËÚ9מÙqv+«%Œ´þ̃PL÷,—gAj †áèYèƒKÈB“lúO ˆ,VÄ«¯¾šï_ûB|òÉ'âõ›$<†áóÏ?ß8Y@å8H-PYa‘ÊLÙ†àO\©Kª-”æÈºÂy0¥bÀ4Œ Žp)·rE`cü*ƒV=wQ7“…¦²›ÚŸx£4ÞÂ?˜Â 7ë9ÁêÆ¹‹Ö#€«!|Ï…QCÀW”„cÞgY5Ùr†‚áÔL2åÓ+݆ÀŸˆ8$ dW<,mg¹=¾ž'ŽPQ…Ì­÷ôÿ,˜5“›¬‚ãGú.Lœ QžylAG'`*>HûÑ/¦pš¢ÕA˜$U¢×$›†þ" „ñÆoädáé§Ÿ†wÞy'?7ùj‰ådA(½â¾„2H= ø‚WJÑíjO.ž ÅP'u«W§%²ò£©YZ}‘Õ€ZŠÂ/ÃõD€d°GË1 íùe”‹Ë^Ö~€‰ÑÍïiwUèñxˆr[0ùIè8Ÿ×  ]ÍÊc<FJ¤ÒùNªùØèü{¥ßçÊR[د,6ÃYÞÎ…yDY¾Ùž• h;WîŠÈ­¹£œ µJ+,jå™¶«%ËÅ9Y«¬Zp‡½R®‡òØ5ɦ¹ÿÈa¼ùæ›9Y8}ú4œ?>?÷Ë/¿Àý÷ß.\Ø¢Úb™…™¤Ê3Êÿ_xQ¼kâêÊnnGüüb02Ó^EiÅEÌòŽç%G¬ÑÆ%ØÜÎMʵ5žkë"y–¦!’¸¶=ØÖE}_&@d°…¸téRNÎ;¦iVÎã4n.…™ «#°„•lQfåœ, '¨GK " „½÷Þ{/' ÿøÇ?5^¹r…Ÿ¿xñ" lUÕLÁS({ü© ~D^ÈaÏSúfdÿÇ¥ZÆA÷Þ{/'ÿüç?áÇ$áÈÂAF»gdáßÿþ7Ÿr¨µ“þþ÷¿ÃñãÇù^Ù}tÐq5Èaƒð}?‰~ýõלüðÃ$@ Y  7!# ›€™/_¾L‚!‘‚ÀW_}•“ô2<ûì³|…@ Dß}÷]N0~wœÄÐ@ Y p|ÿý÷•Õ¸Òá‘G!ÁÈA Žãœ,¸®Ë3⩪J‚!‘‚nI‘Ç©ˆqù$’@ ˆ,x,dŸ|òÉʆR„Ý@ ã¡£ e}$D» Ü,*# ¸©âõ×_‡S§Nm@¯‰Ý ÛÝ!T¶ r4¾¥ñŽù(¶º waÄw¢3b£¥–:ÞmY†58ÂÚsóyÚç@ ²@Ø·(o$…øì³ÏjÓ>/Vª“|{â¾åW•tk'ÉÂfÛÃPiAgàVÊë&à{N}ˆw¦3`HŒø¤[=ïn[–È p,œ+1ý˜" „ýN^yå•ÜÛpûí·óe•ëUÒÜÚíÀ$Z¤¤c°5%·Š¥Ž NXXÑ¥ºmƒÖióórß„0˜@¯-®ï¨#È.}º’ø¾ÝÑ`o¤Lµùcè§õ u®™Bé¹FѾV[ «_j¥Û(Ï ® ˆ]Öf nZ[2…žÄ>;QÞOáˆ{%E/->öŠ~ÉÝï‹T" Ø}A[‰í–ÌêÈ$²z$P ƒ’°~¨ìsÖ·Nú}­³ñ°,Påt¼”âüœœ¢5öÖçµfÙ,é?@ ²@¸ È™3gòïNž< .\ØE¯3벋 ¢;ÜK0š”•t#MË™‚猸âëš^®DôT)u´X#5WF]Ë+§6X¡PÆèŽ—T|ß•]×\;Òû[²ŽïÃxØž;€•5’¦8í±áZaÍ{³äÝ)øaÜX«LŒIª¸+Ÿ‹~JýئÆÿWq›fF*x™Lyº¬.3%VòŒgAÑMm°™"w¼¨PÂAÖao„÷ÊbŠ"kkK“É~:±ÁšøÍrdåi;6¶©ó>ày.ÏY9%kpä7¬ØÇ&Ù4õŸ@ Y \dáùçŸÏ¿ÃÇÁ`°n²À­^7†Ðî§ ‚ÄÕ¸ÿˆc4t±góñ¨DØgÙ¨ZÑÝá4ýìðϨŒ„âo1+Úƒ ðÁR%®³âþvi®?†*0Ù`ç…ë_ÒžŠTÉ1åÝXF_nC²A²€îv>5 0 #ˆ£\g*,éu´Â1¿FVMAbœ!o‹Â§<„û½ÕA˜$µd¡±ŒdÊã%:º ?±HÈ®xH¼Q³a‚LaÐk/ŒYèð}ïãG(:.2·ÞÓÿ³ÏL^² ŽAè»0q‚f9f± œ€©ø íG¿˜>¨È©D–É·®ÿÈá*! ¸=õ,žxâ ÇKÈ‚P|¾ýö[@ ˆ,“…{ï½þýï“@@d°˜,ÜÿýðÉ'Ÿ@@d°˜,†®ë’@@d°˜,à.“—.]"È¡Š›o¾™“…ápçÏŸ'È¡ŠÌ³ð—¿ü^~ùe@ ˆ,ªÈ< §N‚ÑhD!jÃxh€íÇ$ ÈÂÁB¿ßçdáôéÓðä“O’@ûVѺ¸õ·Îʺ>­Õ‚þ¶î›±GX7Ÿ÷Ny w=ÅG÷¸nµ¼Ddᥗ^‚cÇŽ‘@û¡•oÝ3½uŒ¡Ò‚ÎÀ-Èßf{+µäl 8– Εx”ù6ñ½Ñ|σétÊvÇ¿² ý#Y ¬Ÿ,¼òÊ+pÏ=÷@û®ÑaDAEb„AÒ!·Cczm nJ’)ô$öÙ‰Ø=JaI·˜DèH¬1]‰/):x©žŠ}º’¸¾ÝÑ`‰ÒÃf÷)íÊ}óu¬Á°§°öˆmá“`ª"å×t ‡+L[+î“:*8aÖÏ%åùcèwÚ¹w@3Ý¥mD²€DK_à’ ':´™\Y˜d¬½ og]û—ËJ·,På´Jq~[úG ²@XŽC‡q²€[QßvÛm$Â>„=TT#±ÊÅÐKwÕŒ„"Ô&áÜçÈc ‘ƒSföØ0‰ÀÈX¶©ñÿUœ–`¤]õ’j‚ï; ¢"ìš¹¢Òkc Žü½E™8ub:ÌšŸØ`M|^ÞHÓÀbßyΈ··›zKÖUž¬ãû0öy;úvÐØÆÌ³ è&ŒÇ6ØL‘;^T(áÞׇ‰Ô)œ”ñ)Šºö/‘U&cE±vèÂ#ÄÎ'ÛÕ?‘ÂÆÈÂz6“"®6D+0'Ä¡‹Ö¬:NÝ3d¡ò9ƒ)2Iw ¥ŸU+ÿŒÓ’6Iëh1 Ûƒ ðÁR™5ÝÖRFý}óuÊ/+ÓpëÌßâØM*õgiyíR¬A T ²ÁZÔÐÆ”,p/@[Xå™ç@“Æ4´…¡o%¹Ï·©¬X½ÝQ1Uäè2»¾ ‚ßmCÿDËÉ.›Ô˜µòÕW_‘Pû Œº© ¼Û…nWvjíºÉb² çŸS“+¡`4'ª’$ Ž1ˆÖ/*©æûæë()?G$gŽ+„0R;i=ByË¥66—'A9äÂEEÌuC39õ±ÞPÉûœ5·®ýë‘U9.Ä(¥€ÊmèÈa9n½õÖ|éäÃ?LûCöB›“E5```è½Â޲ùø(¿^ZBÔŒX”ÉBjÕÚ ½Úõ÷5*¿ÔϧLRvŸ+E‹O¸'0˜icsyL™Æ‘Â`AŒáˆšÚ˜ª²O7ˆÃHeY×þõÈJ+1 ×@ÏBüíêÈaýds,<óÌ3ðöÛo“Pû"°±—*šÂ2GÅÁÝÓÉ”OKttÂÿG§gd¯ë L’Z¥ßæ ÕÞ«0 #ˆ£\gšZÙ ÷ÍÕQžƒOË”UpüBß…‰¤V¼ÌÈBþdÀɤÚdeוŽ¹Ò—U“[ñ3Dj8]Ò·l5„¾ïç‰#ä«„õžþßê뾦ýËdÅc :8SñA:&ýbú`ËûG ²@XŽßÿþ÷œ,œ&aÊ¿úê+ñlÇ1Üzë­ðßÿþw/’I¾mßò«/’ÖV“…ËçÊê–]8Ñx[NÀw®›N,˜x;e)–ÛÃPiAgà®K¾½Ñ|σétÊvǶmóæÇc=@ï×åË—7WHhå[÷LoÅþ % n©bÛj™nÃmú7^mÓîþW•ãÆî5$F®Òí¸Êo˜ÈÂ>n …d÷„À xåô§Ÿ~º®I±/}²÷hõEƒ­)Åžöœ°`᥺mƒÖióórß„0˜@¯íI?‚0eÁÞw-¿Ï°Ç`(â>IÑó}ïcÏ‚®$î—»}èÊô†.øV7tç±oç÷´;LK—$¬=ªRXCÃa7¸¬kOÚéd =‰}v¢¢_¦ },SÒÙ7Eû]£G«ýÁÿó¶¡;pJÆÉ”¶ £ßàJN_`‡Ú-™Õ— 3duJ N}›û™¶Ù²@•Ó±RŠóÕ6+l¬ËãÁêóÇÐOÇ-'Ít+åÖU°â³™$›sU»F‡Õ+ƒ’ŽEþø5Œá|#Б,X¬]iþ™["×Eý_*Ó…cXÿ{Ú–1Z×o¼¾ìÙ6~¾æ7¸žßSͳ¹üüò¾—«oÍɱùý{vé}Óãò’Jdá ü†‰,ìs<òÈ#œ, '¡œæc^~ùåu[:c§]|Àº#H¸®+¿H"iXΦ3m“Òxdõ¡Ì}ÆÃ¾°Dí y¬–àÊ•+pï½÷nò)÷ ‡Ï×ÈcÃ/ž¯¡—,³êçùþò™æšåZ×ÿuÉtv ~OÛ2Fëù7”=צ æ7¸ÞßÓ‚gséù%}Ÿý­~3Ûæµ†ñe¤†—Í”§ëMÁL‰œ<ãYØï¿a" û=öXž” É2 Ûw]ÛUg¬™Y ¡ÝO W_à¢L Ž=ÐÐE—ÍçáCÈ>ËF•…w‡Ó|¾? ‚0C$üÁX1ñkƒVÝ‚9ÓÙ¬“YJ Œƒ$½]£–*ñùØ0)¶À˜³„f^nqõåÆû¥OªóƒyûÓ6é©1ò:tnEÐÇ— º K.àv[0úÌê¨Ì‡¶¥ÔM¤ïÙÅmnê'o3“awTFG—Ùõ]ºµÚær2™ó°1 ðå"¬Ôú±Z†wß}ž~úéM=ã¢m2#q@…—?c8ÛßeÏ\ƒ\kû¿L¦ ž»ÆßÓ6ŒÑ:~ãÍe϶iñopéï©ñÙl>¿ž¾W«Õ67¾¸‡Eª”­KUÏÂAø YØç 9Yxçwòïq%îñå—_®‹,ˆ¥8eÉ]°írðS#µ“¾ÚUÖ>tšU~XåÏÅ £J*÷e3¾¸ÿx‹©å¨J2{ÓF º øÜ1f}âEÈË“çã¼ÜäÒË­Ú>XLvò6…"(ªoC4d'«Ã©Ÿö†JÞÞ8ŸO^Üæ¨¡Ÿ‹æäÝRzζ¹ô¢™“9»_Rü%V?VËðÊ+¯ðcu$0ꦞ«nº]EŒ9SPn²| «ílzæ–Ëuqÿ—ÉtÁs·ä÷´åc´Žßø²²ëÆ»üŒÖñ{jz6›Îo¬ïórŒ–¾ªï›Y²p~ÃDö9ž|òÉ|bv©_|qùTÄì<(ÉÄ<=ûŠ[#X|‚+Á‚°ºÐšXNòûÊ/îÉ ÓǹÏÖâ—•kÖýÖ›³Þˆy&Ÿ»®gܦzö íŠ%Tmß2²0ŠuÝŠÊ(uŸ–_Ô‹äïV"­´-umž÷ºTΦ/„xF>}ð—)¢T擸PÒH%žú±Z†'NpïÂÊ`c‚ÊHQ Æz¯°à–Œ¡Þô¬Î=sÍr]Üÿe2Ãe¿§-£uüÆ—•Ý4ÞÙoÐýfùï©éÙl:¿±¾/ “eï‡rÙ3V÷ù YØç@oFÞxãÊ9ô*>|¸yg¿Ù ŸoOY²,^$‚5Ëìå‚?ð—·¤Úù\ãV’…ÛOêÁphäó£h}yS– aœ@MA“3«&sP ˜†ÄQ®3,?PÁñ#}&NÀIº´;º ?ó¹ø²[/Y@OBoa¼—µ{uÕ9àû+Á# ?fÎüÓÿ³´º67õ3›—ìhàìõ¤}ê®Çj›Ký Ç|œdÕÑ %ͧ“Æj 0õ8¦z^"°±þŒeν8è^]2†Õþ6ôc‰\ëûß Óš1\ö{Úò1ZÇo|YÙå6Õþ—Ųg³éü†ú¾@Ž ã›x£4æÊ?˜Â ×^³°ßÃDö9Nž<™¯†Xäî}üñÇáâÅ‹ dA<¸zÅňV*^$J)WíÉ¥à˜4˜i?SdÃÞÌšëLî2/¯ÑeøfOX˜Aq-1(b=|]›ëû)dØ’å✬U"ž«m®ö'`ŠK*•ÛI_:ËÆª¸’Õ,³èÆ€ZŠ ¯¸}G=84álÿÿöÎlÍqêzûuCñ5|¾߀uìSŸ“Ä´˜Z‰IƒÃàf„8ÄÐfPAþ ‰1º"‚ A ëÛkoI–lKvWWSÕ]ïïyôtYÖÜ^ï^{Úþk´kËsm6Ýø[ÿ?]w´ËÿñÖ´ëe:sºùÿ`ëÿ§Öïæöïîîu§ÿ?Û~\kPžï tV¿ß'äÿ0ÄÂ5b,Ä‚mÛk×?ùä9váòwúKE 1É[?%åßW‘~RI=š©ÖzþcÇs»c¹z\¼¡ \¶˜’[ sºBɯ¬8—&q=¿K)©(Ër;áÜ:Ûè¥Ûb½Ì›ëY afê}m/óú{æücU>Þe’dú!h{‡íõ½”ïϮ߃]Þaûÿ§ê]JÚÕ2µýÜü.¶}7wûî^jÝ×íØü~U’+ô{vüÿC,\ãœ={¶ÜHê±ÇÛxÏ£>zÙ#ÒXbÙ¢”ýÿ½n.=Fù³#+h"í6œÇGn Þ‚݆aˆÿ¤`‡ïæñùîo;]9 ®qžzê©roˆ3gÎlÖ™B¹òuî’¸jþË„ š;3-q¼€®†Õç“hAþâ(%MFá§09zkñ÷ß°Ûwóø|w· Àá­ ±Ð¶YÏ·ß~K†aHqñ¯ýë2ú‘X‡¿O,Jy)\žÎ»óÞ$€cÄÂ5O,ÄÂ]wÝÕzï7ß|CÏ>û¬¡^<ƒÇa§N‚pชˆ…k^G¡xÙ,8*8²ðÞ{ïÉî.^Y€È8&œ;w®àÈk-pÀ˜ À1âù矗?Ì£ÑHþ»Ó¶Ô\a0ˆpŒx饗¤H¸þúëI×uÚß߇QÀ±à‡\g±Zxå•WÊE™xYE0 8\þ Žˆp(¼öÚk¥XàÙ|ðŒŽ —»7b¼ïC!î½÷ÞËÛá€Cæ²w@,€Ë§Ø¢šÅÂý÷ßO¯¾ú*ŒŽ ¼¹Ù¦ Î à„[mÅG^9§Rpœ¾Ÿ—µ/I¾ã_g0¡Úv;ž!·Nv|~¹[`‡†MW¾cdŸN‰ü®;ÿÀÏ6Õ»º;êQsõ àÒð}¿œ:É!ß'žxFdž‹/Òí·ß~NÏ-·øͺXØÛE,¨ç‡SÂÀ§©¡¶"9Wz pFÞÌ&ïbú?»ZoWÔ;Ëp/!¥Gò-Hi¢íQì^ýĸ4Þ}÷ÝrQ&nÁa!pœàu?8ê•eÜG8½~Ù2î“›l Y8§Q¿S¶  Û/ŸïV¶7òZ:Ñ®áªË¡Cƒ®J¿Ó7hQú¯„ÆZŸLÛ¦_ïšâL~ÎqÈÈóêlŠ#—†•F_ŸæQ‹}š 5ûûÒ9º]–C–¯oåån:_}¶¥nyy,gN–¦®w5“‚tYoÓ[wȱkRg¯Gc¯hÙÇ".i–ÚZ=õѵn‘èçç·Új6#½·——cyÝ·´et££‰wxõ àÒàC±Üód2‘ƒ8Nüò—¿¤>úè²ZȦh‰Ø™ ¦rÒÄ­ˆ…ÔW!÷žA^Ò|2ZFJ± ùä“R,ðN7Ýt}ýõ×0 86ð>7ÜpÃÁ¾—5,ˆfË>~9Ž hõ ‡S:¸L¨“×Wº!Ö[Ër6Fµ 7Ÿ[-[‹XP×crÌÁzË}íüjË»¡nkeÜ Ü±Pv7¨ÃÊrA˜Ù%ÛªjcßâȈBÚ"Z?±.O?ý´ wß}7>}Zžà8ñÌ3ÏгÏ>{ùbA°ç-âž Ïå==Ý–Ÿ#oB»s÷À†ç—i{jð¤fÑ"N(M"ò½EÞÊ>D±4›¹‹„c¼Mç«Ï¶Õ­Á™v*ÝrHP¨#Vƒ%”C–­÷üïbðha“žN^˜PúäzÑV[ɱ}ƒ¼H¸øÈUãKFËîî¦ØN)–]¡~b\.\(ÅOQ{ðÁåtJ޼ä3G½x¿ˆK ÊI™µpz¤œSYgÜñ2â »ì|ð£z~£X`÷³°+³-ªi*·*jçòŠe뽌)˺O§+«yt‡jÌDãùê³mu[+c1ÎÂkXgAÝÚCÙšŸEKK箩µ,ZŽwØ«Ìiµxìõ–×zFmÖ‚?VÖz8„úˆpiüóŸÿ,§NÞrË-ôÔSOÑ|>‡aÀ±ƒw¡äïêwß}w…rH)IDË6½Ôiš%BÌ$镜“—‰Ö¸([’íxþ°êvðòr~iší`«J7D– a¸¹ë#KÛÊÿC×@,œ0ž~úérQ&^ò™·¬æ/Ç^4ìN“å¯Ò¹ËS!Àñ…úEdÿ}ûí·±08¶ðL³¼åo¼Aÿûßÿ`”«žŒÂ…Oa‚¨Ä8¶|ùå—edág?û½÷Þ{r#Ç™?þXÎÞÑuΞ=+wOå¹_}õÕì¦@,œPö÷÷kcø—EW_|ñ½òÊ+ôÈ#È•y$/] ÚÅ£í `G¸%Vˆž Á-6þÁåÁBÄ o¾ù¦ ÜýÀ«åýú׿–sªˆ G•WezóÍ7i:Òk¯½ã€XDß~ûm)8¢Àk,ð¦=¼Þ±äÈñB,Üwß}4›Íä¶Õ÷ß?ŒbeYVŠ^솧¡ñ†=¼q±ä¢6Õ]'Ïœ9#Ïó¢7<- €X8áüéO*Woä®·Àð*Žýë_¯±Ú¦t~b‘®,œ&…EQŒµåbl¢:fÁ0 yÎqœÝöˆÈw§ë &TÛÆ3ä¶ÉÏóNt§ÜmëÂïÓ)qßuçãK¼Öv_L¶®­í¬·×·èØ­2±q@Þï8nWû ÀU/î¹çžrõÆ>ø€~õ«_íàÄÜr;ÚÑ,¬‹…½]Ä‚Kÿo'±‘7³É»˜ÊÁDÛ£þØßpm‹S+·¶Uip¹Í™OIÆ»÷Å´ðfdçtðmŠVËvHéävN] ƒ@B],B:ší”jĸêÅÂ]wÝ%—Êå<ð‘w¡üÏþ³ÕÙ/÷¨ï“›l Y8§Q¿S¶ˆ Ûß k}²œ9Yšº·«™ù¾öû4j4ö÷É·*Ñ€Ž&ò\^cGæËëݾN^¼.ÒÅX^Úa³üðCyþ…^ؾ8Sš·xý”bg”ÿø'”ùf)”pèTú×S³ÓèY”¬Š….;°Yé´ á”º†K«]ßgzk"  4 È÷uôùÚ}®Ñ“µI,´–¹µœõ²©töD«? ( i¦wåX޲¤ÅX„N7ïʉÊüju¬t÷t:ªU^DÚÒ)ò·ütCýšÊ%ê'ê3˜.—üöL¶×€‚ŒZíp» ÀU!¸ âᇦ·ß~[ž¿xñ¢Œ4ì" éuÓ¼…; ÇYpLúè£ÄBîu£™ YóÑ5+‘á@Òe«_.äëÄÂ2Bpéb!’Ñ.ÍdGxFã†û²ÅDõß›nKd¡¡Ì­å\ yK»I”,» Ôa59Òš(Û="‚0 ²‘“Íå*œúRaøGFÒ±p`» À±†…?ýéOéܹsµ)“Ï?ÿ|{WĪX,Æy ·§ÄÅsyOO·åçÈ›P‡Ãè“ÅÚ˜…MΤ³I,pŸùpJq–Õ®©ÖuOˆ…˜Bw,óéêekˆålˆåP”¦r6„?ŸÐp8¡¤­Ì­å\)[>5tO³h'"ˆ|o‘·üó2ÈVwQžbèj:ÅlÂ0»‚ò§[Ò)òïéä… Å¡O®m)W>¶ o ¹j<ÊhÙ}Ðd:°Ý àØ‹…bÌo$õÐC•×ö÷÷I×u¹áÔf± œŽY GÊÙä‘yF8în¥åÛÏI}å„VIOöïÓéʸ2¬¬5P¹&œ•V©¯{µA’§kc"šŒúkáø¾>“⢱̭å\-›¸º°+3F–v í¡Š‚DK[J§¬©5+jéD›ÖYPeØ–NâOËñrpaõh(WQŸ½^oy­gÔf-4Úÿ2ì€XWXàñ o¼ñ†ÜªºÊã?.Wz¼|RJ’äÐVIÌÒ¦´RŠEkY]É()ÿnH'7R+8®'w°2¯—ËÁ+D¦‡TÇK¶–¬Gº–Ö¦rUº!2eËK/Ûá¾kÄ8bF£‘ ·Ýv½óÎ;tË-·Ô®óTJŽ:|ùå—0Ö‰ !»<0¥± xD±(‹…ba¦*¼üówÞ¹v\‹d.| D `E,˜¦I®ëÒí·ß.§M®Â×Y0|öÙgôý÷ßÃp N ¼¬s±7ÄK/½Dãñ˜Þ}÷Ý÷òHÞlªX›ŽÃ< à˜ÂS&ù‡š6>÷Üsr­ ÄðN“EdáìÙ³ôꫯʈP Y8sæ ½ÿþûtß}÷Á0 €âÆo,8²H(b €„…‹Þ‚â‹bÈ—xGžåÀ3–eÉîbÈY,Üzë­ò_^C7“zñÅa €J‘Àc¸ûá믿¦·Þz‹&“ÉV†4æ½¢ËÜK ¥ùÄ"'LÀŠG™7@,€+ o Åb÷ˆàyõÆÏ?ÿœN:µƒT»!vªmEärËädk‡ÝÚNІ›°& âùQëž)M‘FÞeûõ}:%ò»î|¼cÞ‡¡I6í>©v·ø ýßÿýßVçÕ/[¸}*|åªXÈÂ9ú²%lØÊÁ„³¡<7ñWLêÓ°Ó¥±Ÿ§-hØŸ=õ9‹\ÒµeD¢oyÒa›ì°gs²êZW3©ª=|«/Î÷HëŠçº&ÅåymÙRïhôÈéúg7Ih¬õÉ´måÏ&¢%=j¢ŒûeÞ#{Fzo/ÏÛ Eº½>«y³ ÓСAWëô«é¸Rì˜Â"±kRGÔm쵊E™»¤IÛ4Ù¬%/Êë<Û\§õrWíÑü΋t-G¼'­³ñ= À1ƒ»Š1 ¼rc±ÔóË/¿LO<ñÄN-]S´(ìSâQ‰[ ÂQÊÐyÏ / i>©H„ 6/ÅÆÀš•Î[$ ¢áÆëŸ‹ôö4²=Ѳvš¹¡tBVáÔFcrlµÐË®€†ì$§ÈVW"%Pc$’@8Láì÷„³tæ}ô^ýsœ-ÓÖÌ 9îBÔsŸNýˆ£ q-oÍ˜Š¼MÁØÒmõYÍ;ÞWõëê6…¡GzW¥Sµ·fÚ4Ÿ;äGîÉÒ ÷•hóD¦ÁT“ÂHvQ4Ù,mÉkKÖÊUìÑöÎYXµ¾'Ä8vðbL,xVijÏ>+gB0.\ Ûn»m«X-]?¥Øå?ú e¾YŠ%:•~õ”Æì,z–±pRý":¡Ñ<ÊÊtKçZùœä]Öj4‚P—߬üÌ]]ÃÍý³!§—)áÀ⦣ÏË2Yü¬é5|Vi÷L·’_],pda0]vmxfOä7 ©GZ곚WRvÍE!Íô®ÿWÄ‚ŒtT«¼ˆ¨tó1 nÞ5ÕÒ\µYk^Ûê´f£¥=Úßyû{@,€c/óÌãx@ãŸþô§Ú,ˆŸÿüçr–Â6± %¦yËv@޳à˜x¦ CW»ó}v:¥SÊÛý‡Ñ9Ä/ÊçÚ+Ä‚L¯·a€¢r:†—ÔŃtBMyø}0 Á@Sy qâg«÷nþ\O{],¬ŽYðÇÚrðaK}VóJ¿#vÖ" EªXЋ²TxžÅ¦[4¶,²¬1Ía¥õ½›XX¦½Y,o¬ê2¢P5áë³&òV¹og›®ûµÙVž_“ÍZóÚV§6±ÐúÎ[ÞbOx?ˆb¹çóçÏËÙŸ|òIíóV± XŒó–m/ñ\ÞÓÓmù9ò&ÊqOÌ„óžù§eÉ‚Œ^YȲ› o:…®ÁÎVö‡{jœCO'/L(}r½¨Q,t„R‡Ö ËûËÐ8ÿ=œRœeD>o ²¾o‰Ô¢¼Ì£<ÔÞVŸÕ¼Šúi-â„Ò$"ß[¨(A9£0 (Ô«‹Ê!ËÖ{þw1è´Éfmym«Óš*öhyçmï ±Ž)¿ùÍo¤XàŽóù\®·À«8°ˆ`‡´Y,(gcÖÂâ‘r2•ÈA䎗vš¹QN|¯6ª~–‹Ÿ›Ëkš(S§"JZöÝËrÒÑä³!VœPÏü3é•ÑÿU‚éP¶¬9¸àO†µu êŸWÓVbátU,ðàÀ^oY—žQáßVŸÕ¼“…]™eR±åÆuTB{(ŸŸEËw#»¦ÖÀØl³–¼v¨S½ÜU{4¿óæ÷äá?# à¸2¥X¸ë®»d7tüòË/ËëùË_è·¿ýí!ä”R"œîê*¼¾B,WpŒiµc!MbñLÓªŽ™L/½¬Ui­,Õò­~n}6ËŠB‹úlî&h«Ïz^¢~±¸?=Ì9…M6Û”W¥"KëÔn£Íï±®2Μ9SFx6Ä=÷ÜC}ôQyý¿ÿý¯ìŠx÷Ýwa¬E"#2CLi@,žýPˆ…étJ?ü0½ýöÛµ{þþ÷¿Ë{âŽãäQ¸ð)L@,œx}ôQ¹Î¯äÈQ†?þñôüóϯÝ÷Úk¯Ñõ×_/=VÇ4€X×8M`±À] <3Âu]züñÇ7ÞûÆoHQÁQ8®Ô€XÇŒ'Ÿ|RŠ^€éôéÓôÁÈ ¥ˆ ±m[Š…›o¾™n½õV9zý¦›n‚a@,ÅsÏ=Wn$Åc˜Ÿþô§”¦ØÄð~,x1&Þ¦ú?ÿùÜ/‚2 @.ÄÄb–q7Ä¿ÿýozì±Çä@GbÐË/¿,ÅwAðÇ0 饗^’›H €^}õUUà1 ø \Ká›o¾¡ŸýìgG»øRšPª=#°·@,€#„—vf±ð‹_ü‚yäÙÁœ:uŠþùÏnqèjÄÎ`Bµ-ˆ©§fj-âDä‘ï-ò–^Ùê.ÊS Þ\M§˜ áQêˆÓ-éù÷tò„âÐ'׋¶”+[Ð7È‹„‹\5Nd´ì>¨Û²2fáÀvˆ ¸xñ¢ †aЙ3gèþûï—+8°€àý#6‹åÜÌZ>RN-,È3îxqàÈAî´dëx2\YŸ ¢É¨¿Žïë39¯9-å,W^/ïÃ_Í'YØ•™Ëò†öPÞ³¦à)§¬©µ$jéD›ÖYPeØ–NâOËñrpaõh(WQŸ½^oy­gÔf-Ôë¸O§´´ÇAí @.¼ÄûBð¢L¼Ä3‹ƒê&R¼W_ûßÿþw™9¥”$ÉÆÕ³tý|–‡©×iN«õ|2Jb^!2½ÌtJ&ë‘®¥µ©\•nˆ,¥8NP¶ƒÙ N8<ÛÅï8ùË_þ’Î;'·­®ÂË@óàGp”$¤s—¦4 ÀÍ—_~)ÅO“äï Á³ ª|þùçr-žf ŽŠŒÂ…Oa‚¨büÀ|õÕWrÌdäi“|ðA¹0SžbÉ›Mñ¾Ëï’±®Ò4•b§Lòz Ü-qË-·l¼—§Rò¬ Ž2à89@,œp¾ûî;)Ø)èºNûûû²[‚Ï @v)°P`ÁÀÓ'y|Â]wÝE.\€q@,‹Ž&ðl›Àë-¼óÎ;0 ˆ à¨nä™|ß§?þñôç?ÿ†±Uàñ Qà™Þzë-šL&0 ˆ à™<-’×WxñÅé³Ï>“㈠¹á†¤X8{ö¬Üyò¿ÿý¯Œ6d±ÜÁË=?ýôÓôÈ#ÈsYà}!v…÷ràÝ*£†= @4ޤ½®½}RšO,šº^2 àZ‚ab±ð‡?üArdxC©×_}‡§cšê+»Dv‡4ŽƒܧS¢<׿ŒýRµ³dg0¡Ú¶Nž!·Ÿ¾tiÑxØ­ÙËp¯%¥6¼ÚÓç5ûÕwæ,v½¾ˆ…“ï ÁbgAc^{í5zì±Ç¶¶"§þñï5(Í2JBtÞ¢z¯w!¥‰¶Gý±_Ä;È›Ùä]L/#I·ÜJz4 ëbao±P/Sì2­±É"îŒÜ =f߈U;^Ú³VWˆ«|ËíÂ~éKaÐb±GH鱨×!|? '…Ûn»MFxgI»Àð G^Ú¹l1Éh´æ`ûâ|×teKs¬õÉi+!Îk-*¿ÏièР«®uúÕkù³¶M#¾Þ5Å™”C+[©Ý¾N^Þ0ô­åù½ŽFn²O“¡Fc_•7œÓ¨ß)[·†í×ò±œ9YZ'/£IÒ‡çuQÏô©¬Š…¦´WËôÌCù÷Ä_qP©OÃNW”5)ŒKîøì%;Øp»·Õ½jã××ìØöŽÄµ`y­7ªw_ ]ñÙôÖrìšÔ¢r\¼@ŠEYº¤Yž*sä’®-£0ýüüÖïKƒ®È÷±pRàh‹…çž{N®¹À«:~ÿý÷rà#o4ÕDäèòGu=ŠžÕSŽ'.þ?°š1%Ç6¥óØØ”åN’ÃÔ]ݦ£]u­–?kNÈq♄¦†A3oA7•i ì@ÝÍN‹CàÂ8sâlŸNýht7.óÙëä…!Í'#%tœHæcÎe4eT­·ƒÎ[Ʀhd¹§²Ü‰[ -i¯•)š—âc`ͨ €'Ê©n¼áóîh㦺¯Úø‹Õ2ï·¼#!jdÚÂyúÁ‚ì\ÈõV" šiÓ|î#¹$K'ÜW"Ì ¦Ú2"U”yO#[¼ë…ëÐÌ wÿ¾l°Ãù~ N wß}·Œ(<ùä“R4ð¶ÕÌï~÷;zûí·Ÿsžüq_ *Ü«"â‡Vü@¦AyÕ3ù¹Yát9,P…4Ó»r,@œÿø›ÂôLwS\ƒÒ4 ƒCÞEÿxïš^þyé T>J×HJcv=K•‘ŸÓg¥Óá~wÙ:.ZÆ~J±3ÊDB™o–b¡=íÕ2qZ8¹~­ÐÔøŽtE,¤u±ÐfCÚÉÆíu¯Û¸^æ¶w¤",ÝZÚÒ–+bAF:ªU^DÔõ|LC§[‹RyZ+˜­ß—V;]ïbá¤ðë_ÿZΈà™¼äó'Ÿ|"Ï¿òÊ+r cê¶KN¼Y-±ž üêW…?ÖJ“xÖÊà7nùYyx_=kxU5RPÙ©·b‹õòsÅxæZÄgG"Íj>•tJ§("ü€g9Àq[Úõ2- ó¨õÝ z±ÐfCÚjãK©ûºÛÞÑzÚÉšXõòšGw­L³*Ý­ö^ìò}i³Ó¡? '…x@v9<øàƒòøÛßþ&Ïÿûßÿ–"‚»%6‘SÕRœ,êbG:ˆ¾åWþòWß·¸µ7¢°Ò*w6Ft‹ÿåÅH¶î»4“Æk?Ú-Î 6nºŒLT£õ|6‰…üZ4S¡í½âYÚšv›cQ¶ÿEÑ·ŸÔlX M6ÜÍÆ»Ö}ƒXhyGëi¯´ºkbkewƒ:¬¼þEadòkÿ¾´Ùéпˆ…“w7ðÞ–eÉ®Ž(p¤áý÷ßox2ËgC'çª_8tiة̣ }ƒ¼HüìF®êûå!ÝÔS}øšE‹8¡4‰È÷y sÝ‘©VhOˆ…˜Bw,[æ]Ý)ûî9 ½7œR,”ªôIÇsé´zº-|äMä³JèlvMbA°ç-áž ÛÒ®–)˜Y4žù§eÉ‚Œ^YÈÒ.}Ó¡(ÌmÄv-º!Úl¸íú%Õ}ƒ[ÞQ!û†Ma´ ñ°³qÌÂpêQêˆå λ«dë=ÿ»øÞyötò„âÐ'׋¶~_¶Úé°¿ˆ…“Âïÿ{¹b£išä8ŽèXÀ¯7Ót´a…0«ý°îõzËë=£6’ qÑ­äÓÏÃz>E?¾W:'³F”S*ËÙ–v½LgN¯ØJÔa–cn.¯i£‘tV嘅Vn·ñîu§ vl{GD®5(Ïw: Ûåbp}•_hU”¨˜L#î•Î]SkZ$þ´ï°W™aÑú}Ùb‡Cÿ~ N ¼Ì3oSÍë-ð&RUqðÍ7ßÐ7ÞHûûû­iÈÃP´.WÃÍ•Ðp–RܸÂcFIS’î2M¥“•Ïç)¥IËʈ)%Ir…VNlN»Z&þ;–+8Æ´zg*ì˜$Ù%ÚpW_ZÝ×íØüŽT®Ä™,sºVæMeÙÍG÷ýb\ÅØ¶-§Lò†R"æUx¿^ ú`$¤sÓÌ.ƒm6„a À†»¸‚£ _|ñ…\ͱÊ×_-§T6]ho† ŸÂ-µËi]·Û6†€XW˜sçÎÉŽ|°0FrçÉ*¼©‹‰W_}µqvˆpò /Èq Qˆã˜ àÏ?ÿ|í>^šW{dÑ€Žåĸæ9þ<ÝtÓMr/Ž üæ7¿¡üã0 ˆ à&yL¯©À"á©§ž¢ù|ÀXŠ7ÞxCvAð,Ïó¤P`Á@,É;ï¼C?ÿùÏå²Ï¼G¸+€Xß÷¥XÇôüóÏË=!¸[€X’Åb!Å™3gÊîžFÉ«7 @®ÚÈba2™Èƒ¹÷Þ{éÃ?„q@,µàpd¡pÿý÷ËsO<ñÄU2#"¥ó‹œ0=ayÄø¹xñ¢£ððÃËE—×uéÑGÝâ+WwìÐÀ°épVæß§S"ÍëÎǻ߷¡ ;]QŽ"Í »â³Ìc™·¿ZþH•ÅôÖí»¦(WO¤Q”+öè’fy* ñ¬.>éõóóÍeÏí9›‘ÞËm¤-¯û­¶ù…sõ;eôðýZº–3'Këäéš@c N,XX–Eº®ÓW_}%Ïóø…wß}w± ¼G03¤CÑåÁ M ƒfÞ‚o*ïØA鄬ܩiæ„wA_ÂvØIäÌ=гj«½-­õÈ‚YL3S9ÉIáÝ„ãç®®nSz¤³ãØù5O>ÛÏ) <šÍ<Hò:‚£öy™w²Zþ}UÍ´i>wÈŽÜ ’¥îsýûäeÂnS.gOuQäeÜÛÓÈõ]¸Íܰ½ìU{SrlS‰q÷_LÚl[ä×3È CšOF•èPBf!>Fc‘nõýĉ‚£¼/÷Ì].\çy7JÞ¾ºM,°CÜ-í¢EÞLVÆ,dBŒdçÖÑç¥s3ÅçžéV#KœëšÞºhM«.ú+ãŒù²K$q•³{EQH3]´Þ;†*o.|º£)…ÉAT”#Ý,ÖÊ_؆mÒQ­ò"rPˆé¤;*‚0šEµ2Z~½ùÞZv¶§ƒiPÞï™=qÿ€‚¬Ý¶*ÝNe,EJc=ެ¨÷ÔÕgå{3:Eä N¼-õ©S§d4á½÷Þ“ç>þøãöq ¹CìëcšNmrÕ± 1Mõ~9Ðÿí•NF9£6– wLå=UGÜ–ÖzdadûäM†j¼BEl$žµ2à°ÒÝ ð§£eèߘ©È±ÐÛ(VÊ¿ÖE³N0ÑÊ2¤eMeXí½h/»²§î.óòÇZe@e³mU~]ª )DVßÓj:±p¢àE˜xÜÂ#b•™rȲõžÿ]ˆš¢Œ=¼0¡8ôÉõ¢ö²c úy‘pñQ^ÎÑl«m)žKõt[F)"o"í«MÞ“ ˆÄÂÉÄ0 ºþúë¥0¨î8É]wß}wƒXPl“X`'¤UFàëÃ^mð£¹&Dk8ï:Páó}:]qhÍiUîÛPž`ªÒÙy{a×Ç5ÈtÅI3.†Ë±s³_ž×F£Ê ‹JÞ«å6­³ î í¡Š”DK;Jç®M¤óOüi9ÞaooÙ’o,{îÄ÷z½åµžQ›µÐh[B€u+éösá°þžŠ±&þà N"¼w9ðbL¼ÞBwE°8ØÒÏ)Å¢¬"%åßÍd©h§Ù¡¤Õ’‹x>ù¤kçÓD䟬§œ&ñÆó»—ÿeeI×ÒÚTöJ7D¦ìtéeKe~‡Svĸ&¹çž{äþo¿ý¶ü» /ûÌk0€ãJB:wy`J#b\IxÄwÜAûÛßèæ›o®]ûî»ïèöÛo§¿üå/0Ô±$£páS˜ *€XWßýîwdš¦ <2Ëꎇ—„æ<¦×e N¿ÿýïå¶Ôo½õ–\oá_ÿú×Ú=ÿüç?éôéÓR4àÀÁ@,œ Ξ=+—{æñ ÷Ýw½ÿþû0 ˆ°ä™gž¡x€þüç?˵^ýuÄXÂû@üö·¿¥§Ÿ~šÇ‘‹3  äÅ_”bÇ.¼óÎ;ôÐCÁ( À’×^{MŠîŠøì³Ïä@Fb”ð, ¼M5¯«ÀK?óêÄø¾/fâi“ ¯æÈk+ @ÂFñÔÉŸüä'òóo~óúûßÿÃ€Ë ¥ùÄ¢©}Q²ˆlS§Á`@#Ó¡ô ×û¼¨·¦ø ˆpm†¡Ü]’ÅÂþózöÙgå¬Ö}aËn£5ÔW{úüPò¬ïâÙ¡¡9£dÇÇ}«'wÜ4Æ醽óscŸN‰2^w>ÞPîbçÏãð"+åbì¯ÎxÛm·Ñ/~ñ ÙýÀc&“ Z{`ƒ)]¹¥õv±’ÕÝ£N¾ÅöåæÉÛv§…O]“Ž×ôvñºM5.ǵµ¶pÂå¶éE¹]Q…8B:šoaJa‡þØ/íâÍlò.âÿ€X;ÂÛóR]øä“OèÂ… rc)´öÐÚ»± ºÊ¦½ÁPF º¥XHÉ1´ÒæÝ¾N^¼ŒBŒµ>™³é½üºfÐ"]ɳ™K•2¤á2ïNù¬oõUžŽx¦Kc?i¼·,‡mÓˆ¯wMqfÓ¹¶ºÔÅBWŠšu‡»¦(OÆåƒ±È§KšååZÚ%]|.òèçç·–½Á†¾µ,ï^G#7Ù§ÉPöØWù…sõ;åÿÃökéZΜ,­“§kR NÜõÀ]¼õ»ï¾+7‹âÏß~û-Z{híí&²…a‘øÁ‚ìÜ™öJ±ÐÔ0hæ-(ð¦2”׬ÜÁiƔ۔×÷6e•ïšÌ3‹ifª´'…ÇJ}™wW·) =Ò»êY™r0“¢¥3°È™»DÍ÷ÖÊaNÈq"ÿÍçšë²þ]ÓL›æs‡áȽ Y:á>§Û'OT2˜rzJ´æõÙÛÓÈy,\‡fnØZÏm6LXÈq·ÎÜ£8«–3ϯg†4ŸŒd:#'’éš…øEº†ü[Ç–èbádÂ=þøãåRÏ¿þõ¯¥#Ýê4ÐÚ;Y­½±xÆJ„&%³[,,…bšdpE9žA8$áÈÓ ¼Ë39ò4  SyöW¢AÆ|9p2q•{EQH3]¼£ŽAq^K–ÃÛáÞD–¹gV˼é\[]ÖÅ‚ü^tÔ{*¾Kµè\G}§F³¨VF˯¿Ð­eo³aaÓ[+§J·S{wcþ¾ö,ùM¾G}VڃǢt£{ @,€«o¼QîÁûC0¼äsë G´öNfk¯Q,˜R,¸IÝÉ.JLS½_vY­FØéˇÉkKñ‘¿³‘KÞd¨"X•üÏZéVb›Zy×V½ÛîårµèئsmuY¦FK´-˜heÒš-{´ªgw){£ ×ÞGE,¬½;ñ, )DVëŸ4ˆ@±N<¸‘…ÂO}wªºf ›ÂhAãaý(›ö„ƒ)tDz˪«;jLB)éäEÂ=E. ØŽ£ÙæhFä¨6Vï'ŸÎ¹§Y´ˆJ“ˆ|o‘¿»Ûl¹w±Ð^—Mãcê¶ŠU¡•C–ï3ÿ»@E{:yaBqè“ëEÛëÙfÃ\¸î §ËÿÓ•rÆsiÏž®GÞDÖI›,6Ô_Ù³± N&¼(Ó«¯¾J÷ÜsOyŽÇ-üãÿØÒÂDkïDµö6Î&Q] ®5(?w: eô'š‡¤UÆgèÃ^¥ëD•¯×[¦Ù3–c06¬íL•@Ù¹%v=Ò%í¤lÃ]AUÛ´Ýknø®­k­Ë>.¿k ¶×B{¨¾¯Ñ²ŽÒ¹kéüZFÀö*³JZËÞfCþîå¢^‰ÕJ9ùÿ=ÝJº}Ýn°IÕóð£ N"Qp]—n¹å–òÜùóçå ÇV±€ÖZ{²TØ&nŠÚ¤òZ–‹Ÿ¤ü»"ª²´åù­¹‹4…ÐJÓC¾÷Rêr¨Ö”ÓšÓ4Û¡ì»ÙßO’fuâüš¯±pâyì±Çè/ù ]wÝurê$óïÿ›nºé&úïÿ»±…‰ÖZ{‡CB: 8Lǃ Ä8ÞØ¶-# ·Þz« ¼åo¼qy­#´öÐÚÛbÓpáS˜ E ˆp¬9wîœ<î½÷^úè£Êó<+â®»î–ÕhíÄÂIg>ŸÓÓO?-÷„à½! X$ðàG¾®ÖÞW_}Eo¾ù¦\WãÌ™3r ëwÞ)§Ïr·Ó 7Ü@×_=F#Ù-Å váÀÑtˆp‚`ðÈ#ÐsÏ=GÏ?ÿ|íÚ—_~)xD®ø]ñx^¶›7ûàƒ¤@à)±, yªì_ÿúWúðÃ)Š"Ùýôõ×_ËûyÊ,]á4ðÎ @ÂÝ <>—{žN§k×ÿõ¯É)Ñ’º:îRâ¨GxuNŽüêW¿¢§žzJFb\2ü±\c÷ƒxà`  ÎçŸN·ß~» Ws+€X5¾ùæ®æ~j]7.ó @,œLx[± G.^¼£€XuxÚÜþþ¾\úÙ÷}ĨsÇwȈÂÿøG9M€X5xqž‹ïy=üðÃ0ˆP‡/Òsá¹¢ß.¤q$ôÙ¾wAJó‰EN˜^åVJéü5Q€XàÉ'Ÿ¤W^yE®úÇ3"¾ûî»–»#»µ ·mká„ Þ‘òHöIP»\î ¦kKùV?ß%rŸN‰ò]w~[ùv½ï°ž«ê”M;fòn•ÇáÛsõ@,€ãS˜Ífòï»ï¾[.ÜDìÒY½Hpgäi»XÛ*g ìt¬NÍ—…4uÐ& â}¼™MÞÅmá´ºeöæÄDÛ£þ¸(ºkúmIºr‹ìáÔ¥0äZ‹EHGã¸õ@,€ãÏk¯½FgÏž-£ ¼¹Tál(ÅÂÄ_wYä’®-£}Ë“bÁd±0›“5P׺šI…¾HC‡]u§oÐ"]ŠŒ±Ö'ÓqÈèwäõÞȦXä1ìäéëSŠsæZ™o·¯“WøôD9Z% ò<}KÜ×ÉÄ>M†ý}U‡pN£øàƒòoÞ•°uc<§~î,ÖŒâ¥ÎCåÙžhùºÍÜÊ®v£19¶ŠLèÜ-‘?ÓÕm Ctv^»t.fþ\ߘÒlª—Nj`Ù4“N«C³XÝ;5 š‰|o*ëÀÊ–¯=dǦS”Ÿqøsœ·Ì+" ¨CÏ / i>ÉüFN´"šóKá„YÌìÌ=г]Ó_ÖwÝN¹à1m!är„#÷‚dé„ûü\Ÿ¼Œ(˜²]zª‹¢él±{ñ¾4awÇ6eýøzv¥ê€XÇŸO>ùDîÁ|ñÅtóÍ7·? Ó/úÎ5šG™hÀ«k-â œD—Ó¬üÌÝ]Ã-Ÿ{EQH3]´€;F.@Ôs=ËÍňj]ŠAêÉÏõnŒÒ4 C<×Ñ—Ñ‘Ä3U> áî2_ŠåÀêbA•§S Ò˜\ÏRc~´K~)Y\_Ó»Äô›íTˆè¨Vy9(l!tGEF³(ªl~'[í.òLƒò~Ïì‰ûdW¨~ˆpüá-Šo½õÖò3ÿÍ»Mn#p8.œA×¢O¥CîÑz¤\9ÃKêâÅ‚g­ Úã+;– Ïå³ú¹+W²‹‹iª÷ó4ò.‹šRc:â\äêª^–³âìdºT^á³£”Ž´*Úò[ÖïÒÒo¶SYW¯yÜG0ÑJû¥5‘´þNv±{uŒ‰?Ö**¯@ý àøÃK=ó’ϼô3Ãã^~ùåžõ-Õê|ýUÕZÙF±°l‘WÄBÞu6F¢Wž«‰ƒúçÈI'5“à78!g?ˆ{úÎ*WV[ÆÂÙ¥ËÈæ+gMä÷µç×âL[Óo¶Ó²® b¡ìnP‡•;ä"‚°úNv±»QQê(¼Rõ@,€«îzHådÞ}÷]ºï¾û6·`gg>ÅiFY² £§" Iꩱ =¼0¡8ôÉõ¢F±Ð‘N0F³h'”&ùÞ"oï.T«º'œwL¡;–ÑŽ®îÔ§KF¶Š‚Tœéª³ãñœfO·e+;ò&ò58ry_{~*Œ¿7œR,7åÚ5ý6;³!< À‚@±4”š Zïùß{}Õºoz'[ì.Çô ò"áâ#—|ïhÙ}pèõ@,€«Ó4éÓO?UíAán¸á¹_Äz$¡__w´¼…-~þýiÙ·.²IGφXq½¼Ï;YØå€IyÈV(­?'\¯ÚºÎ¨ÉŽ_8)­R}ØÛ0x.Ø)ZÈK±pº2!ο[)O?w|µû¶äçO†•µvM¿ÅN×YP÷†öPE9Š!â^éܵ‰tþ›ßÉ»ó€Ç^oy­gÔf-zý àê€gCT7‘⮈_|qã½¼¾B,WpŒi}ýÆLF(ÒôR¶ºÏÄ1%éåÌ£KE™’¼<œ^BÙe¤Åuh_²=?¶Qó󻤘4½“Mv¯tCdªŽMßãS?ÄøAxê©§jë+|öÙgtË-·ÈUÁI"!»<0¥±Vy饗è™gž©{衇è€qN… ŸÂQÄXáwÞ‘â Jš¦ôãÿ˜ž{î¹r¦±pBá…™x_ˆUx †;î¸CŠ8®ä€XÇœ¯¿þšn¼ñFÄhæg?û™ìz ÀFx­…0 a `3“É„Þ~ûmÄØÌŸþô'y `#UX> @,€’ .Ð]wÝC€X›á¥¯¿þú–xNåÞÖÿß™”ÎO,rÂtë}óÖûvM À‚# Åî“›‰h<ìÖv?,w‚<öé”HóºóÜ› Ü²¾ã$ïp¨»?ô~ÕºìZ¯„ qߨqo†ÓÙ¸S%ïy¾e—ùŽ àhyôÑGÉuÝÆë±kHÇ3ö"¹óà‘f+7#of“wñ€i¦®Ü"yU,£ Õºù£]ÊP”5iv´»¤“oá=œº- q„t4ñˆ”&ÚõÇþá¼cÄ8ZΟ?/w l"œ ¥X˜øë?ôièР«Z±¾A‹téÇZŸLÛ¦_ïÞL§ú]ÙAE…8Ôïôɉöi2Ôhìï+·¹¤kËHFßòÚóÚ*TY,gN–Ö‘Ïw5“”ÞIÉ1´2¯n_'/Vѳ±¼MÏ(Ǿ¬KÕÉ·=“)Ê:²g¤÷òëZÕ–u±°Í¦—n|&uözBð™ÆÂ&]ÒrÛ^²Í‹÷;Û\fßZÖu¯£‘›¬¼ãpN£~§Œ~¶_Kwó»@,€#ãã?¦_þò—Í7Äsêç?ükF¥K}öîê6…¡G:;•]þè[¹ÑÌ 9î‚ÎÄÇ(Ÿ÷­ž¸® ·\q†yš{{Ùžh»Íܰ=¯Ä‚Y8´Ñ˜[EJô¹º65 š‰¼o*ÓäÁi,oó3uÇ^ý»í™Š­Œ©(Ÿ)¯sý²Õ4·Ø¡'ímÓ|î#¹$K'Üç<úä‰Dƒ);óžê¢8ˆÍ·”9 „ÈößÙ{gÞqÏ / i>ÉtFN´å] À‘Áƒò“ŸÐ·ß~Û"„³èýàÍ£Œ’²{" ( i¦w+ÎUè™Ëît1VŠ€ÝIHCv4“EÍiZ+QŒÖ¼Ä‚Y ]vz³šèÕ®—ŒÒ4 CÜ×Ñç[ÊÛüL³Xh{F•u0]F1<“…É€dÖìÓd‡^.ê:Õ*/"ªBù˜†ŽŠ ŒfQͶ—dó­eNÉb››Þš]TºÊXŠ”Æ,z–Hu—w€XGÂý÷ßOÿûß·Þ8Îæn‹>õ¬•ÁtÜ’äüå¼áUûá#Ò¹ÅhúÂ[•ÁwG♲ŻIOÚòÚ(âZd¡^–Ü!IÓTïçi*Û+SSyÛži mϬYðÇZƒ}v°ƒ×<¢1˜hå3iiÛØ|k™«6ÞôŽ»T¢á³ÐB¤í] À‘ò /Ð3Ï<³Ó½*? ×_U-Dgc„xóCßêËÈİ¿9Ì^´fUk~µ•ÛWÞ¢î™~¥¯fHTŲ,K9#é¸f²S<£ñŠcÚTÞög6‹…ög ™®ØxDaC«¼Éݶ™*ewƒ:¬Ü!Èæ[ËÜ"dºB,¤Ëh †Üëš2²Ðô® àˆáÅ™n»í¶Í­Ñ™Eã™OqšQ–,Èè©ÈB’zj,ƒfÑ"N(M"ò½EÞbm˜ÍTdBÄKÖl‘fO'/L(}r½hy~c^©êï iÊNxò¦ªÜ޲F±ÐHµ´{‰ÇºcY¶®îPÖRÞög6‹…ögò~ú¾A^$ÜeäÒ€óÍší³ÉålÂ0  PGœä”Y¶Þó¿÷úªu ›o+³ê¦ØN)βzâ¹5=Ý–QŠÈ›H{¨.žæw€XÇÃ0è³Ï>ÛIè×CÑ-o!‹Ÿò…]~”‡l.Åút¿| ]§h*gxºÒ·ŸøÓ²ï]tËEs^<š®ÔU®'~Íq­: ÷§ Ç¥Uê¥{+ê6”·õ™j]*·>£Ê³×ë-Ëß3*3VìÓd‡ë,¨çB{¨"Qeð”s×&Òù_ºÍ·•Y|o&ÃÊZõ:DB0u+éösáÐú® àè9wîÙ¶½ñ¯¯ËcZ_¿1£$Ž)Iwí…$­ÙµÕ"ÛòÊ(ŽB¹åv|IEIEÝ’¼^œ~BÙüL–åI;'»ÙçHm^é†ÈÒÆ2ó÷¦yÅÏTæ‡A€XW_~ù%ÝxãÂY`R;ØF"1¥ˆpòxòÉ'éÔ©S0ØBFá§0ATˆpò\@–Ñüc93âûᅦA@,€u¸ùÎ;Žãvކÿ(“à HIEND®B`‚libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/resources/images/logo.png0000644000000000000000000005643211021722676023413 0ustar ‰PNG  IHDR°¬xW pHYsaa¨?§itIMEÖ -¦ LÜ IDATxÚìw\IÇ'=ôÞ;x( RA, àyvÅ^Oñìålçkïåìz'zž]φzö.Ò«"½*½·@BÊîûGN.Èf ˜ïÇ?pwvvf2Ùüö™gž‡€¢(€@ à† ‡@ H7£ªªŠÉd2™L333 …õ@ ˆ0‚|úôéÇïß¿ûð!´¸¸”\[[kæÌY?þø£oG€ëw@ä‹úþý»ˆˆˆººz ue7ón¶6†ŠŠ4üö}ú¥ëÑEŵ7nÜ7nÔO@z555aaa¡¡¡¡¡ïbbâ8ޱ‘–»«Ù 7«n–}¬õ ‚Ð%‚¬ÝtçÏ+—/_ž6mÔO@º?¡¡¡>|xÿþíçÏ)€>½ ºštµèfeb¬§’µ›nß}œŸ_ ¨¨õ@ ©©©¡ÿðîë×2™äÐßt›…»«Å@WK ¥¶ÖYSÛØ×iûÞ½–/_õ@ î‡Ã‰‹‹ã;€‡…}¨ªªQR¢»8™r³pwµt`¦ @mç-Öl¼Qšžž õ@ y…Á`DDD„††¾ÿ6**šÅjÒÖVèb>ÐÍr»•]?#‰(ÅÛ={™|à/Ì%&~BÄÂ\wìèÁ[6èmm¦LK £,;n΀°°°ñãÇCý@ D¦ÉÊÊjvfÊÊÊ!¶}øÞãįËmû;+«ZIÊiª+Ë(»ƒš¡®®hÓÇê'@ ²Çûøñ#_1}øð¾´´œJ%;9šÏ›íéë³­Í%³4Š"ÜÊ&V—]Èk*è8ñ@QÄÍÙ$4ô]û«‚ú @ ˆ`2™QQQ|ðˆˆ£AMUÑÕÙ|ÓڱÆëõ=UÁ¤UÍ„¢¬ŽnŠ¢  î.æWnÜf2™ P?A 骪ªøÑ,ß¿—Àår ô5Ü]͘ãíímbÖBëTÍÄáð?åÕôtUºY¢( PÄÝÕ”ËåFEEy{{Cý@ ¤ó¨¯¯?sæÌÅ‹RRÒßõ2èj¶|ñ2OO/=ƒ>dªqgj&FCSlü—ššF™LtèoââdÎ?Õlv(ŠÄÔX]_O=,, ê'@ Ç‘#GvìØŽð8S';ïÞ:vÇ`uM«Ö4S¯©°ƒ4SE%#.á “É()QÍ„"j ™Ðo ÄÝÅøÃ‡Ðv6ê'@ mO«W¯Þ¸ÖoÍš%:Cˆ$•NÓLy_+“>òx@[[ÙËã;Q5ÿkvúx(êæb¼÷p‚ D¢äÁ¥ ~‚@ ‚‹¬^½úð¾éËVì Ð-^cSCbÇi&ARÒJ²rÊøÿ57Õ i‹QÃìP¨›“q]]}rr²ÄmƒñÇ!àÂËËS]¹îÖ­?iJŽìÆTVÝ;m’î-Øln|â×’²:‘HèÛÛ —•nËb,'.ñKy9ÃÁÞÄÜTë›xBD‰§,R( Âãñ,l=tøhPPÄí„ö'@ âÉÍÍ ýpëÊB ½[ͬ}.­šëêYqñ_j뙕ìhoâîj)ªpuuÃÁ£Ï/]‹d44Èdâ¹Ó³ÆŒ²o©œê¬¸„¯ö¶úêêôæµ<P"u` õ"!‘_/³yØe Tû~§å Ç ôpÂÂÂh4ŠÏˆ!D’ ‹ÓÎÚJËê>泚8UeºÓ35U‘™²²Ë>& p0µ0×>pôù™àwLgMs×ÕQY½áÖ¾COÆŒ²ã‹§²òÚøù,TE‰êäh¤ªJmVNÍ*W'ý›!ïÛÓ~¨Ÿ =·®¤> p/yS#§ PXû™‡rzjêKàð—ŠÒ€¨¬¯çð¸ÊTmME"<Õþ¤‘ª…¤Gô@h4‡P¨ê„S)A 9¹åÉ©Å<èëªõêM£µ®CIN-ÌÌÊ.¯`‚xíÛ1~ýª‘3§º“IÄ«7£î=Llld—”Ö]½¥¤DAª§­4ÄÂN'¿}Ÿyývb»Éo„µx(êæbxàXxaa¡‘‘ÔOHë (—ÃcÝü´²–Uô¹ô ‘@Ð(/[ðó`_#S‘XI*aõ¹¦$@d—7²›‘™éõÌÆ½oÝ ÇûôZc¥5Ž*éi(((p¹<³XQ¨zVºØKx<äsJQÞ×JE ‚¥¹ö(?[±»ÞV®ûëÞƒ„Ú:&€J% p0èæán5lH€ººâ•›QÿÛqEšª‚¢"µ®ž¥ªJùÞßöo'AQäæÝÄ[÷>mXí ÒÒ/ÊÉAH$„……Mž<ê'¤¥râ½ÏýíqúîZV1_$¹ZY{ÙØ¶^ðØ–*¢Aúö½°Ò3àÿagbŽ è›ä©…'•33Õš6Ùõòùy€ŠJÆ«7©§~“œZô%¿ AP"‘ð÷í¥uõLÀ‚9ƒ˜¬ÛBÎþxñ&ãsJñ˜Q6Ê×ILÇsÊ÷|ú|Ä…ruÒ }+ñh@ýénp‘¦¨ü+òÎåVGQH¤Iîžê@ò()D.ˆˆ×Á"42 uD‡ïù$ K]}sÝÔÂ|.†C @z$ÉÝÝ=2&—Ë.¦Ð­H=§¨Õ’šÿO7ïÄ^º‘šQB¥JËêš2qì.ár‘êêÆs§fNçÔØÈ¶uÝ~ë^ÜàA½ž½L>~úu~A5ÿrsS­)œÝ]-‡ þÎÌTS[KAI‘ºjýþYŸ¡Ö¾Ã­MŒÔ 4#þUH,&gˆ‡<áXß TnNzç/½b0ÊÊÊP?Az:o²O<Ï:\ÕøEGEÍÛÆÎɲÎ KÈ_”55D Ž!ˆbð`Ïà³'xìb™j J? ²jý_.‡«©*¸:›—•×—”Ö½x•2sªûµ <}2š&Œ’VœšVlf¢•SXXãáfõôy²¿¯í 7+wW }=5ðol'ÞwVÚ¡ÏW§^¹5ÀÑtüÇ’²º_¶…¨©)ôícpçÚ¿‘™Zæ67ÓX¾Øã›Bc~ü\üåk5(Eµ_+"RN º:t3Sõ°°0¨Ÿ =—´òW/³Ž$•<2×Ñåè¢@¥â¼h5©¬ŽX©Ï5Ã^¹ãSŨ/ª®t5^¬¡` ‡ô4ÜÝ݉DbDTFïþå$ŠøwÎ'Ï?öí§ @­«gÅÄæº 0<~þÙÑÞdF ÛÛÐ ]]•~6†€Ê*ÀwôÑs§gùùôû&žþ›}E@KñõPccS\BAE%@&Û~ºŽvÖ-½þ+žþ±Q¹8j}ø a(¨Ÿ rOFÅ»á£(dÔÅò;O[~xœT’ŠÄ}®¹ª„§|#»‰ÁâZk{Ãa‡@ =;»~‘193ç“©úD’«Å(ßÐØxò"YSCIU…îêd®¥¥ü>,37¯ÂÌD+*:°lÍ93múÙÿþß ôÕ¼=­ûÛÖÌNÍꧪŠŸßÐЄ HE%c̨>ƒ·Zò›ªE"€qsÒÞ~ ’Çã‘H$¨Ÿ =‹”²gÁÑd*o “Ù ‘™ «I¥*ˆ¥4AZE*i ÖérM„ÄS‰PC*ç‚ÿø‰¿ËøJ&RûëGôÄ÷ÕŒ Çnø áÕ‹*™–Q’ø)_E™ÈÈ,=¸{™LÊ/¨¾xüÅþ#ÏlzÌt[µþ/€ªª‚¥…6 îÃ/ÿ>¢Q!å„|ͯúø¹€Í檡¡0ÈÍäñ³´õ[ŸÖÕ5¹¹êé*ˆO­˜šKº:é0Ÿ>}rtt„ú ÒƒH+õGì,6R?ÖÅ•¢ÓØÈ«WDUZ-É< ¡Y<ÕÊëˆUz\SET P[E,ûG?xtTQѬ$·¬´²–1Ä|yÒÓˆ‰‰Ù·oï½{!¦&Z“Æ @xµ¬º7åûXë÷±ÖGQ46þË…Ëá×oÅШd~HL‡þÆçOÏ"‘ˆ±~¡RHZZÿÙþÖlB^JZqZf Š  ¦&ê~íÉb³¢Ñˆ.Œ^½Í‰ŒÊ·ï§ÃCxÅÅu F†Jÿ,ö‰0;5Ë,k+%uu…°°0 ôEQ8- rùTñîDx‘Èëân¬©]DÎQ±ŽKà”’¾jðt›ÕU%©¸žX­Ç5%j¡–Id0 D@RE4ªˆö BQ4$6²ªŽ¼dà58þ¤çpñâÅ9sæØÛ™._ìmok]–_I"“zÙ™¸¸Z©«+b\Ëáð®ÞŒzû>ƒËãYšëøûÚº»ZD8Z45±ã?~)(¨%µnk~H§Võ—˳°=:lˆùøzoÙý¾°¨`k£}xÏÇþ:ÿÆ2`q“Ê-Í•u´h¨@%Eg…ièºyó/¨Ÿ =u1~nJyH€£³™¶.C?Õ«ªH%朾àÛ²]±JÑ4kÉ(EÑPD• .ð ñ.5)&;ÓËbÑt‡ßàøC žÃÇÇ·dá ùž¿ïÿ[¹´ÊXD#•Ln ºYÏ[âC"%«ŸïW^UÓB£’ú™©c-á ÐÚÚFP5U꘩ÅıÙ}.àñP€žžêpï>üˆP¢6Ùá!<"$}.úýèð¨¯_òkøUYYhL›ÔoÒØ>ELMT½¬Ô_¼ÍÕ×Qêiàcò(«¦¶ISƒŠéTŽ€:تP©¤°°0¨Ÿ ÝŸ3‘c«˜9þÖNdq;Nùᔲ äÐ/HV-ê ¢2ÌŠÂU&‚6lUýœŸ‡"ô.—ìôGÁÁ‡@ =‡¢¢¢§OŸ?=óÏcÏšÅS#‡—JÖW52GyÜÆ‚l[R-™H”W…ÜŒ;ÅM°†ÄOù™Ye(Š„^V:c¾wh^æCQô[r:aûPNnÅÑÓ¡á‘yãF÷Ý´Ö;øÏè¿î%ÙõÕó÷uvw6t`PRZŸ™]™œVž_XcaªB$TU¨F[ñwØÕ×71Øë”‡aÍâ;QQ©{[Ͱ°°iÓ¦Aýéΰ¸õ vå k›Þ†â#X2˜•Ú—´l@?uR€Jj Ô5êD]BGUP %”—“—ÓW××Éh|Ò£¸té’šª¢]?£ìï"PÏæeºúýN”••m˜7ÕÉ'šTRZX:ø¯~RWS˜4Þ©•—Ûÿš”wífÜ£gÉVZ;7û>z–róN"@ˆŒùŠ¢¼cvo𸩤°¨69½üá“ô’²†Ï)åµuM?Îé8ÁºŸÖßOsŽžÑæi”÷µîØokjÙó¦[£ßŒL-Å“`XN¥Ð÷oÚ:8Ðÿ "gºßL"~ˆøò9µ,9¥¼‰Í¨¨P]è»»LŸÔ§¼¢aáŠWé™ÕÍ·PQ¦lY7`æ+ ³“ z{ö¦tÞ²ÕÕÕjjjøÚŸ òD}SÙ‹¬C:z¦Ú:" ±xhN-r/4r‚MzÃ\u-]mGៗ@$b¦jQC´P€¾Oûœ“k¬f¿zð+èö@z $‰B!UVi[tÓ4ëEýo‚,SS²Ž1`d4¹œOIùNÌ1ÄSUUý’Õ7ž¾HáÑÒT½`ÁAE$þcp•"U”râÛ~f.¸•;w†Ûˆ¡ÖÅ¥µGO½›ùãµ-ëG¨É€’"e´osSÕ?¯&DÅå;:è|Ž\ œïÛ2ÜÁƒöos#“BNTYµÉiÕ\PÄPŸ>ÜK—N#€Àò¸ÒP#~g¥õ¤Ûò±ø>À³O¿–§X µzaDäm@þY’&Ž0!xIp—˜ìÌдdSu§Åî!êtC8ì¤gB§Ó™#+½Ê„Le* `ªJe±XK–, æ—©ªªb–:ÔP¨½­õ[Oÿhš°ˆìð¨ÜeA^£úæTk¨Ó—.ôØ´ýIN^Å’…®]~;›?Ú¿Ë»y' pöBJœ;ÃVÔ2‘ˆ ‡ËKJ®ÌÉ«%`i¡4z¤!‰„ y;µËÀΆÛ¦Áú "O|.}Òú›MJ•â›bBA#ÿ¿l#q¾ ¦ÜÖúËëjS óãr2MÔV~©@Q‡c@z,}úô9}êé®­?\¾l¨`ÓTXž—É`0òòòÌÍÍÖ/œåB©€ k©ÿ»8ÐlvjhhŠÏ»q' ¯«¬§£äì`È×Cû¼)(ªÑÓU´é­sùz"‚ðÞ}ø’žYI$*«™,¶àN=A=ÔØÈ‰K,-«`%‘€]_õ £M[È,1â  ¨²±ª´ê'HO¢ž&T Ͼ¾™x¦´êYJˆJ) TòPPª¢ ¢DQ¡29ÎmÚ½q­ž¦Zí׬ì" ™(d!ƒ¦ø¯xB@srË>}.TT ; 0QùÝ[ñªªTc#UðŠÞô¹º†io«ÏWH{· [´üï³â ”÷nò½¿•¶DßÂ5! •U± eŒ†&€â{­Áî:Í)ôÛò³Só):Ànj‚ú ÒS@_ ±e æßIOiJrÒ1T¢²y¬F£ùxékEF)ʨ@§#êÙÇø´¢@ÛGÃñpl!H¥¡¡aãÆÕÕÕ;vìÐÐÐ8}öÁÛg«­¼l‡°,—WW9¨. ðãÀ‰.‚²¬ † ï÷M9¡Í2ÅÒ\ÓÂ\ƒ¯~ü|¬ ÕVmx”\ÔßV?>±ðò}•³ùnIƒÝbCçU”3 ”‰´9mK~aíÇÏål6EQM Ú ]ee†ÂOBÙ` ú1™ijiÒ¦Q‚ñ òÄéȱ‹ï/ö P,b£‘¥hRhž¿tqR/B_ÍÖ•@P€rìZb€Il  MD_ QÍ*)~š×Äå8O™áð»EjÒ3ÉÈÈX¸páÆGŽ ÈÌÌ´±± œè¼`æÀ{¿¿Ò®®»’\¶ÈÑ@ƒþ¯ý¥œÃ«0Ð]µeßy[¸¤e”.]’ð©ˆ­× ³#ûGš« ”D@Q„—šQ™‘U‰"( P#åþý4)=„ßì ÈýÊòü>ñÑ£GP?Aº'WÅf›kâJ{\¹ÿž ‘ˆc- Ú8ëake̤̊ÆâÊ2AuŽÓŸVZƒ)p!H¥¾¾~̘1W®\14üwëÌßÿ=qâ„‘Ãm6¬9uæÙ‘ÖÚÆÄ€Nbq‘B.à¨*98úv2; é!!•“÷µª °ÖÌDÍØH¹¹0‡ÍIL*-,ªCQ”HÖV꽿S#Z 2Ñ©…Ûhvp¹èü•™©Y”¯_ I¤6¤¦€ú "O0J#õ3¨ÞKœÙ[”å©Uªõq¹Y¿ä<Íl¾À\Ã/éÉ (¸téROOO¡Sïß¿÷÷÷(oõò æ ..®‰ ËRÕP8ØZOWõÛåx…‹@I„ÑЛPX]áRˆöý´ •±ôP”–Ìâ·™ÃAÖíÈ{ô¢îõë·nnnm.¨Ÿ rCÅË£U¯N æf°ƒ6qœ ñÔÐÐÄúRQ–[VšQ\H$ÐN˜`{@…¦K$àðB ÎþýûétúŠ+Zžº{÷îÁƒuuuž>}F"Þ}Hd"‹Åe±8EÕá¯ÖQ(Düö¡ò FüÇ"“ª¤Lq²×UW£‰ÐC"S ‹OXÊ TTrnÞ/ûãZEu ÷Áƒ‡üÅÊ6ýÇ!r»,«øÖZV~"Êe OÓaR\iZM *BQ¡+ˆº¼¦¡¡‰Ëyü±‰Ã©¨¯S¦j;LñÝ hs‚@ ÏŸ?õê•Ðñ²²²C‡•––¾}û–F£UWW_»víéÓ§2EKW‘@ ¼ ½’øé«‹“ ¶pÉûZõ9¹„‡  Úšô!&4Q@ñ$ÕCÂÉX0dÖ—ft\}tB}t+;·NEEiñâe+W®400`Ä ý "ëT¼8Rw›]‘+t\¹¯Ïa­;H@SYÅ\GWT )ù, §lím¹Ô\ÃÙRs XiæÂ… €¹sç6INN>räHYYÙâÅ‹ýýýE]¨««½<È}é"/lûPzFY/+M"•¢+³„—šÎˆŠ¯N¨Žo,+o¤Ó©îînžžÞžžžƒ RRR’xÄ ~‚È. ï þ˜…ò8࿳”¢n¤bÿ½î¨Í\À«o*{ú?@#§&±(ä?‹¦Ó_ÿo³yæn@ )p`!DˆE‹­_¿ÞÒÒÐÔÔ´`Á:¾råÊ~ýúa_8vì+ûʹ-$NëÉzñë¡%±r7f5q?ÕF%ÔFÇ3bë ¶††êàÁ^žž^žžžNNNŠt~àúDá5T•Üþ¹1'JhÁ@VÑ1šL7qICÁxö€ 6YXûQ°$¬l¨j @Ä’ŸŸoff`2™óçÏÿá‡ð\8x°çþýoàaé!,å$™USÃŽI¨ŽŽ¯ŽŽg|L®ápcO/߃Ó====ûöíK H?* ÔO™£6îvMäfntËSDºŠñ¼Ktû–§Ù)1‹ IDAT¨$ Mw8z"‚H¤ÆÆÆ)S¦¬\¹røðá8/ôð𨨨ÏÎ)·´ÐÀcj»ÌjÝìTXÔ_WÀH˨ôµ±ö°êgÏÁƒ›ššvôˆAý‘!Øe™µqw*_ •eeŠº¡ÑÜ?éFФ@ R†o¡™={öªU«† †ÿB'''“gi¡&Z …¯”Df¡(’žY_W__PTO&“œœGzÀÓÓÃÃCSS³3G ê'ˆ¬À©.ȞΩ.h}¦ªèÎ †â ´Ÿ1cÆ”––òÿÞ·oŸ··7“†††ôôtÖ&ñ R©ÎÎNÑ1_¦O²k·ÙIXfqØÜOÉÕQqQqÕÑñÕ5µ,%%…. òöôôtssSPPè2ÅÙ%þã‚4ÿ$tÖÇÇg„ ÍÿJæ é6 rèС¬¬,ÀBWeͪ8vYf«%‰4%Ó [|Ÿ'Hw}ñíºäq×i½kõÖT*•F£Ñh4:®¥¥¥¥¥¥­­­««knnnaaaaaaii©ªªÚ£æ[LLŒ«ë¿±K=zÔÓ¾ wWQQQWWçÏ===KKK++«Þ½{ÛÛÛ‹+7n¼~-8îÝ€0³¦à2;1ê›b+¢âÊ£ãjâ?U²X\ÍÁƒ½¼¼†xzz:88´)Jx7ÑO‰‰‰ÅÅÅ;wîÄyI¿~ý–,YÂÿ{Ô¨Q°¢ éjkk¯]»¶jÕª¦où®oNÓîoÐúž²šñ¼?éFvpÜ ~‚ú©#011éß¿¿ƒƒƒ———d±päˆåË—Ÿ8qBðÊÈÈèÕ«ÔOØÉä¾}ûz{{5jÈ!4­ùTrr²­­íµ?&ú³ovZ•(@‘²òƨ¸²¨¸ò¨¸êäÔJA--Mööòòòôô´¶¶–ÅW'|xöìÙ¢¢¢òòr‰ë±´´TQQ¬\¹²OŸ>|uÅ?‘#*++,Xòo¬MEâÅÉZ½´ZYM&«êÍ>§`æÇ ê'¨Ÿ:›aÆùøøøûûS©Ôn6ÙØl¶¡¡aee¥¢:vìÔOøQUU:uê?þèäôÏÃÙÏod]uÚƒà4;åäÕFÄ–FÇ–EÅUå~©!ýû÷óò:xð`OOOÙ×ñ«Ÿ9räÈ¥K—>}úÔõûûûëéé6lØ`aaѬ‘á’Ÿ,sýúõiÓ¦ ™Ô_q‡Z«…µ†.Ñõ 4¨ŸäW?ùûû§§§ùòEÐoA.ÐÒÒš>}úܹsºÏÒù­[·&OžÜR ÈÂÛxll,ÿ×ÔÔTSSSPPðùóçׯ_§§§KE÷èéé))))++“Éd‹Åd2ËÊÊÊË˹\®dÓ{×®] øðáÃСC'Žé}tßp ´"žP„Ëã}N­ˆŠ-Œ)‹Ž¯(¯h R)®®.^^Þƒ4hššš<=¸:îuþüùàà`ü—LŸ>=66¶³dÚ´iîîÿîcŸ9s¦ºº:ü‰’©‡rUU•à‘O+õ)¤V~A•ûúÏûŽXϤ¦¦&??ÿÑ£Gûöí«­­Ås‰‘‘ÑöíÛ}||ôõõeÍpÒÔÔ”•••žžžœœœ””QPP /Ÿ…››ÛÎ;}||ºÁ¼òõõ}ñâEËãÇ_¶l™,·üÕ«WsæÌiÓ´¡Óé...®®®666¢v¨¡(¤¨¨øôéSCCÃððp‹…ó.D"qÕªU»vízýúõ„ ãÝ]ô—,°÷dD$€"L'>±$"¦$*¶,6¡¬¡‘­¦¦2hß™ÉÙÙYpPÎ^ü:B?UWWGDDÌ™3cµÎÃÃcãÆæææ‚{õêU^^Þü¬|úôiHHHjjª­µMdffÊÈÂ6pìØ±5kÖðx¼æ# Ý”WVi©žTíПt€HW…ƒÖÃùüù³³³s³«œ(“’’øÑ“傘˜˜¹sç&''ã,O¥RMMM---ŒŒ 5¾¡¢¢B¡P¨T*ߨÀ·+°X¬²²²Âo¤¤¤$&&JÖ`//¯]»vyzzÊï\ÊË˳²²jÕhmm––&ãËgÑÑÑnnnb‹õíÛ×ÏÏÏÏÏÏËË §:¹uëÖÛ·oO:ðøñ㺺º»wïž={6""gÛìíí?~œ››»víêÈÈh=]e*“É--¯çrCC½Áƒ‡ð™lmm»É*mØlöĉE}ÿ•””¶nÝzùòe‡³Â7oÞ\¾|ÙÀÀ@2—ûÌÌL"3lܸQèZ7D5uÿ_ürýøåú1Ëô, à4TÃá‚ð7nœØoú÷ß/wýº}û6ž‡ØòåË¿|ù‚ÿ™‰MEEÅ‹/Ö¯_ooo/\˜>}zee¥œN¤M›6atíñãDzß<ú)??¿MuFDDøúú²ÙlEýýýi>õöíÛàœ&&&YYY(Ц¦¦îÛ·o÷îݼtéRNNN·|.IY?1™Ì€€€VGV]]ýÍ›7í©üìÙ³‚›N¡~êú °ÖKu½·êzïMMŽŽŽÅÅÅp¸ |6oÞ,ö›¾nÝ:¹ëWs"l~ÿý÷j@qqñ™3gðÿ@òÑ×× ‘»Ñæp8úúúýòóó“w (~:{öì„ jjjøÿå/ àr¹û÷ïÇi¿°´´,))é!Ï%)ÛÐ~þùçÇ·úþßÎe?þøã£G®]»¦¡¡5º‡Þ×í[·ÿm]ó‘Áƒc?é = CCC±eŒŒŒä®_ºººZZZb‹u\|&}}ý   ¸¸¸øøø àÌ«ZRR2vìØ °Ùl9í{÷î•””`xöìYFF†Œ÷¢ÿþÒªŠÍf/Z´¨  àÖ­[ÍŽÛ–––ÙÙÙ‚ÅH$Òºuëž?®¬¬,¶Îœœœ©S§ÊÝV ɦ~Љ‰¹ÿ~ËãlÞ×´µµ§NzçΉ'ÊÝ®`2àùvaHYˆ ¢££#¶L'§nB> ­‚ç+ÓNƒƒƒÓÒÒf̘Ó7åüùó>>>íqNídNŸ>]EQÁ¸P² ?ůTعsg@@ÀöíÛL‡úòåËŒŒŒß~ûmãÆ¡¡¡|wÕaÆ=}úÏ“ùÍ›7Gí&)Ú²ZuÓVUU}ýúuG˜ÎƧƒpýNÖ ÄþȨT*%ˆ Ïž=ûMøð¡Å5æÁƒ¿ýö›¬ð‹/ÒÒÒ 4Hìjj*üÞ‰ÂÚÚÚÞÞ^l±øøx¨ŸÄ ¦N55µ¿þúkÔ¨QpfC P?Éx^º<ÙE¿~ý}:ö…—.]™µºg‚' Îðú=Z?É~~~‡†3énÏ)Ú¨ë'éÚ† ð$ k5r—pâÄ ¡XØ|ß±< çÏŸ‡_=Q´îQƒõ“䤦¦fffv²„jk.'"ãàñ™•Ó„x¶‚ËŽŠýóÏ?ñØ7mÚÄZݵÔÕÕ]¸pAðÈÀù¡AíííÝÝݱ/?uêTÉC"b#/Ùpu—iýtîÜ9Œ5ÎŒŒŒ¬¬¬Îì‘‘Ñœ9süüóÏp®C òýœ"»k×äkÛ ¥¥åO?ý$¶XJJÊÅ‹»¼µ.\ [ hvk‚ÊÉÉùûï¿á·¯UðØMµµµ¡~‚Édr¹\Œ¿tÉ’%‹/nþ/þ°D6éÆ/²]»·N6oÞŒÇÍ´ËC "䮡¡1yòäæÿN™2Eì¦BYdеà Ɇ'6GÖOb ûöm'¿ªÎŸ?_WWNq¤{Г…Ë]Ø*--­eË–‰-öñãÇØØØ.lç£G²³³Ìž=[ðWŸN§Ïš5 »’W¯^áLœ×Ó`2™bËXXX@ý„E¯^½°ã—ÔÕÕ={–Ífwf¯œœœüüüà‡@ ~’qäÎþX´h‹à¹s纰‘ÇŽ:ÒrÁOHh‚j•††±eÄÆÙêéúÉßß_lhÚëׯ¯_¿¾±±±3;¶lÙ2ü ÔO]BÆ—ccãÑ£G‹-výúu<ÉÚ:‚äääW¯^ ñööîÝ»·P±>}ú 2»ªË—/WWWÃï P?u’WæÑ£Gñ¤É”"ÎÎÎ?üðœåÔO2ý–O×øùóç‹-SWWÖ%Íki4ejk‚jllìZCšl’››‹]@CCÃÙÙê'éðûï¿Ï;7<<¼ÓîxòäÉiÓ¦á “ @ P?ágøðáx’ :‡ªªª+W®ÑÕÕ?~|«…Ç/ÖYöôéÓ²ŽA¦››eÆŒò¸6ÝÙúiÍš5xŠ!ò矎7îùóçÓ7uuõ«W¯nÚ´ Îuõ“QPP>|¸Øb¯_¿îü¶ ¹‹Ì›7OÔ:)•J›ö8//ïÁƒp® "Ö"SaèeW?}÷Ýwø —••M›6måÊ•PÎC ˆü†¶Â“o466¶®®®3[ÅårO:%x„@ ,\¸ã’… Š] †^ä‚TWWøð£ÀСCùqJ¡~ƒ‡‡G`` þò•••ÇŽóõõ…¡É ÔOrÚr<ÞÁ</99¹3[uïÞ½üü|Á#¾¾¾Øé---}||°«}ûömRRœ®|þúë/Œ¸áàÁƒ=âË+•ïÿ/¿üb``Ц«^¿~èááQXX§#È}ûöÅD#AEG€'lAK` ü (*˜TˆiÓ¦999Aý„[[[œ^P‚444„‡‡9òСCpRB ˆA&“ñ¬Ñtf Ô¸¸8¡FFFxB-Œ=ÚÐлÌÕ«W«ªªàç~ýúu ›¢––Öþýû{ÈPHÍt¼jÕ*< ™[’œœ¼nÝ: …âëëûèÑ#8;!D.ppp)ýÔÒø´`Á<¡>Éd²Xg&“ÜÃ?ñÚÚÚ 6ˆ:K .^¼hddõS+"wïÞ­®®.Áµ(Šr¹Ü/^L:ÕËË+!!¡©© >› D–133[æË—/Ó˜ÒÒÒ›7o !‘Høwýøãb• d°hÑ"!÷2AÖ¬YƒgWA·,ź&OžL£ÑÆŽ+q õõõ¡¡¡  444<|ø0|BÉwîÜyñâ…à‘iÓ¦yyyÁ‘@z b“O€NÌà~æÌ¡Da£FÂÓÂæ¾<|ø£Ìׯ_CBB&L˜Ð3?î-[¶)TA&Nœ¸wïÞž5"¨´yò䉲²²´š·gÏžÜÜ\ÒÕ`g =vì"H‡"öY‘ŸŸ»ÖÉà ijjÚ -ijjÒÓÓºõãÇÛT //¯ž9a¶lÙ‚qÇñãÇs8œžöP"àù0ÚÊÍ›7÷íÛ—˜˜(•Ú,--ÕÔÔ8àâ⢦¦Ö劳¨¨ˆŸúÇÈÈc¡766A ngÇž={455±«êPõ£¢¢bccÓjêêꨨ¨M›6%%%alXURRêÛ·ï­[·ðØóE‘——WVVÆÿ[OO¯=Ua••UUU¥®®nmm½èPZZºÿþ–i ètúÑ£G½zõÒÔÔ쩘œœÜÐÐðæÍŒ—Âð3|0€LÆko.))ùúõ«à‘®š¢ÍˆÐ“ŸŸßØ SÈo×ÒÒÒD=:šÑÔÔ¬¬¬ìè–\ºtiöìÙ‚G,,,²²²ÚA++«¼¼<ìb x¿ºÍ„©­­ ºqㆨS§N½xñ¢Íï/vLWÿ–׆„„àIIÑ’… FEEuŽÅøôéÓæææí™`...×®]ª¶¤¤„oTÃfݺup‘ v­™òòr±§P(ÝŒ–±°)Jii©U•””ˆµ£Ðéôòòrùš0ÕÕÕqqq\.ç-jjjÎ;gooq“>ôh§‚޾A\\Ü Aƒ¤kS¡R©vvv¯_¿®­­m %ˆ\ÅgëÖ­ü¾|ùrüøñÞ½{K¥wjjjÇ Ã?×›‰ŠŠ²§¡NH?åçç2„¿èÓVÊÊÊ:S?½yóF°Ë8­#BúéË—/îîîíñÛÓÓÓ{òäIUUUÇ}•–/_.ªƒ$iÐÁX[¤Óé»víÊÌÌDQ4;;{ß¾}òZèg)88Š Ø5> ClãÕÕÕ;º“&MºéäÉ“¥X[KvïÞ-_¦±±‘F£©ªªúøøüüóÏW®\ /((`0<ÉdVTT|úôéþýû[·nõññÁNýK£Ñ6mÚÔÐÐÐÓ2;ç6ׯ_wppúÊ”ŸŸß£GØlv{ÚsñâE;;;üëå[·når¹°³³kµ‘HThžˆ½|Ž=Êb±ÚÔ—1cÆH0ŒÍú‰ÇãUTT8::¶4Ò6·_lmW®\inϧOŸ.^¼xñâÅI“&µ)7~ý$™Å¨Y?1™LŒO°­Lš4©ƒœ(ß½{‡ñáöë×ïêÕ«B—¼~ýúâÅ‹ÚÚÚ¢®êի׬Y³°ýÀZ53 (2`×øO ±722êÐ6|ýúµå/Ë«W¯$®ðåË—b;ellÜ…îÒ’Mooïö?âˆDâøñãù¯^Й7 ñóó“ú¤››[ˉùõ×_qþšúùùÍŸ?¿ÕSÞÞÞ+V¬8xð`ËúY,ÖŠ+Æçúúú øîܹàÔjÍú©¥s’¥¥åŠ+^¼xÑ|‹~ø¿~$))iÞ¼yR×O§Njî/~§N¾~ŠˆˆÌ̆Á¨Q£˜L¦t¿8ïß¿µ.L"‘V¬XQ\\,êÚ¤¤¤6­÷Íœ9sÅŠžžže*++¡È€]ã¿~ˆm¼µµu‡¶aýúõÒ½#‚ x^*nÞ¼)_fçÎíy²)**þôÓOP6u~BQ´¦¦æÕ«W^^^ÒõB¥Óé666Òúh‹‹‹ÿý÷¶®æ(((xyy­]»6%%Eì:ƒÁˆ‰‰ñòòë/¥§§—œœ,YGÒÓÓß½{'Ö‘ÐÓÓ“ËånÞ¼YÐDD¥R8Ðò{XSSƒíZÔ«W/Qía³Ù{÷îÅc†”Ìÿ©¤¤$%%eöìÙb³1º¹¹=xð UÛŒ‡‡‡—————׆ RRR6oÞÌÿ¯¾¾>Ι)ůLccã”)SZ½‘ŠŠÊùóçÅÖ˜˜(ÖÉwÀ€çÎKIIá›<+++SRR–.] õìxò™8::v\[®S>|¸ÕâI)æáá!_&<<\²ßÖQ£F={¶K¾õP?µÎõë×íì줻ã±W¯^iiiÒj¡»»;þ[ó·!Hp—]»v‰Õ–––B~Ùm">>;.¼ŽŽÎäÉ“…äÅÝ»wEU˜ššŠ±§¬¬ŒÝž7ŠuÌ’ØœOTTT['²²òÿþ÷¿«W¯Š2ËGDD\½zŸ©©i{>/A8ÎÏ?ÿ,êFøCÑ$&&b¿ÄÇÇ·¼JÔæ>¨Ÿ`×øð#¹´É×Pºüþûï-ïÛ??+**ðïãââähÂðx¼ˆˆˆ3gÎ :ÔØØ¸Ug`ii9vìØ-[¶Ü¿¿Kë¡~ÂÅíÛ·}||¤(¡LMMýõW©´-22¿ÿÐ¥K—$¾ÑÉ“';úîÊ•+mZk?ç)V?¡8œ–Ú©ŸPÅ?¯TUU×®]‹Ó2''gùòåbë\¿~½T&á_ýÕVÑ# QF,¨Ÿ ~’<¹í–.]Úq èׯ_Ëh©ÔŒg/öìÙ³åzÂp¹Ü¤¤¤˜˜˜ÄÄÄÜÜܪª* ö-AýÔeÔÔÔ<þ|èСҒPaáÂ…íWÍL&OœþaƵs×—Ëýõ×_ÅîwhÞîסúÉÍÍ­¢¢Bl…­ê'ccãE‹eee‰½\(GzGè§ß~û O—,YÒÖ÷<#ƒ¦ØEÌ6ѧOQ· lÓö‚úúúŠªíûï¿Ç©ŸV¯^Ý%OX¨ŸdGÉÂ÷a{«üñÇ-W*sssKJJà"WÇ'„’ÌvMl‚ A:âÖ-Ý•””¤QYзDIIIì§Ó2š?ü.Àõ»®ÄØØxÏž=>ܱc‡ËI| Þ¸q£ÄÙ—°=…544¤»Ñ»wo±W'NœúhÛØØÜ¹s*ÜÂÂÂððð»wïK–K„B¡H=ðR›PPPPTTlO ø^q×_VV†‘°Sâ/E[ß@ÌÍÍ[¦µ‡@š§± 4¨#&ÖÕÕ]¸pAèàÔ©S¥ûTQSSÃŽÕ§™:!ò Q–×»wïÿýïyyyÅÁ‹õ¡IDAT›7o–8·ÆñãÇ==»v V‰¹páB}}½ÐÁ   ©ßO‘‘‘üŒò¨Ÿdeeå;wfdd¬[·N²¥t ²pwÕƒoĈØú©  àâÅ‹pâB$@KKËÃã“¿&Øl¶Øw¹ŽÐO¨ˆ˜/ÎÎÎiãââ‚§I-=Ù!P?Éû÷ïøðáÖ­[۴ퟟùòeyééO?ý„]àÔ©SpâB¤Nuu5~>}ú„½ÇYKK«#¬Ô=ÊÊÊ’©¡øë¯¿:ngê'éЧOŸmÛ¶·i“*›Í>{ölmm­tÓëú€þýûÃyÙ=hH·ÿ¸lƒ]`Ò¤IRÏdÒØÃf³qœƒ@ýÔÅÌœ9óéÓ§S¦LÁïEûáÇwïÞÉEï utt0 p8œÍ›7ùÛ娫«c¯y=zôH¦ÜÐÐ k/îAä´åbó©M:Uê7MNN~ùò¥ ŽÆï¿ÿ@ý„ ƒñîÝ»Vÿv***7nÜVQQÁyÉ‘#Gðd ïr<<<°MP(ŠÖÕÕÁ¹Ûõ_"ÿô“Š‹‹ïß¿/ê,þ ˜¨Ÿx<^ËðK‚˜˜˜t„ó“Ìnv+..ÆÎ¶úé®^½êííÝåŽ8ãÆ»}û6Î oß¾}þü9üÈ!VÙ³g¨Ÿpòþýûªª*ŒsæÌ‘º‡CUUUËPv³fÍê„H?Û·o—_m‘-ýÄçþýû]¾gÇ××÷Þ½{ðÕÒÍPTTÄH~·fÍ8DP?u!†LþìÅ“f»­766 숵dÑ¢EØ)JÑÑÑQQQpJCý$UUUþ&¸«W¯~ùò¥kû0zôèV·³Ê/yÊø„„„tù°C:zŒ7NÔÙ†††ŠŠŠ¶Ö‰áxÛ§OŸ‘#GÊìhÈu$l¸\®Üµ™Çãݹs£À‚ Ä>ÄÚ ‡Ãi=xàÀ$2’==½I“&‰-MPP?‰gêÔ©}ûö2`øðáÝ)0à®]»° äçç3 8}»7~~~AÒ%ØCšš*ê”ššš¡¡!ÔOP?ááÞ½{¢ÎR(”µk×Jý¦7oÞl™®xÙ²eÖk<÷ºuëVqq1ü.@ý„Y0Aéêê¾~ýZl1%"Gxyyaxà^¸pATÆßV ÁØ‚Š‘Zê'¨Ÿ„8zô(ÆÙ H†\,GŽ:b``€Æ[º¸¹¹‰ §ÉápΜ9Óåߨ±d]?5gÅJKK?~|—÷DAAaõêÕØeÎ;?rˆ±råJQ&(6›]TT„³žŠŠŠ½{÷Šú©^°`ŒGëÆ¿rÿ)...,, ãUv÷îÝR¿éÛ·o[¦W_´h…Bé̾ã1A={;¬(ü¾@ý¶mÛÖüwRR’,„ œ={¶‘‘üP!Ý??¿Ã‡‹:;wîÜèèh<õüúë¯%ƒƒƒ%Î/Ù9Ȳ“5‹Å¢Óéütm½¼ËkÛÊ–-[0Îì:"xçC àâ]÷¦¶¶vñâÅ÷ïßTBžžž!!!.\¸víZDD„½½ýwß}×òZQâI]]ÝÞÞ~ÇŽÏž=Û½{·‰'Yþ= p ô“\$嬬¬ 5µ¼¼¼öíÛ×A÷={ö¬ÐA ŽÈLŒŸÁƒ;88`—ár¹§OŸîˆ»ãÑOr·)¡'ê§VÕçÏŸ—ñX2RÔ1]r_ …ÒR¹Bº‹- K{äÈ‘›7oòf•””ÜÝÝCCCOŸ>=yòdìÚ–,Yrúôé›7o&&&þïÿëÕ«—Ü H³ƒ¶¬!vÎÔÔ´ûé'‡3mÚ´üüüVÏ:::>xð ƒ^M9ÒÐÐ tpæÌ™ ];&8tļ…ú©›è'"‘Øêï¦M›Ö­['k]511133“ý$''§e˜]¡·8q»+cÆŒá;0ñQUU}úôéÊ•+[î×ÓÓ[¼xñ7x\ºt‰÷_Nœ8±xñb___ù™BúI‚¸‘,K–GžÇãM›6MTæõ>}ú<{öLMM­#n][[۪ǞpÍ´iÓ´´´°Ë”——_¿~½Kô“ŒO*¨Ÿ€L&¶<Ž¢èÑ£G·oß.SVw[[[±FWYàîÝ»Nš€3fÀ‰Û]IJJòmrqqÁÎLG ˆÌœ9“ø_ºÊPÚíõSMMMbbbóµµµ%°‹´Lˆ+; (:oÞ¼Û·o·zÖÌÌìÅ‹:::t÷'NÔÖÖ tuuíׯ_— NŸ?¾Øb‘MK–'ÔOâáp8Û¶m+//ïäþ\½zUÞeÇÞ½{1ÎZXXxxxÀ‰Û-AQtÏž=‚Gœœœ°7ßõêëëe°Uoß¾Ü %YÒ’–ëS2‹Åš>}º¨égkkjllÜAwg0­f‰™3gŽŒŒÏO?ý$Ö‰0!!áýû÷Ò½/žµ9¨ŸäC?ÙÙÙaD›õ÷÷ÿúõkgöçÇ¢NÉŲWTTöëÅĉ­­­áÄí–<}úTÈødii)Ëi};ºº:lUûïdV?yyy‰Z~1bDXXXG$¹kæØ±c•••B)ŠXo¿NÃÌÌìûï¿[LêÞÀxl±²ù¾õ“0ÞÞÞ) >}ú4aÂlo)rûömQ+_óçÏ—z°Úß~û ;ôs[ijj:sæ Æótâĉ۷o‡³¶»²k×.8­RQQ!ƒ­Œœ ÌÃ`0d­_÷ïßwrrõp›;wîãÇUUU;T.·š¶hذab½Ž:“Å‹‹-óðáÃôôt)Þm©åº'Dõ“XbccÇŒsòäÉNÈ`UZZÚª6WRRZ¼x1•J•îíJJJvîÜ)Å~•––^¼x£ÀêÕ«»|ã ¤ã(((€ƒ ê«!kM*++KNN<"™¥P¦~êÊÊÊÇŽ[RRÒò¬¢¢âéÓ§ÿøãŽÎÚ{ôèÑêêê–ÇÇŒ#SsÀ××Wìž$A¤›™-V6ß7 ~’„¸¸¸eË–ag”Ê»àÒ¥K[=åçç×A!=>|øìÙ³zbèС„S¶G‘••%jßxO™jŠ¢÷ïߊ +™~ª©©‘…UWWóc[îýÄÙÙ9>>Å¥ÔÔÔ9r¤ÕSÞÞÞ25 ÂÌ™3Å»téÒ—/_¤uÓââb<ïöð¡!úiëÖ­xŠ!!á‡~xöì™–––Ä19αcÇDyBŒ1âÂ… ~úí$===<<¼ƒ²5µJaaá7°2!%×÷ØnøüÀHíŒÁÍ`0ĦqÀÏÓ§O«ªªZ‰‰ùá‡æÌ™3oÞ¼æƒ4­9b!¶òÇÏœ9Ãÿ{åÊ•}úô<«  ÐžAîŽ;–——'E%„¢(p8.—Ëf³›šš˜L&“Élhh`0µµµ555UUUeee999YYY999býv%ÓO¿I¹ÙŒñøñã‹/†††b›8qâþýû;M¸$''‹2>rss…&p—ƒ3íåË—G=qâD©<(Ä–ILLd³ÙRwY´þ4iìÏ7n—ËE¥ÁëׯEý R(”´§ò6Eݸq£dwa0~†Úþ±»é÷Ê•+h'’™™)v|øÀíùú¯X±âðáÃ/^¼@e•K—.ɾÂkVBt°Õ$|ئ«¬­­7lØ0räH‰·g—––Ο??<<¼UË“ššÚ©S§¦OŸÞž®±Ùl†³0•J]»víŒ3lllðß"""âСCwïÞmõl@@À•+WÚiyÊÎζû{wÓÄýǼ–¶Ôk ¬UZ‡[ é¦È¦£ Fƒq#b ,&nn.›Ã,£Ä,1 —ሃi\Šƒn#qƒ›€Ù\0Í¢ áÁ:F«<ôaÔßý5Ð^¯Ïe¾_z×Þ]ï{í}ú½ï}> Ä¿ž…BáÏ?ÿì‰òéV.­©¾HKK‹ÓI•J¥Ýk ‰‰‰–ÉpèÐ!»©¿øâ 2yöL—ó}˜p8œÈÈH©Tš——GætîZ­öÈ‘#î­ùí9ƒÁ¡T¥¿ÿþ{eeeWWù—°X¬èèègŸ}–Çãñx¼ððp‡Â`0 FÓétZ­V«ÕÎÍÍMNNŽÝ»wïÖ­[d†Óh´¬¬¬ŠŠŠ-[¶xnwõ÷÷›ºõz½Z­Ëåd®fÆÄÄ$$$…B.—fú›””ä¹Mµd4ççç'&&ºººÎž=ëÐ-D©©©‰ä¹çž  ¢ÑhÄÿ?ÖjµSSSJ¥ò‡~8}ú4ùÜâqqqûöí{ùå—cbb¸\.“É\.?Ež¢þ§Ç;¦$''×ÕÕ©ÕjNGr]¦Ï[CCÃK/½dk±l6û믿vý}9Q½H \¼xqnnŽ`ɃA­VŸ?žÅbÙú±"‘HT*•+Û¯×ë•J%ÉïØØX¥R©×ë=³wvvFFFÚÝžU«V]ºtɉ&ûã?Ètª3™Ì¦¦&µZm0ý¯V«+**Èä¿a³Ùv'úŸ<ä…^xï½÷¼p ØuîÜ9Ÿï ‡DEE‘w<())ñ·Î|>ÿwÞõBûúí¹Ì;›J°ÙËëÔÿ”óqüd–——'“Éš››m­âÓO?•Éd2™Ìîº233ݵw\©þ˜œœ,{âþýûæe* ™LV\\LðÚÐÐÐîîn7¾»»Û‰v),,”ÉdÆG›F£‘Éd¶BÆ¥;;;ÉŸ“d2Y^^ž£o¹¨¨¨¯¯äZFGGOœ8áÄÁðå—_Ú]8ñQá5R©Ô÷_LËÍúõëI¾µS§Nyn,£bcc=zåʣѸ¬Ûñâ§åwýŽB¡Ü½{wÑø¸¸¡¡!G—Ãd2m]α[7Q"‘;vL$…„„¸å#¾~WQQ166ÖÝÝm7ÙÆêÕ«ÍCùT*AƼuëÖåä䔕•9—ÛwppP¥R½ýöÛæŸþqúÖžèèh–™™™™™™””Äår>0ÌwžÖÖÖ:z}ŠÃá„……þøãwß}×r ‹Å"“T«ÕÜV611aÎ&ŸžžÞÑÑa9—Íf›ïM³Å`0ŒéééY4øC$ ,j/»ƒ t:ÕX™Á`XíÚœœœÜ»w/q0¯ða½mÿ‰Ÿž Ñh+W®d±XAAA!!!¦a7«V­âóùB¡0!!äÐ1O¿5*•Êd2YOóù|@ ¢££×®]ûâ‹/’Ö‰ø ñØBsËR †\._t–5÷H™oÚloo7Õ§»téÒõë×]_/—Ë=xðà† ²³³}õšššššzëÖ­sçÎutt\¹rÅ¡…”——›Ò+=zÔõn³ÜÜÜEÅÉ‹ŠŠìŽ >s挭¹® *ß´iÓ¢øiûöí¯¼òŠÝöõõ}ÿý÷¶æ™ÿß»w¯X,¶œ[ZZj·’†R©$Hõ¾´ó¯¨¨hQںÇÛ-%188h5Á­/QQQß|ó É„ ž–››«P(º_îdÔ××?óDÐL&“N§›bµÿü‰gµ¯—7aÍS×ÿä¨ééiSoMss³)ûˆÑh$Näiy'''G"‘ÐétžlˆûŸŽ?¾(w¨Z­6÷j”••™/8^¾|Ù2ID"1gûäñxv;Kàé±°°066–œœì«´@–.\¸àÄx2ÄOÞc4‰3 DEE-êfðGã'[ººº=z´k×.p`×ÌÌLLLŒJ¥¢P($o9~ã7l}@jkk—æ,~øð¡ÝB¤[·nõyâoÿä/=T*ÕßjCº‘¿•mžvíÚe ž(ÊÐÐPXX˜‹Ë´úÉjooïïïohh (388ˆ°·`ø •J•““cN¨ë¹B÷~øáÍ›7Mµt¬&KT«ÕÕÕÕhÄOþ«££Ã||@@@YY™»2qØÂåry<^~~~[[Ûwß}·(kƒÑh$“±ñøFOOOii©ù!ŸÏ///÷ÚÚ9ÎîÝ»«ªªÐˆŸ–½^___O…Ë;8ŸŸo9E©TÚf€ø |`ff¦¹¹Ùç›±råʲ²2Ë)r¹Ünz}ÄOà/^ô“- …>L;€øé¿‰bÁ]ˆ“ÇzÓš5k,SØÇÅÅù° â'°nnnŽ ¤´oeee9]=ñX±ìJăêëë3ØÄO°üûÌû¹—¾ýö[óÿ,+33m€ø Àïlݺ5;;{éôÞÞ^s-<ï¸}ûvKK‹ù᫯¾ºiÓ&4â'wBþpχJ °:K*•¶µµyg3FFFvîÜ966fz\YY‰Ö@üäf¸ÿ±X|íÚµÙÙY·¬ôæÍ›mmmb±ø«¯¾ZXXøÿ—•úÖ[o ´ â'g'ÂQ(>Ä^×±ÙìòòrâçÌÏÏ_½z5%%åõ×_/))qeu'Ož,))Ù°aÃîÝ»¯^½ºhnqq±L&c2™h[V`4¢¢¢³gÏñ·lÙÒÓÓƒ¶ FÃ.°evvöï¿ÿÆ~¯©©©)--žž&ÿ’ÆÆÆÆÆF …" CCC—>A£Ñܹs‡Ôo©+6nÜxâÄ 4€ýïLô?ÙÒ××g7ùMMMÍ‘#G°¯À]ärùž={ŒF£·¿V¬8pà@}}=š€ Œ²îÏ?ÿܳgݧ555ŒŒ`w»äää( ‹åÍ•ÆÇÇ×ÔÔ xpàg'úŸ–ºsçNZZš9‘ 1‘HT[[›’’B£áb(¸ÇÐÐPuuµéœG%&&^¸pÏçc· ~rÌ‚^¯§P(½½½ýýýJ¥Ò¡%¬^½ºªªÊôN§#œWÌÎÎÊåòÇOOO{ârNOKK{óÍ7Qáñ“ÃZZZFGG¯_¿îÞZ÷ÙÙÙiii–S¨Tê¡C‡pÀ£NŸ>ÝÐÐpãÆ w-066vÇŽKQ@üDVzzzGG‡ÕY!!!IIIä5??íÚ5[s †§KpÀ•J¥ššš:yòä_ýõË/¿8ñ™]»víš5k"""ªªªØl6q®N@üdGggçää¤ÕYááá;vì ¿¨G) [s©TjAA8pÑùóçÍ—ó>úè£ÑÑQ«O‹·ìïLLLŒÇÞ@üàÈ_€ø ñâ'ÄOˆŸñâ'ÄOˆŸ? ~ÄOˆŸ? ~@üˆŸ? ~@ü€ø àéò? ‹ä}b@3ÙIEND®B`‚libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/resources/xsl/0002755000000000000000000000000011550465534021302 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/resources/xsl/html_chunk.xsl0000644000000000000000000002670211134200352024152 0ustar '5' '1' 1 0 1 0 book toc 3 1 1 90 figure after example before equation before table before procedure before ,

Authors

1
libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/resources/xsl/fopdf.xsl0000644000000000000000000004476111474433614023141 0ustar Copyright © 2005-2010 , -5em -5em Spring LDAP ( ) 1 0 1 1 book toc 2 0 0 0 5mm 10mm 10mm 15mm 10mm 0mm 18mm 18mm 0pc justify false 11 8 1.4 0.8em 17.4cm 4pt 4pt 4pt 4pt 0.1pt 0.1pt 1 left bold pt 0.8em 0.8em 0.8em pt 0.1em 0.1em 0.1em 0.6em 0.6em 0.6em pt 0.1em 0.1em 0.1em 0.4em 0.4em 0.4em pt 0.1em 0.1em 0.1em bold pt false 0.4em 0.6em 0.8em pt 1em 1em 1em #444444 solid 0.1pt 0.5em 0.5em 0.5em 0.5em 0.5em 0.5em 1 #F0F0F0 0 1 90 '1' figure after example before equation before table before procedure before 1 0.8em 0.8em 0.8em 0.1em 0.1em 0.1em libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/resources/xsl/html.xsl0000644000000000000000000000643611134200352022764 0ustar html.css 1 0 1 0 book toc 3 1 0 90 0 figure after example before equation before table before procedure before ,

Authors

libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/resources/css/0002755000000000000000000000000011550465534021264 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/resources/css/html.css0000644000000000000000000001152011021724376022732 0ustar body { text-align: justify; margin-right: 2em; margin-left: 2em; } a, a[accesskey^="h"], a[accesskey^="n"], a[accesskey^="u"], a[accesskey^="p"] { font-family: Verdana, Arial, helvetica, sans-serif; font-size: 12px; color: #003399; } a:active { color: #003399; } a:visited { color: #888888; } p { font-family: Verdana, Arial, sans-serif; } dt { font-family: Verdana, Arial, sans-serif; font-size: 12px; } p, dl, dt, dd, blockquote { color: #000000; margin-bottom: 3px; margin-top: 3px; padding-top: 0; } ol, ul, p { margin-top: 6px; margin-bottom: 6px; } p, blockquote { font-size: 90%; } p.releaseinfo { font-size: 100%; font-weight: bold; font-family: Verdana, Arial, helvetica, sans-serif; padding-top: 10px; } p.pubdate { font-size: 120%; font-weight: bold; font-family: Verdana, Arial, helvetica, sans-serif; } td { font-size: 80%; } td, th, span { color: #000000; } td[width^="40%"] { font-family: Verdana, Arial, helvetica, sans-serif; font-size: 12px; color: #003399; } table[summary^="Navigation header"] tbody tr th[colspan^="3"] { font-family: Verdana, Arial, helvetica, sans-serif; } blockquote { margin-right: 0; } h1, h2, h3, h4, h6 { color: #000000; font-weight: 500; margin-top: 0; padding-top: 14px; font-family: Verdana, Arial, helvetica, sans-serif; margin-bottom: 0; } h2.title { font-weight: 800; margin-bottom: 8px; } h2.subtitle { font-weight: 800; margin-bottom: 20px; } .firstname, .surname { font-size: 12px; font-family: Verdana, Arial, helvetica, sans-serif; } table { border-collapse: collapse; border-spacing: 0; border: 1px black; empty-cells: hide; margin: 10px 0 30px 50px; width: 90%; } div.table { margin: 30px 0 10px 0; border: 1px dashed gray; padding: 10px; } div .table-contents table { border: 1px solid black; } div.table > p.title { padding-left: 10px; } table[summary^="Navigation footer"] { border-collapse: collapse; border-spacing: 0; border: 1px black; empty-cells: hide; margin: 0px; width: 100%; } table[summary^="Note"], table[summary^="Warning"], table[summary^="Tip"] { border-collapse: collapse; border-spacing: 0; border: 1px black; empty-cells: hide; margin: 10px 0px 10px -20px; width: 100%; } td { padding: 4pt; font-family: Verdana, Arial, helvetica, sans-serif; } div.warning TD { text-align: justify; } h1 { font-size: 150%; } h2 { font-size: 110%; } h3 { font-size: 100%; font-weight: bold; } h4 { font-size: 90%; font-weight: bold; } h5 { font-size: 90%; font-style: italic; } h6 { font-size: 100%; font-style: italic; } tt { font-size: 110%; font-family: "Courier New", Courier, monospace; color: #000000; } .navheader, .navfooter { border: none; } div.navfooter table { border-style: dashed; border-color: gray; border-width: 1px 1px 1px 1px; background-color: #cde48d; } pre { font-size: 110%; padding: 5px; border-style: solid; border-width: 1px; border-color: #CCCCCC; background-color: #f3f5e9; } ul, ol, li { list-style: disc; } hr { width: 100%; height: 1px; background-color: #CCCCCC; border-width: 0; padding: 0; } .variablelist { padding-top: 10px; padding-bottom: 10px; margin: 0; } .term { font-weight:bold; } .mediaobject { padding-top: 30px; padding-bottom: 30px; } .legalnotice { font-family: Verdana, Arial, helvetica, sans-serif; font-size: 12px; font-style: italic; } .sidebar { float: right; margin: 10px 0 10px 30px; padding: 10px 20px 20px 20px; width: 33%; border: 1px solid black; background-color: #F4F4F4; font-size: 14px; } .property { font-family: "Courier New", Courier, monospace; } a code { font-family: Verdana, Arial, monospace; font-size: 12px; } td code { font-size: 110%; } div.note * td, div.tip * td, div.warning * td, div.calloutlist * td { text-align: justify; font-size: 100%; } .programlisting { clear: both; } .programlisting .interfacename, .programlisting .literal, .programlisting .classname { font-size: 95%; } .title .interfacename, .title .literal, .title .classname { font-size: 130%; } /* everything in a is displayed in a coloured, comment-like font */ .programlisting * .lineannotation, .programlisting * .lineannotation * { color: green; } .question * p { font-size: 100%; } .answer * p { font-size: 100%; } libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/pooling.xml0000644000000000000000000003537011021722676020655 0ustar Pooling Support Introduction Pooling LDAP connections helps mitigate the overhead of creating a new LDAP connection for each LDAP interaction. While Java LDAP pooling support exists it is limited in its configuration options and features, such as connection validation and pool maintenance. Spring LDAP provides support for detailed pool configuration on a per- ContextSource basis. Pooling support is provided by PoolingContextSource which can wrap any ContextSource and pool both read-only and read-write DirContext objects. Jakarta Commons-Pool is used to provide the underlying pool implementation. DirContext Validation Validation of pooled connections is the primary motivation for using a custom pooling library versus the JDK provided LDAP pooling functionality. Validation allows pooled DirContext connections to be checked to ensure they are still properly connected and configured when checking them out of the pool, in to the pool or while idle in the pool The DirContextValidator interface is used by the PoolingContextSource for validation and DefaultDirContextValidator is provided as the default validation implementation. DefaultDirContextValidator does a DirContext.search(String, String, SearchControls) , with an empty name, a filter of "objectclass=*" and SearchControls set to limit a single result with the only the objectclass attribute and a 500ms timeout. If the returned NamingEnumeration has results the DirContext passes validation, if no results are returned or an exception is thrown the DirContext fails validation. The DefaultDirContextValidator should work with no configuration changes on most LDAP servers and provide the fastest way to validate the DirContext . Pool Properties The following properties are available on the PoolingContextSource for configuration of the DirContext pool. The contextSource property must be set and the dirContextValidator property must be set if validation is enabled, all other properties are optional. Pooling Configuration Properties Parameter Default Description contextSource null The ContextSource implementation to get DirContext s from to populate the pool. dirContextValidator null The DirContextValidator implementation to use when validating connections. This is required if testOnBorrow , testOnReturn , or testWhileIdle options are set to true . maxActive 8 The maximum number of active connections of each type (read-only|read-write) that can be allocated from this pool at the same time, or non-positive for no limit. maxTotal -1 The overall maximum number of active connections (for all types) that can be allocated from this pool at the same time, or non-positive for no limit. maxIdle 8 The maximum number of active connections of each type (read-only|read-write) that can remain idle in the pool, without extra ones being released, or non-positive for no limit. minIdle 0 The minimum number of active connections of each type (read-only|read-write) that can remain idle in the pool, without extra ones being created, or zero to create none. maxWait -1 The maximum number of milliseconds that the pool will wait (when there are no available connections) for a connection to be returned before throwing an exception, or non-positive to wait indefinitely. whenExhaustedAction 1 (BLOCK) Specifies the behaviour when the pool is exhausted. The FAIL (0) option will throw a NoSuchElementException when the pool is exhausted. The BLOCK (1) option will wait until a new object is available. If maxWait is positive a NoSuchElementException is thrown if no new object is available after the maxWait time expires. The GROW (2) option will create and return a new object (essentially making maxActive meaningless). testOnBorrow false The indication of whether objects will be validated before being borrowed from the pool. If the object fails to validate, it will be dropped from the pool, and an attempt to borrow another will be made. testOnReturn false The indication of whether objects will be validated before being returned to the pool. testWhileIdle false The indication of whether objects will be validated by the idle object evictor (if any). If an object fails to validate, it will be dropped from the pool. timeBetweenEvictionRunsMillis -1 The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle object evictor thread will be run. numTestsPerEvictionRun 3 The number of objects to examine during each run of the idle object evictor thread (if any). minEvictableIdleTimeMillis 1000 * 60 * 30 The minimum amount of time an object may sit idle in the pool before it is eligible for eviction by the idle object evictor (if any).
Configuration Configuring pooling should look very familiar if you're used to Jakarta Commons-Pool or Commons-DBCP. You will first create a normal ContextSource then wrap it in a PoolingContextSource . ... ... ]]> In a real world example you would probably configure the pool options and enable connection validation; the above serves as an example to demonstrate the general idea. Ensure that the pooled property is set to false on any ContextSource that will be wrapped in a PoolingContextSource . The PoolingContextSource must be able to create new connections when needed and if pooled is set to true that may not be possible. You'll notice that the actual ContextSource gets an id with a "Target" suffix. The bean you will actually refer to is the PoolingContextSource that wraps the target contextSource Validation Configuration Adding validation and a few pool configuration tweaks to the above example is straight forward. Inject a DirContextValidator and set when validation should occur and the pool is ready to go. ... ... ]]> The above example will test each DirContext before it is passed to the client application and test DirContext s that have been sitting idle in the pool. Known Issues Custom Authentication The PoolingContextSource assumes that all DirContext objects retrieved from ContextSource.getReadOnlyContext() will have the same environment and likewise that all DirContext objects retrieved from ContextSource.getReadWriteContext() will have the same environment. This means that wrapping a LdapContextSource configured with an AuthenticationSource in a PoolingContextSource will not function as expected. The pool would be populated using the credentials of the first user and unless new connections were needed subsequent context requests would not be filled for the user specified by the AuthenticationSource for the requesting thread.
libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/contextprocessor.xml0000644000000000000000000002225611471054707022633 0ustar Processing the DirContext Custom DirContext Pre/Postprocessing In some situations, one would like to perform operations on the DirContext before and after the search operation. The interface that is used for this is called DirContextProcessor: public interface DirContextProcessor { public void preProcess(DirContext ctx) throws NamingException; public void postProcess(DirContext ctx) throws NamingException; } The LdapTemplate class has a search method that takes a DirContextProcessor: public void search(SearchExecutor se, NameClassPairCallbackHandler handler, DirContextProcessor processor) throws DataAccessException; Before the search operation, the preProcess method is called on the given DirContextProcessor instance. After the search has been executed and the resulting NamingEnumeration has been processed, the postProcess method is called. This enables a user to perform operations on the DirContext to be used in the search, and to check the DirContext when the search has been performed. This can be very useful for example when handling request and response controls. There are also a few convenience methods for those that don't need a custom SearchExecutor: public void search(Name base, String filter, SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) public void search(String base, String filter, SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) public void search(Name base, String filter, SearchControls controls, AttributesMapper mapper, DirContextProcessor processor) public void search(String base, String filter, SearchControls controls, AttributesMapper mapper, DirContextProcessor processor) public void search(Name base, String filter, SearchControls controls, ContextMapper mapper, DirContextProcessor processor) public void search(String base, String filter, SearchControls controls, ContextMapper mapper, DirContextProcessor processor) Implementing a Request Control DirContextProcessor The LDAPv3 protocol uses Controls to send and receive additional data to affect the behavior of predefined operations. In order to simplify the implementation of a request control DirContextProcessor, Spring LDAP provides the base class AbstractRequestControlDirContextProcessor. This class handles the retrieval of the current request controls from the LdapContext, calls a template method for creating a request control, and adds it to the LdapContext. All you have to do in the subclass is to implement the template method createRequestControl, and of course the postProcess method for performing whatever you need to do after the search. public abstract class AbstractRequestControlDirContextProcessor implements DirContextProcessor { public void preProcess(DirContext ctx) throws NamingException { ... } public abstract Control createRequestControl(); } A typical DirContextProcessor will be similar to the following: A request control DirContextProcessor implementation package com.example.control; public class MyCoolRequestControl extends AbstractRequestControlDirContextProcessor { private static final boolean CRITICAL_CONTROL = true; private MyCoolCookie cookie; ... public MyCoolCookie getCookie() { return cookie; } public Control createRequestControl() { return new SomeCoolControl(cookie.getCookie(), CRITICAL_CONTROL); } public void postProcess(DirContext ctx) throws NamingException { LdapContext ldapContext = (LdapContext) ctx; Control[] responseControls = ldapContext.getResponseControls(); for (int i = 0; i < responseControls.length; i++) { if (responseControls[i] instanceof SomeCoolResponseControl) { SomeCoolResponseControl control = (SomeCoolResponseControl) responseControls[i]; this.cookie = new MyCoolCookie(control.getCookie()); } } } } Make sure you use LdapContextSource when you use Controls. The Control interface is specific for LDAPv3 and requires that LdapContext is used instead of DirContext. If an AbstractRequestControlDirContextProcessor subclass is called with an argument that is not an LdapContext, it will throw an IllegalArgumentException. Paged Search Results Some searches may return large numbers of results. When there is no easy way to filter out a smaller amount, it would be convenient to have the server return only a certain number of results each time it is called. This is known as paged search results. Each "page" of the result could then be displayed at the time, with links to the next and previous page. Without this functionality, the client must either manually limit the search result into pages, or retrieve the whole result and then chop it into pages of suitable size. The former would be rather complicated, and the latter would be consuming unnecessary amounts of memory. Some LDAP servers have support for the PagedResultsControl, which requests that the results of a search operation are returned by the LDAP server in pages of a specified size. The user controls the rate at which the pages are returned, simply by the rate at which the searches are called. However, the user must keep track of a cookie between the calls. The server uses this cookie to keep track of where it left off the previous time it was called with a paged results request. Spring LDAP provides support for paged results by leveraging the concept for pre- and postprocessing of an LdapContext that was discussed in the previous sections. It does so by providing two classes: PagedResultsRequestControl and PagedResultsCookie. The PagedResultsRequestControl class creates a PagedResultsControl with the requested page size and adds it to the LdapContext. After the search, it gets the PagedResultsResponseControl and retrieves two pieces of information from it: the estimated total result size and a cookie. This cookie is a byte array containing information that the server needs the next time it is called with a PagedResultsControl. In order to make it easy to store this cookie between searches, Spring LDAP provides the wrapper class PagedResultsCookie. Below is an example of how the paged search results functionality may be used: Paged results using <literal>PagedResultsRequestControl</literal> public PagedResult getAllPersons(PagedResultsCookie cookie) { PagedResultsRequestControl control = new PagedResultsRequestControl(PAGE_SIZE, cookie); SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); List persons = ldapTemplate.search("", "objectclass=person", searchControls, control); return new PagedResult(persons, control.getCookie()); } In the first call to this method, null will be supplied as the cookie parameter. On subsequent calls the client will need to supply the cookie from the last search (returned wrapped in the PagedResult) each time the method is called. When the actual cookie is null (i.e. pagedResult.getCookie().getCookie() returns null), the last batch has been returned from the search. libspring-ldap-java-1.3.1.RELEASE.orig/docs/docbkx/user-authentication.xml0000644000000000000000000002263211471060746023200 0ustar User Authentication using Spring LDAP Basic Authentication While the core functionality of the ContextSource is to provide DirContext instances for use by LdapTemplate, it may also be used for authenticating users against an LDAP server. The getContext(principal, credentials) method of ContextSource will do exactly that; construct a DirContext instance according to the ContextSource configuration, authenticating the context using the supplied principal and credentials. A custom authenticate method could look like this: public boolean authenticate(String userDn, String credentials) { DirContext ctx = null; try { ctx = contextSource.getContext(userDn, credentials); return true; } catch (Exception e) { // Context creation failed - authentication did not succeed logger.error("Login failed", e); return false; } finally { // It is imperative that the created DirContext instance is always closed LdapUtils.closeContext(ctx); } }The userDn supplied to the authenticate method needs to be the full DN of the user to authenticate (regardless of the base setting on the ContextSource). You will typically need to perform an LDAP search based on e.g. the user name to get this DN: private String getDnForUser(String uid) { Filter f = new EqualsFilter("uid", uid); List result = ldapTemplate.search(DistinguishedName.EMPTY_PATH, f.toString(), new AbstractContextMapper() { protected Object doMapFromContext(DirContextOperations ctx) { return ctx.getNameInNamespace(); } }); if(result.size() != 1) { throw new RuntimeException("User not found or not unique"); } return (String)result.get(0); }There are some drawbacks to this approach. The user is forced to concern herself with the DN of the user, she can only search for the user's uid, and the search always starts at the root of the tree (the empty path). A more flexible method would let the user specify the search base, the search filter, and the credentials. Spring LDAP 1.3.0 introduced new authenticate methods in LdapTemplate that provide this functionality: boolean authenticate(Name base, String filter, String password); boolean authenticate(String base, String filter, String password); Using one of these methods, authentication becomes as simple as this: Authenticating a user using Spring LDAP. boolean authenticated = ldapTemplate.authenticate("", "(uid=john.doe)", "secret"); Don't write your own custom authenticate methods. Use the ones provided in Spring LDAP 1.3.x. Performing Operations on the Authenticated Context Some authentication schemes and LDAP servers require some operation to be performed on the created DirContext instance for the actual authentication to occur. You should test and make sure how your server setup and authentication schemes behave; failure to do so might result in that users will be admitted into your system regardless of the DN/credentials supplied. This is a naïve implementation of an authenticate method where a hard-coded lookup operation is performed on the authenticated context: public boolean authenticate(String userDn, String credentials) { DirContext ctx = null; try { ctx = contextSource.getContext(userDn, credentials); // Take care here - if a base was specified on the ContextSource // that needs to be removed from the user DN for the lookup to succeed. ctx.lookup(userDn); return true; } catch (Exception e) { // Context creation failed - authentication did not succeed logger.error("Login failed", e); return false; } finally { // It is imperative that the created DirContext instance is always closed LdapUtils.closeContext(ctx); } }It would be better if the operation could be provided as an implementation of a callback interface, thus not limiting the operation to always be a lookup. Spring LDAP 1.3.0 introduced the callback interface AuthenticatedLdapEntryContextCallback and a few corresponding authenticate methods: boolean authenticate(Name base, String filter, String password, AuthenticatedLdapEntryContextCallback callback); boolean authenticate(String base, String filter, String password, AuthenticatedLdapEntryContextCallback callback); This opens up for any operation to be performed on the authenticated context: Performing an LDAP operation on the authenticated context using Spring LDAP. AuthenticatedLdapEntryContextCallback contextCallback = new AuthenticatedLdapEntryContextCallback() { public void executeWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) { try { ctx.lookup(ldapEntryIdentification.getRelativeDn()); } catch (NamingException e) { throw new RuntimeException("Failed to lookup " + ldapEntryIdentification.getRelativeDn(), e); } } }; ldapTemplate.authenticate("", "(uid=john.doe)", "secret", contextCallback)); Retrieving the Authentication Exception So far, the methods have only been able to tell the user whether or not the authentication succeeded. There has been no way of retrieving the actual exception. Spring LDAP 1.3.1 introduced the AuthenticationErrorCallback and a few more authenticate methods: boolean authenticate(Name base, String filter, String password, AuthenticationErrorCallback errorCallback); boolean authenticate(String base, String filter, String password, AuthenticationErrorCallback errorCallback); boolean authenticate(Name base, String filter, String password, AuthenticatedLdapEntryContextCallback callback, AuthenticationErrorCallback errorCallback); boolean authenticate(String base, String filter, String password, AuthenticatedLdapEntryContextCallback callback, AuthenticationErrorCallback errorCallback); A convenient collecting implementation of the error callback interface is also provided: public final class CollectingAuthenticationErrorCallback implements AuthenticationErrorCallback { private Exception error; public void execute(Exception e) { this.error = e; } public Exception getError() { return error; } }The code needed for authenticating a user and retrieving the authentication exception in case of an error boils down to this: Authenticating a user and retrieving the authentication exception. import org.springframework.ldap.core.support.CollectingAuthenticationErrorCallback; ... CollectingAuthenticationErrorCallback errorCallback = new CollectingAuthenticationErrorCallback(); boolean result = ldapTemplate.authenticate("", filter.toString(), "invalidpassword", errorCallback); if (!result) { Exception error = errorCallback.getError(); // error is likely of type org.springframework.ldap.AuthenticationException } Use Spring Security While the approach above may be sufficient for simple authentication scenarios, requirements in this area commonly expand rapidly. There is a multitude of aspects that apply, including authentication, authorization, web integration, user context management, etc. If you suspect that the requirements might expand beyond just simple authentication, you should definitely consider using Spring Security for your security purposes instead. It is a full-blown, mature security framework addressing the above aspects as well as several others. libspring-ldap-java-1.3.1.RELEASE.orig/samples/0002777000000000000000000000000011475315320015721 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/readme.txt0000644000000000000000000000101411475315306017711 0ustar Sample application demonstrating the very basics in Spring LDAP A basic data access class for manipulating a person entry is located at: org.springframework.ldap.samples.article.dao.PersonDaoImpl For comparison, a corresponding implementation using traditional JNDI programming is provided in: org.springframework.ldap.samples.article.dao.TraditionalPersonDaoImpl To verify the functionality, start the sample webapp using mvn jetty:run and navigate to http://localhost:8080/spring-ldap-person-article/showTree.do libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/0002777000000000000000000000000011475315320021006 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/readme.txt0000644000000000000000000000214211475315306023001 0ustar Uses Spring 2.0. Sample application demonstrating how to do the most basic stuff in Spring LDAP. A very simple dao implementation is provided in org.springframework.ldap.samples.article.dao.PersonDaoImpl It demonstrates some basic operations using Spring LDAP. For reference purposes, a corresponding implementation using ordinary Java LDAP/JNDI implementation is available in TraditionalPersonDaoImpl. How to use: ----------- The project is in a Maven build structure. Make sure you have installed the samples-utils artifact, as this will be needed for this project to work. 'mvn jetty:run' will start up a web server demonstrating the capabilities. The web application will be available under http://localhost:8080/spring-ldap-person-article-spring20/ 'mvn eclipse:eclipse' will construct an Eclipse project for you to use. Import that project into Eclipse using File/Import/Existing Project, and select this directory. 'mvn test' will run some integration tests that require the LDAP server to be running. It's recommended to run 'mvn jetty:run' from another terminal window before 'mvn test'. libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/pom.xml0000644000000000000000000001253211475313400022315 0ustar org.springframework.ldap spring-ldap-parent 1.3.1.CI-SNAPSHOT 4.0.0 spring-ldap-article-spring20 Spring LDAP Article Sample (Spring 2.0) war Example code that matches the article published on java.net on April 18, 2006. Uses Spring 2.0, rather than 2.5 maven-compiler-plugin 1.5 1.5 org.mortbay.jetty maven-jetty-plugin org.springframework.ldap spring-ldap-test log4j log4j 1.2.9 javax.servlet jstl 1.2 org.springframework.ldap spring-ldap-samples-utils org.springframework spring-test org.springframework spring-beans 2.0.8 org.springframework spring-core 2.0.8 org.springframework spring-dao 2.0.8 org.springframework spring-beans org.springframework spring-core org.springframework spring-jdbc 2.0.8 org.springframework spring-beans org.springframework spring-core org.springframework spring-context 2.0.8 org.springframework spring-beans org.springframework spring-core org.springframework spring-web 2.0.8 org.springframework spring-beans org.springframework spring-context org.springframework spring-core org.springframework spring-support 2.0.8 org.springframework spring-beans org.springframework spring-context org.springframework spring-core org.springframework spring-webmvc 2.0.8 org.springframework spring-web org.springframework spring-support org.springframework spring-beans org.springframework spring-context org.springframework spring-core javax.servlet servlet-api provided org.springframework spring-mock 2.0.8 test libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/0002755000000000000000000000000011475313400021566 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/0002755000000000000000000000000011475313400022545 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/0002755000000000000000000000000011475313400023466 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/0002755000000000000000000000000011475313400024255 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/0002755000000000000000000000000011475313400027475 5ustar ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/ldap/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/ld0002755000000000000000000000000011475313400030015 5ustar ././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/ldap/samples/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/ld0002755000000000000000000000000011475313400030015 5ustar ././@LongLink0000000000000000000000000000017000000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/ldap/samples/article/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/ld0002755000000000000000000000000011475313400030015 5ustar ././@LongLink0000000000000000000000000000017400000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/ldap/samples/article/dao/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/ld0002755000000000000000000000000011475313400030015 5ustar ././@LongLink0000000000000000000000000000023500000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/ldap/samples/article/dao/PersonDaoImplIntegrationTest.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/ld0000644000000000000000000000211611475313400030015 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import org.springframework.ldap.samples.article.dao.PersonDaoImpl; /** * Integration tests for the PersonDaoImpl class. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class PersonDaoImplIntegrationTest extends AbstractPersonDaoIntegrationTest { public void setPersonDao( PersonDaoImpl personDao) { this.personDao = personDao; } } ././@LongLink0000000000000000000000000000025000000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/ldap/samples/article/dao/TraditionalPersonDaoImplIntegrationTest.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/ld0000644000000000000000000000205111475313400030013 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; /** * Integration tests for the TraditionalPersonDaoImpl class. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class TraditionalPersonDaoImplIntegrationTest extends AbstractPersonDaoIntegrationTest { public void setPersonDao( TraditionalPersonDaoImpl personDao) { this.personDao = personDao; } } ././@LongLink0000000000000000000000000000024100000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/ldap/samples/article/dao/AbstractPersonDaoIntegrationTest.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/java/org/springframework/ld0000644000000000000000000001004011475313400030010 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import java.util.List; import org.springframework.ldap.NameNotFoundException; import org.springframework.ldap.samples.article.dao.PersonDao; import org.springframework.ldap.samples.article.domain.Person; import org.springframework.test.AbstractDependencyInjectionSpringContextTests; /** * Abstract base class for PersonDao integration tests. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public abstract class AbstractPersonDaoIntegrationTest extends AbstractDependencyInjectionSpringContextTests { protected Person person; protected PersonDao personDao; protected String[] getConfigLocations() { return new String[] { "config/testContext.xml" }; } protected void onSetUp() throws Exception { super.onSetUp(); person = new Person(); person.setCountry("Sweden"); person.setCompany("company1"); person.setFullName("Some Person"); person.setLastName("Person"); person .setDescription("Sweden, Company1, Some Person"); person.setPhone("+46 555-123456"); } protected void onTearDown() throws Exception { super.onTearDown(); person = null; personDao = null; } /** * Having a single test method test create, update and delete is not exactly * the ideal way of testing, since they depend on each other. A better way * would be to separate the tests and load a test fixture before each * operation, in order to guarantee the expected state every time. See the * ldaptemplate-person sample for the correct way to do this. */ public void testCreateUpdateDelete() { try { person.setFullName("Another Person"); personDao.create(person); personDao.findByPrimaryKey( "Sweden", "company1", "Another Person"); // if we got here, create succeeded person .setDescription("Another description"); personDao.update(person); Person result = personDao .findByPrimaryKey( "Sweden", "company1", "Another Person"); assertEquals( "Another description", result .getDescription()); } finally { personDao.delete(person); try { personDao.findByPrimaryKey( "Sweden", "company1", "Another Person"); fail("NameNotFoundException (when using Spring LDAP) or RuntimeException (when using traditional) expected"); } catch (NameNotFoundException expected) { // expected } catch (RuntimeException expected) { // expected } } } public void testGetAllPersonNames() { List result = personDao.getAllPersonNames(); assertEquals(2, result.size()); String first = (String) result.get(0); assertEquals("Some Person", first); } public void testFindAll() { List result = personDao.findAll(); assertEquals(2, result.size()); Person first = (Person) result.get(0); assertEquals("Some Person", first .getFullName()); } public void testFindByPrimaryKey() { Person result = personDao.findByPrimaryKey( "Sweden", "company1", "Some Person"); assertEquals(person, result); } } libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/resources/0002755000000000000000000000000011475313400024557 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/resources/setup_data.ldif0000644000000000000000000000156711475313400027557 0ustar dn: c=Sweden,dc=jayway,dc=se objectclass: top objectclass: country c: Sweden description: The country of Sweden dn: ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: organizationalUnit ou: company1 description: First company in Sweden dn: cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person userPassword: password cn: Some Person sn: Person description: Sweden, Company1, Some Person telephoneNumber: +46 555-123456 dn: cn=Some Person2,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person2 userPassword: password cn: Some Person2 sn: Person2 description: Sweden, Company1, Some Person2 telephoneNumber: +46 555-654321 libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/resources/config/0002755000000000000000000000000011475313400026024 5ustar ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/resources/config/testContext.xmllibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/resources/config/testContex0000644000000000000000000000310511475313400030104 0ustar ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/resources/config/ldap.propertieslibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/test/resources/config/ldap.prope0000644000000000000000000000013711475313400030012 0ustar urls=ldap://127.0.0.1:3900 userDn=uid=admin,ou=system password=secret base=dc=jayway,dc=se libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/0002755000000000000000000000000011475313400022512 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/0002755000000000000000000000000011475313400023433 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/overview.html0000644000000000000000000000013311475313400026162 0ustar This document is the API specification for the Spring LDAP Article sample. libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/0002755000000000000000000000000011475313400024222 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/0002755000000000000000000000000011475313400027442 5ustar ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ldap/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400027762 5ustar ././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ldap/samples/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400027762 5ustar ././@LongLink0000000000000000000000000000017000000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ldap/samples/article/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400027762 5ustar ././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ldap/samples/article/domain/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400027762 5ustar ././@LongLink0000000000000000000000000000021200000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ldap/samples/article/domain/Person.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ld0000644000000000000000000000474011475313400027767 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.domain; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; /** * Simple class representing a single person. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class Person { private String fullName; private String lastName; private String description; private String country; private String company; private String phone; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals( this, obj); } public int hashCode() { return HashCodeBuilder .reflectionHashCode(this); } public String toString() { return ToStringBuilder.reflectionToString( this, ToStringStyle.MULTI_LINE_STYLE); } } ././@LongLink0000000000000000000000000000017400000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ldap/samples/article/web/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400027762 5ustar ././@LongLink0000000000000000000000000000022200000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ldap/samples/article/web/DefaultController.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ld0000644000000000000000000001044411475313400027765 0ustar package org.springframework.ldap.samples.article.web; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.samples.article.dao.PersonDao; import org.springframework.ldap.samples.article.domain.Person; import org.springframework.ldap.samples.utils.HtmlRowLdapTreeVisitor; import org.springframework.ldap.samples.utils.LdapTree; import org.springframework.ldap.samples.utils.LdapTreeBuilder; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.multiaction.MultiActionController; /** * Default controller. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class DefaultController extends MultiActionController { private LdapTreeBuilder ldapTreeBuilder; public void setLdapTreeBuilder(LdapTreeBuilder ldapTreeBuilder) { this.ldapTreeBuilder = ldapTreeBuilder; } public void setPersonDao(PersonDao personDao) { this.personDao = personDao; } private PersonDao personDao; public ModelAndView welcomeHandler(HttpServletRequest request, HttpServletResponse response) { return new ModelAndView("welcome"); } public ModelAndView showTree(HttpServletRequest request, HttpServletResponse response) { LdapTree ldapTree = ldapTreeBuilder.getLdapTree(DistinguishedName.EMPTY_PATH); HtmlRowLdapTreeVisitor visitor = new PersonLinkHtmlRowLdapTreeVisitor(); ldapTree.traverse(visitor); return new ModelAndView("showTree", "rows", visitor.getRows()); } public ModelAndView addPerson(HttpServletRequest request, HttpServletResponse response) { Person person = getPerson(); personDao.create(person); return showTree(request, response); } public ModelAndView updatePhoneNumber(HttpServletRequest request, HttpServletResponse response) { Person person = personDao.findByPrimaryKey("Sweden", "company1", "John Doe"); person.setPhone(StringUtils.join(new String[] { person.getPhone(), "0" })); personDao.update(person); return showTree(request, response); } public ModelAndView removePerson(HttpServletRequest request, HttpServletResponse response) { Person person = getPerson(); personDao.delete(person); return showTree(request, response); } public ModelAndView showPerson(HttpServletRequest request, HttpServletResponse response, Person query) { String country = query.getCountry(); String company = query.getCompany(); String fullName = query.getFullName(); Person person = personDao.findByPrimaryKey(country, company, fullName); return new ModelAndView("showPerson", "person", person); } private Person getPerson() { Person person = new Person(); person.setFullName("John Doe"); person.setLastName("Doe"); person.setCompany("company1"); person.setCountry("Sweden"); person.setDescription("Test user"); return person; } /** * Generates appropriate links for person leaves in the tree. * * @author Mattias Hellborg Arthursson */ private static final class PersonLinkHtmlRowLdapTreeVisitor extends HtmlRowLdapTreeVisitor { @Override protected String getLinkForNode(DirContextOperations node) { String[] objectClassValues = node.getStringAttributes("objectClass"); if (containsValue(objectClassValues, "person")) { DistinguishedName distinguishedName = (DistinguishedName) node.getDn(); String country = encodeValue(distinguishedName.getValue("c")); String company = encodeValue(distinguishedName.getValue("ou")); String fullName = encodeValue(distinguishedName.getValue("cn")); return "showPerson.do?country=" + country + "&company=" + company + "&fullName=" + fullName; } else { return super.getLinkForNode(node); } } private String encodeValue(String value) { try { return URLEncoder.encode(value, "UTF8"); } catch (UnsupportedEncodingException e) { // Not supposed to happen throw new RuntimeException("Unexpected encoding exception", e); } } private boolean containsValue(String[] values, String value) { for (String oneValue : values) { if (StringUtils.equals(oneValue, value)) { return true; } } return false; } } } ././@LongLink0000000000000000000000000000017400000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ldap/samples/article/dao/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400027762 5ustar ././@LongLink0000000000000000000000000000021200000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ldap/samples/article/dao/PersonDao.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ld0000644000000000000000000000225711475313400027770 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import java.util.List; import org.springframework.ldap.samples.article.domain.Person; /** * Data Access Object interface for the Person entity. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public interface PersonDao { void create(Person person); void update(Person person); void delete(Person person); List getAllPersonNames(); List findAll(); Person findByPrimaryKey(String country, String company, String fullname); } ././@LongLink0000000000000000000000000000023100000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ldap/samples/article/dao/TraditionalPersonDaoImpl.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ld0000644000000000000000000002516411475313400027772 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import javax.naming.Context; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import org.apache.commons.lang.StringUtils; import org.springframework.ldap.samples.article.domain.Person; /** * Traditional implementation of PersonDao. This implementation uses the basic * JNDI interfaces and classes {@link DirContext}, {@link Attributes}, * {@link Attribute}, and {@link NamingEnumeration}. The purpose is to * contrast this implementation with that of {@link PersonDaoImpl}. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class TraditionalPersonDaoImpl implements PersonDao { private String userName; private String password; private String url; private String base; /* * @see PersonDao#create(Person) */ public void create(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { Attributes attrs = getAttributesToBind(person); ctx.bind(dn, null, attrs); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#update(Person) */ public void update(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { ctx .rebind( dn, null, getAttributesToBind(person)); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#delete(Person) */ public void delete(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { ctx.unbind(dn); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#getAllPersonNames() */ public List getAllPersonNames() { DirContext ctx = createAnonymousContext(); LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls .setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search( "", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results .next(); Attributes attributes = searchResult .getAttributes(); Attribute attr = attributes.get("cn"); String cn = (String) attr.get(); list.add(cn); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } /* * @see PersonDao#findAll() */ public List findAll() { DirContext ctx = createAnonymousContext(); LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls .setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search( "", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results .next(); String dn = searchResult.getName(); Attributes attributes = searchResult .getAttributes(); list.add(mapToPerson(dn, attributes)); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } /* * @see PersonDao#findByPrimaryKey(java.lang.String, java.lang.String, * java.lang.String) */ public Person findByPrimaryKey(String country, String company, String fullname) { DirContext ctx = createAnonymousContext(); String dn = buildDn( country, company, fullname); try { Attributes attributes = ctx .getAttributes(dn); return mapToPerson(dn, attributes); } catch (NameNotFoundException e) { throw new RuntimeException( "Did not find entry with primary key '" + dn + "'", e); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } private String buildDn(Person person) { return buildDn(person.getCountry(), person .getCompany(), person.getFullName()); } private String buildDn(String country, String company, String fullname) { StringBuffer sb = new StringBuffer(); sb.append("cn="); sb.append(fullname); sb.append(", "); sb.append("ou="); sb.append(company); sb.append(", "); sb.append("c="); sb.append(country); String dn = sb.toString(); return dn; } private DirContext createContext(Hashtable env) { env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); String tempUrl = createUrl(); env.put(Context.PROVIDER_URL, tempUrl); DirContext ctx; try { ctx = new InitialDirContext(env); } catch (NamingException e) { throw new RuntimeException(e); } return ctx; } private DirContext createAnonymousContext() { Hashtable env = new Hashtable(); return createContext(env); } private DirContext createAuthenticatedContext() { Hashtable env = new Hashtable(); env.put( Context.SECURITY_AUTHENTICATION, "simple"); env.put( Context.SECURITY_PRINCIPAL, userName); env.put( Context.SECURITY_CREDENTIALS, password); return createContext(env); } private Attributes getAttributesToBind( Person person) { Attributes attrs = new BasicAttributes(); BasicAttribute ocattr = new BasicAttribute( "objectclass"); ocattr.add("top"); ocattr.add("person"); attrs.put(ocattr); attrs.put("cn", person.getFullName()); attrs.put("sn", person.getLastName()); attrs.put("description", person .getDescription()); attrs.put("telephoneNumber", person .getPhone()); return attrs; } private Person mapToPerson(String dn, Attributes attributes) throws NamingException { Person person = new Person(); person.setFullName((String) attributes.get( "cn").get()); person.setLastName((String) attributes.get( "sn").get()); person.setDescription((String) attributes .get("description").get()); person.setPhone((String) attributes.get( "telephoneNumber").get()); // Remove any trailing spaces after comma String cleanedDn = dn .replaceAll(", *", ","); String countryMarker = ",c="; int countryIndex = cleanedDn .lastIndexOf(countryMarker); String companyMarker = ",ou="; int companyIndex = cleanedDn .lastIndexOf(companyMarker); String country = cleanedDn .substring(countryIndex + countryMarker.length()); person.setCountry(country); String company = cleanedDn.substring( companyIndex + companyMarker.length(), countryIndex); person.setCompany(company); return person; } private String createUrl() { String tempUrl = url; if (!tempUrl.endsWith("/")) { tempUrl += "/"; } if (StringUtils.isNotEmpty(base)) { tempUrl += base; } return tempUrl; } public void setUrl(String url) { this.url = url; } public void setBase(String base) { this.base = base; } public void setPassword(String credentials) { this.password = credentials; } public void setUserDn(String principal) { this.userName = principal; } } ././@LongLink0000000000000000000000000000021600000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ldap/samples/article/dao/PersonDaoImpl.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/java/org/springframework/ld0000644000000000000000000001352611475313400027771 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import java.util.List; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.directory.Attributes; import org.springframework.ldap.core.AttributesMapper; import org.springframework.ldap.core.ContextMapper; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.filter.EqualsFilter; import org.springframework.ldap.samples.article.domain.Person; /** * Default implementation of PersonDao. This implementation uses * DirContextAdapter for managing attribute values. It has been specified in the * Spring Context that the DirObjectFactory should be used when creating objects * from contexts, which defaults to creating DirContextAdapter objects. This * means that we can use a ContextMapper to map from the found contexts to our * domain objects. This is especially useful since we in this case have * properties in our domain objects that depend on parts of the DN. * * We could have worked with Attributes and an AttributesMapper implementation * instead, but working with Attributes is a bore and also, working with * AttributesMapper objects (or, indeed Attributes) does not give us access to * the distinguished name. However, we do use it in one method that only needs a * single attribute: {@link #getAllPersonNames()}. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; /* * @see PersonDao#create(Person) */ public void create(Person person) { Name dn = buildDn(person); DirContextAdapter context = new DirContextAdapter(dn); mapToContext(person, context); ldapTemplate.bind(dn, context, null); } /* * @see PersonDao#update(Person) */ public void update(Person person) { Name dn = buildDn(person); DirContextAdapter context = (DirContextAdapter) ldapTemplate.lookup(dn); mapToContext(person, context); ldapTemplate.modifyAttributes(dn, context.getModificationItems()); } /* * @see PersonDao#delete(Person) */ public void delete(Person person) { ldapTemplate.unbind(buildDn(person)); } /* * @see PersonDao#getAllPersonNames() */ public List getAllPersonNames() { EqualsFilter filter = new EqualsFilter("objectclass", "person"); return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), new AttributesMapper() { public Object mapFromAttributes(Attributes attrs) throws NamingException { return attrs.get("cn").get(); } }); } /* * @see PersonDao#findAll() */ public List findAll() { EqualsFilter filter = new EqualsFilter("objectclass", "person"); return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), getContextMapper()); } /* * @see PersonDao#findByPrimaryKey(java.lang.String, java.lang.String, * java.lang.String) */ public Person findByPrimaryKey(String country, String company, String fullname) { DistinguishedName dn = buildDn(country, company, fullname); return (Person) ldapTemplate.lookup(dn, getContextMapper()); } private ContextMapper getContextMapper() { return new PersonContextMapper(); } private DistinguishedName buildDn(Person person) { return buildDn(person.getCountry(), person.getCompany(), person.getFullName()); } private DistinguishedName buildDn(String country, String company, String fullname) { DistinguishedName dn = new DistinguishedName(); dn.add("c", country); dn.add("ou", company); dn.add("cn", fullname); return dn; } private void mapToContext(Person person, DirContextAdapter context) { context.setAttributeValues("objectclass", new String[] { "top", "person" }); context.setAttributeValue("cn", person.getFullName()); context.setAttributeValue("sn", person.getLastName()); context.setAttributeValue("description", person.getDescription()); context.setAttributeValue("telephoneNumber", person.getPhone()); } /** * Maps from DirContextAdapter to Person objects. A DN for a person will be * of the form cn=[fullname],ou=[company],c=[country], so * the values of these attributes must be extracted from the DN. For this, * we use the DistinguishedName. * *Mattias Hellborg Arthurssonellborg Arthursson * @author Ulrik Sandberg */ private static class PersonContextMapper implements ContextMapper { public Object mapFromContext(Object ctx) { DirContextAdapter context = (DirContextAdapter) ctx; DistinguishedName dn = new DistinguishedName(context.getDn()); Person person = new Person(); person.setCountry(dn.getLdapRdn(0).getComponent().getValue()); person.setCompany(dn.getLdapRdn(1).getComponent().getValue()); person.setFullName(context.getStringAttribute("cn")); person.setLastName(context.getStringAttribute("sn")); person.setDescription(context.getStringAttribute("description")); person.setPhone(context.getStringAttribute("telephoneNumber")); return person; } } public void setLdapTemplate(LdapTemplate ldapTemplate) { this.ldapTemplate = ldapTemplate; } } libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/0002755000000000000000000000000011475313400023770 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/0002755000000000000000000000000011475313400025017 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/jsp/0002755000000000000000000000000011475313400025613 5ustar ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/jsp/showPerson.jsplibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/jsp/showPers0000644000000000000000000000053411475313400027350 0ustar <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> Back

Full name: ${person.fullName}
LastName: ${person.lastName}
Description: ${person.description}
Country: ${person.country}
Company: ${person.company}
Phone: ${person.phone}

././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/jsp/showTree.jsplibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/jsp/showTree0000644000000000000000000000130311475313400027331 0ustar <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

Operations

Clicking a link below performs the described operation which will be reflected in the LDAP tree below

Add new test person 'John Doe' (only works once)
Add a '0' to the phone number of test person (only works if the person has been created)
Remove test person

Tree contents

Click a person row to see the attribute values (country and company rows do not have additional info)

${row}

././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/setup_data.ldiflibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/setup_data.l0000644000000000000000000000156711475313400027334 0ustar dn: c=Sweden,dc=jayway,dc=se objectclass: top objectclass: country c: Sweden description: The country of Sweden dn: ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: organizationalUnit ou: company1 description: First company in Sweden dn: cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person userPassword: password cn: Some Person sn: Person description: Sweden, Company1, Some Person telephoneNumber: +46 555-123456 dn: cn=Some Person2,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person2 userPassword: password cn: Some Person2 sn: Person2 description: Sweden, Company1, Some Person2 telephoneNumber: +46 555-654321 ././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/applicationContext.xmllibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/applicationC0000644000000000000000000000250311475313400027346 0ustar ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/basic-servlet.xmllibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/basic-servle0000644000000000000000000000300411475313400027314 0ustar /welcome.do=welcome /showTree.do=showTree /addPerson.do=addPerson /updatePhoneNumber.do=updatePhoneNumber /removePerson.do=removePerson /showPerson.do=showPerson /*.do=defaultController ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/ldap.propertieslibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/ldap.propert0000644000000000000000000000013711475313400027353 0ustar urls=ldap://127.0.0.1:3900 userDn=uid=admin,ou=system password=secret base=dc=jayway,dc=se libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/WEB-INF/web.xml0000644000000000000000000000174111475313400026317 0ustar Spring LDAP Basic Example org.springframework.web.context.ContextLoaderListener basic org.springframework.web.servlet.DispatcherServlet contextConfigLocation /WEB-INF/basic-servlet.xml 1 basic *.do index.htm libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/webapp/index.htm0000644000000000000000000000012711475313400025607 0ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/resources/0002755000000000000000000000000011475313400024524 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring20/src/main/resources/log4j.properties0000644000000000000000000000040511475313400027656 0ustar log4j.rootCategory=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n log4j.logger.org.apache.directory=ERRORlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/0002777000000000000000000000000011475315320017030 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/readme.txt0000644000000000000000000000011711475315306021023 0ustar Demo applications for demonstrating conversion of legacy JNDI to Spring LDAP. libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/pom.xml0000644000000000000000000000220311475313400020331 0ustar org.springframework.ldap spring-ldap-parent 1.3.1.CI-SNAPSHOT 4.0.0 spring-ldap-demos pom Spring LDAP Demos demo demo-tiger spring-release Spring Release Repository http://maven.springframework.org/release log4j log4j runtime libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/0002777000000000000000000000000011475315320017754 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/readme.txt0000644000000000000000000000163211475315306021752 0ustar Demo application to be used for demonstrating how to convert a legacy JNDI-based dao implementation written in Java 1.4 to use Spring LDAP, focussing on the Java5 support in Spring LDAP. For reference purposes, a corresponding implementation using ordinary Java LDAP/JNDI implementation is available in TraditionalPersonDaoImpl. How to use: ----------- 'mvn test' will start up an LDAP server before running the integration tests that verify the dao implementation. 'mvn eclipse:eclipse' will construct an Eclipse project for you to use. Import that project into Eclipse using File/Import/Existing Project, and select this directory. You can start converting the org.springframework.ldap.demo.dao.PersonDaoImpl class. The original traditional implementation, as well as a "solution", is available in the org.springframework.ldap.demo.solution package. Run the tests after you have converted a method. libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/pom.xml0000644000000000000000000000307611475313400021266 0ustar org.springframework.ldap spring-ldap-parent 1.3.1.CI-SNAPSHOT 4.0.0 org.springframework.ldap spring-ldap-demo Spring LDAP Demo jar Example code for demonstrating the process of refactoring from plain JNDI to Spring LDAP (Java 1.4). maven-compiler-plugin 1.4 1.4 maven-eclipse-plugin org.springframework.ldap spring-ldap-test org.springframework.ldap spring-ldap-core org.springframework spring-context org.springframework spring-test test libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/0002755000000000000000000000000011475313400020534 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/0002755000000000000000000000000011475313400021513 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/java/0002755000000000000000000000000011475313400022434 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/java/org/0002755000000000000000000000000011475313400023223 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/java/org/springframework/0002755000000000000000000000000011475313400026443 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/java/org/springframework/ldap/0002755000000000000000000000000011475313400027363 5ustar ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/java/org/springframework/ldap/demo/libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/java/org/springframework/ldap/dem0002755000000000000000000000000011475313400030051 5ustar ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/java/org/springframework/ldap/demo/dao/libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/java/org/springframework/ldap/dem0002755000000000000000000000000011475313400030051 5ustar ././@LongLink0000000000000000000000000000021000000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/java/org/springframework/ldap/demo/dao/PersonDaoIntegrationTest.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/java/org/springframework/ldap/dem0000644000000000000000000000700111475313400030047 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.demo.dao; import java.util.List; import org.springframework.ldap.NameNotFoundException; import org.springframework.ldap.demo.domain.Person; import org.springframework.test.AbstractDependencyInjectionSpringContextTests; /** * Integration tests for the PersonDao class. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class PersonDaoIntegrationTest extends AbstractDependencyInjectionSpringContextTests { private Person person; private PersonDao personDao; public void setPersonDao(PersonDao personDao) { this.personDao = personDao; } protected String[] getConfigLocations() { return new String[] { "/config/testContext.xml" }; } protected void onSetUp() throws Exception { super.onSetUp(); person = new Person(); person.setCountry("Sweden"); person.setCompany("company1"); person.setFullName("Some Person"); person.setLastName("Person"); person.setDescription("Sweden, Company1, Some Person"); person.setPhone("+46 555-123456"); } protected void onTearDown() throws Exception { super.onTearDown(); person = null; personDao = null; } /** * Having a single test method test create, update and delete is not exactly * the ideal way of testing, since they depend on each other. A better way * would be to separate the tests and load a test fixture before each * operation, in order to guarantee the expected state every time. */ public void testCreateUpdateDelete() { try { person.setFullName("Another Person"); personDao.create(person); personDao.findByPrimaryKey("Sweden", "company1", "Another Person"); // if we got here, create succeeded person.setDescription("Another description"); personDao.update(person); Person result = personDao.findByPrimaryKey("Sweden", "company1", "Another Person"); assertEquals("Another description", result.getDescription()); } finally { personDao.delete(person); try { personDao.findByPrimaryKey("Sweden", "company1", "Another Person"); fail("NameNotFoundException (when using Spring LDAP) or RuntimeException (when using traditional) expected"); } catch (NameNotFoundException expected) { // expected } catch (RuntimeException expected) { // expected } } } public void testGetAllPersonNames() { List result = personDao.getAllPersonNames(); assertEquals(2, result.size()); String first = (String) result.get(0); assertEquals("Some Person", first); } public void testFindAll() { List result = personDao.findAll(); assertEquals(2, result.size()); Person first = (Person) result.get(0); assertEquals("Some Person", first.getFullName()); } public void testFindByPrimaryKey() { Person result = personDao.findByPrimaryKey("Sweden", "company1", "Some Person"); assertEquals(person, result); } } libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/resources/0002755000000000000000000000000011475313400023525 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/resources/log4j.properties0000644000000000000000000000040511475313400026657 0ustar log4j.rootCategory=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n log4j.logger.org.apache.directory=ERRORlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/resources/config/0002755000000000000000000000000011475313400024772 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/resources/config/setup_data.ldif0000644000000000000000000000156711475313400027772 0ustar dn: c=Sweden,dc=jayway,dc=se objectclass: top objectclass: country c: Sweden description: The country of Sweden dn: ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: organizationalUnit ou: company1 description: First company in Sweden dn: cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person userPassword: password cn: Some Person sn: Person description: Sweden, Company1, Some Person telephoneNumber: +46 555-123456 dn: cn=Some Person2,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person2 userPassword: password cn: Some Person2 sn: Person2 description: Sweden, Company1, Some Person2 telephoneNumber: +46 555-654321 libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/resources/config/testContext.xml0000644000000000000000000000256511475313400030046 0ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/test/resources/config/ldap.properties0000644000000000000000000000013711475313400030027 0ustar urls=ldap://127.0.0.1:3900 userDn=uid=admin,ou=system password=secret base=dc=jayway,dc=se libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/0002755000000000000000000000000011475313400021460 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/0002755000000000000000000000000011475313400022401 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/overview.html0000644000000000000000000000013311475313400025130 0ustar This document is the API specification for the Spring LDAP Article sample. libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/0002755000000000000000000000000011475313400023170 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/0002755000000000000000000000000011475313400026410 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/0002755000000000000000000000000011475313400027330 5ustar ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/demo/libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/dem0002755000000000000000000000000011475313400030016 5ustar ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/demo/domain/libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/dem0002755000000000000000000000000011475313400030016 5ustar ././@LongLink0000000000000000000000000000017100000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/demo/domain/Person.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/dem0000644000000000000000000000472511475313400030026 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.demo.domain; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; /** * Simple class representing a single person. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class Person { private String fullName; private String lastName; private String description; private String country; private String company; private String phone; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals( this, obj); } public int hashCode() { return HashCodeBuilder .reflectionHashCode(this); } public String toString() { return ToStringBuilder.reflectionToString( this, ToStringStyle.MULTI_LINE_STYLE); } } ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/demo/dao/libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/dem0002755000000000000000000000000011475313400030016 5ustar ././@LongLink0000000000000000000000000000017100000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/demo/dao/PersonDao.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/dem0000644000000000000000000000220411475313400030014 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.demo.dao; import java.util.List; import org.springframework.ldap.demo.domain.Person; /** * Data Access Object interface for the Person entity. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public interface PersonDao { void create(Person person); void update(Person person); void delete(Person person); List getAllPersonNames(); List findAll(); Person findByPrimaryKey(String country, String company, String fullname); } ././@LongLink0000000000000000000000000000017500000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/demo/dao/PersonDaoImpl.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/dem0000644000000000000000000002120411475313400030015 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.demo.dao; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import javax.naming.Context; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import org.apache.commons.lang.StringUtils; import org.springframework.ldap.demo.domain.Person; /** * Traditional implementation of PersonDao. This implementation uses the basic * JNDI interfaces and classes {@link DirContext}, {@link Attributes}, * {@link Attribute}, and {@link NamingEnumeration}. The purpose is to contrast * this implementation with an implementation based on Spring LDAP. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class PersonDaoImpl implements PersonDao { private String userName; private String password; private String url; private String base; /* * @see PersonDao#create(Person) */ public void create(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { Attributes attrs = getAttributesToBind(person); ctx.bind(dn, null, attrs); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#update(Person) */ public void update(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { ctx.rebind(dn, null, getAttributesToBind(person)); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#delete(Person) */ public void delete(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { ctx.unbind(dn); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#getAllPersonNames() */ public List getAllPersonNames() { DirContext ctx = createAnonymousContext(); LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls.setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search("", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results.next(); Attributes attributes = searchResult.getAttributes(); Attribute attr = attributes.get("cn"); String cn = (String) attr.get(); list.add(cn); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } /* * @see PersonDao#findAll() */ public List findAll() { DirContext ctx = createAnonymousContext(); LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls.setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search("", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results.next(); String dn = searchResult.getName(); Attributes attributes = searchResult.getAttributes(); list.add(mapToPerson(dn, attributes)); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } /* * @see PersonDao#findByPrimaryKey(java.lang.String, java.lang.String, * java.lang.String) */ public Person findByPrimaryKey(String country, String company, String fullname) { DirContext ctx = createAnonymousContext(); String dn = buildDn(country, company, fullname); try { Attributes attributes = ctx.getAttributes(dn); return mapToPerson(dn, attributes); } catch (NameNotFoundException e) { throw new RuntimeException("Did not find entry with primary key '" + dn + "'", e); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } private String buildDn(Person person) { return buildDn(person.getCountry(), person.getCompany(), person .getFullName()); } private String buildDn(String country, String company, String fullname) { StringBuffer sb = new StringBuffer(); sb.append("cn="); sb.append(fullname); sb.append(", "); sb.append("ou="); sb.append(company); sb.append(", "); sb.append("c="); sb.append(country); String dn = sb.toString(); return dn; } private DirContext createContext(Hashtable env) { env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); String tempUrl = createUrl(); env.put(Context.PROVIDER_URL, tempUrl); DirContext ctx; try { ctx = new InitialDirContext(env); } catch (NamingException e) { throw new RuntimeException(e); } return ctx; } private DirContext createAnonymousContext() { Hashtable hashtable = new Hashtable(); Hashtable env = hashtable; return createContext(env); } private DirContext createAuthenticatedContext() { Hashtable env = new Hashtable(); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, userName); env.put(Context.SECURITY_CREDENTIALS, password); return createContext(env); } private Attributes getAttributesToBind(Person person) { Attributes attrs = new BasicAttributes(); BasicAttribute ocattr = new BasicAttribute("objectclass"); ocattr.add("top"); ocattr.add("person"); attrs.put(ocattr); attrs.put("cn", person.getFullName()); attrs.put("sn", person.getLastName()); attrs.put("description", person.getDescription()); attrs.put("telephoneNumber", person.getPhone()); return attrs; } private Person mapToPerson(String dn, Attributes attributes) throws NamingException { Person person = new Person(); person.setFullName((String) attributes.get("cn").get()); person.setLastName((String) attributes.get("sn").get()); person.setDescription((String) attributes.get("description").get()); person.setPhone((String) attributes.get("telephoneNumber").get()); // Remove any trailing spaces after comma String cleanedDn = dn.replaceAll(", *", ","); String countryMarker = ",c="; int countryIndex = cleanedDn.lastIndexOf(countryMarker); String companyMarker = ",ou="; int companyIndex = cleanedDn.lastIndexOf(companyMarker); String country = cleanedDn.substring(countryIndex + countryMarker.length()); person.setCountry(country); String company = cleanedDn.substring(companyIndex + companyMarker.length(), countryIndex); person.setCompany(company); return person; } private String createUrl() { String tempUrl = url; if (!tempUrl.endsWith("/")) { tempUrl += "/"; } if (StringUtils.isNotEmpty(base)) { tempUrl += base; } return tempUrl; } public void setUrl(String url) { this.url = url; } public void setBase(String base) { this.base = base; } public void setPassword(String credentials) { this.password = credentials; } public void setUserDn(String principal) { this.userName = principal; } } ././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/demo/solution/libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/dem0002755000000000000000000000000011475313400030016 5ustar ././@LongLink0000000000000000000000000000021500000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/demo/solution/TraditionalPersonDaoImpl.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/dem0000644000000000000000000002204011475313400030014 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.demo.solution; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import javax.naming.Context; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import org.apache.commons.lang.StringUtils; import org.springframework.ldap.demo.dao.PersonDao; import org.springframework.ldap.demo.domain.Person; /** * Traditional implementation of PersonDao. This implementation uses the basic * JNDI interfaces and classes {@link DirContext}, {@link Attributes}, * {@link Attribute}, and {@link NamingEnumeration}. The purpose is to contrast * this implementation with an implementation based on Spring LDAP. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class TraditionalPersonDaoImpl implements PersonDao { private String userName; private String password; private String url; private String base; /* * @see PersonDao#create(Person) */ public void create(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { Attributes attrs = getAttributesToBind(person); ctx.bind(dn, null, attrs); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#update(Person) */ public void update(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { ctx.rebind(dn, null, getAttributesToBind(person)); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#delete(Person) */ public void delete(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { ctx.unbind(dn); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#getAllPersonNames() */ public List getAllPersonNames() { DirContext ctx = createAnonymousContext(); LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls.setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search("", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results.next(); Attributes attributes = searchResult.getAttributes(); Attribute attr = attributes.get("cn"); String cn = (String) attr.get(); list.add(cn); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } /* * @see PersonDao#findAll() */ public List findAll() { DirContext ctx = createAnonymousContext(); LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls.setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search("", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results.next(); String dn = searchResult.getName(); Attributes attributes = searchResult.getAttributes(); list.add(mapToPerson(dn, attributes)); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } /* * @see PersonDao#findByPrimaryKey(java.lang.String, java.lang.String, * java.lang.String) */ public Person findByPrimaryKey(String country, String company, String fullname) { DirContext ctx = createAnonymousContext(); String dn = buildDn(country, company, fullname); try { Attributes attributes = ctx.getAttributes(dn); return mapToPerson(dn, attributes); } catch (NameNotFoundException e) { throw new RuntimeException("Did not find entry with primary key '" + dn + "'", e); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } private String buildDn(Person person) { return buildDn(person.getCountry(), person.getCompany(), person .getFullName()); } private String buildDn(String country, String company, String fullname) { StringBuffer sb = new StringBuffer(); sb.append("cn="); sb.append(fullname); sb.append(", "); sb.append("ou="); sb.append(company); sb.append(", "); sb.append("c="); sb.append(country); String dn = sb.toString(); return dn; } private DirContext createContext(Hashtable env) { env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); String tempUrl = createUrl(); env.put(Context.PROVIDER_URL, tempUrl); DirContext ctx; try { ctx = new InitialDirContext(env); } catch (NamingException e) { throw new RuntimeException(e); } return ctx; } private DirContext createAnonymousContext() { Hashtable hashtable = new Hashtable(); Hashtable env = hashtable; return createContext(env); } private DirContext createAuthenticatedContext() { Hashtable env = new Hashtable(); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, userName); env.put(Context.SECURITY_CREDENTIALS, password); return createContext(env); } private Attributes getAttributesToBind(Person person) { Attributes attrs = new BasicAttributes(); BasicAttribute ocattr = new BasicAttribute("objectclass"); ocattr.add("top"); ocattr.add("person"); attrs.put(ocattr); attrs.put("cn", person.getFullName()); attrs.put("sn", person.getLastName()); attrs.put("description", person.getDescription()); attrs.put("telephoneNumber", person.getPhone()); return attrs; } private Person mapToPerson(String dn, Attributes attributes) throws NamingException { Person person = new Person(); person.setFullName((String) attributes.get("cn").get()); person.setLastName((String) attributes.get("sn").get()); person.setDescription((String) attributes.get("description").get()); person.setPhone((String) attributes.get("telephoneNumber").get()); // Remove any trailing spaces after comma String cleanedDn = dn.replaceAll(", *", ","); String countryMarker = ",c="; int countryIndex = cleanedDn.lastIndexOf(countryMarker); String companyMarker = ",ou="; int companyIndex = cleanedDn.lastIndexOf(companyMarker); String country = cleanedDn.substring(countryIndex + countryMarker.length()); person.setCountry(country); String company = cleanedDn.substring(companyIndex + companyMarker.length(), countryIndex); person.setCompany(company); return person; } private String createUrl() { String tempUrl = url; if (!tempUrl.endsWith("/")) { tempUrl += "/"; } if (StringUtils.isNotEmpty(base)) { tempUrl += base; } return tempUrl; } public void setUrl(String url) { this.url = url; } public void setBase(String base) { this.base = base; } public void setPassword(String credentials) { this.password = credentials; } public void setUserDn(String principal) { this.userName = principal; } } ././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/demo/solution/testContext.xmllibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/dem0000644000000000000000000000256511475313400030026 0ustar ././@LongLink0000000000000000000000000000020200000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/demo/solution/PersonDaoImpl.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo/src/main/java/org/springframework/ldap/dem0000644000000000000000000001055311475313400030022 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.demo.solution; import java.util.List; import javax.naming.Name; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.support.AbstractContextMapper; import org.springframework.ldap.demo.dao.PersonDao; import org.springframework.ldap.demo.domain.Person; /** * Spring LDAP implementation of PersonDao. This implementation uses many Spring * LDAP features, such as the {@link DirContextAdapter}, * {@link AbstractContextMapper}, and {@link LdapTemplate}. The purpose is to * contrast this implementation with that of {@link TraditionalPersonDaoImpl}. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class PersonDaoImpl implements PersonDao { private static final class PersonContextMapper extends AbstractContextMapper { protected Object doMapFromContext(DirContextOperations ctx) { Person person = new Person(); person.setFullName(ctx.getStringAttribute("cn")); person.setLastName(ctx.getStringAttribute("sn")); person.setDescription(ctx.getStringAttribute("description")); person.setPhone(ctx.getStringAttribute("telephoneNumber")); DistinguishedName dn = (DistinguishedName) ctx.getDn(); person.setCountry(dn.getValue("c")); person.setCompany(dn.getValue("ou")); return person; } } private LdapTemplate ldapTemplate; public void setLdapTemplate(LdapTemplate ldapTemplate) { this.ldapTemplate = ldapTemplate; } /* * @see PersonDao#create(Person) */ public void create(Person person) { DirContextOperations ctx = new DirContextAdapter(buildDn(person)); mapToContext(person, ctx); ldapTemplate.bind(ctx); } /* * @see PersonDao#update(Person) */ public void update(Person person) { DirContextOperations ctx = ldapTemplate.lookupContext(buildDn(person)); mapToContext(person, ctx); ldapTemplate.modifyAttributes(ctx); } /* * @see PersonDao#delete(Person) */ public void delete(Person person) { ldapTemplate.unbind(buildDn(person)); } /* * @see PersonDao#getAllPersonNames() */ public List getAllPersonNames() { return ldapTemplate.search("", "(objectclass=person)", new AbstractContextMapper() { protected Object doMapFromContext(DirContextOperations ctx) { return ctx.getStringAttribute("cn"); } }); } /* * @see PersonDao#findAll() */ public List findAll() { return ldapTemplate.search("", "(objectclass=person)", new PersonContextMapper()); } /* * @see PersonDao#findByPrimaryKey(java.lang.String, java.lang.String, * java.lang.String) */ public Person findByPrimaryKey(String country, String company, String fullname) { Name dn = buildDn(country, company, fullname); return (Person) ldapTemplate.lookup(dn, new PersonContextMapper()); } private Name buildDn(Person person) { return buildDn(person.getCountry(), person.getCompany(), person .getFullName()); } private Name buildDn(String country, String company, String fullname) { DistinguishedName dn = new DistinguishedName(); dn.append("c", country); dn.append("ou", company); dn.append("cn", fullname); return dn; } private void mapToContext(Person person, DirContextOperations ctx) { ctx.setAttributeValues("objectclass", new String[] { "top", "person" }); ctx.setAttributeValue("cn", person.getFullName()); ctx.setAttributeValue("sn", person.getLastName()); ctx.setAttributeValue("description", person.getDescription()); ctx.setAttributeValue("telephoneNumber", person.getPhone()); } } libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/0002777000000000000000000000000011475315320021064 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/readme.txt0000644000000000000000000000156311475315306023065 0ustar Demo application to be used for demonstrating how to convert a legacy JNDI-based dao implementation written in Java 1.4 to instead use Spring LDAP. For reference purposes, a corresponding implementation using ordinary Java LDAP/JNDI implementation is available in TraditionalPersonDaoImpl. How to use: ----------- 'mvn test' will start up an LDAP server before running the integration tests that verify the dao implementation. 'mvn eclipse:eclipse' will construct an Eclipse project for you to use. Import that project into Eclipse using File/Import/Existing Project, and select this directory. You can start converting the org.springframework.ldap.demo.dao.PersonDaoImpl class. The original traditional implementation, as well as a "solution", is available in the org.springframework.ldap.demo.solution package. Run the tests after you have converted a method. libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/pom.xml0000644000000000000000000000333611475313400022375 0ustar org.springframework.ldap spring-ldap-parent 1.3.1.CI-SNAPSHOT 4.0.0 org.springframework.ldap spring-ldap-demo-tiger Spring LDAP Demo (Java5) jar Example code for demonstrating the process of refactoring from plain JNDI to Spring LDAP (Java 5). maven-compiler-plugin 1.5 1.5 maven-eclipse-plugin org.springframework.ldap spring-ldap-test org.springframework.ldap spring-ldap-core-tiger org.springframework spring-context org.springframework spring-test test junit junit 4.5 test libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/0002755000000000000000000000000011475313400021644 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/0002755000000000000000000000000011475313400022623 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/java/0002755000000000000000000000000011475313400023544 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/java/org/0002755000000000000000000000000011475313400024333 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/java/org/springframework/0002755000000000000000000000000011475313400027553 5ustar ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/java/org/springframework/ldap/libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/java/org/springframework/ld0002755000000000000000000000000011475313400030073 5ustar ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/java/org/springframework/ldap/demo/libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/java/org/springframework/ld0002755000000000000000000000000011475313400030073 5ustar ././@LongLink0000000000000000000000000000016100000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/java/org/springframework/ldap/demo/dao/libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/java/org/springframework/ld0002755000000000000000000000000011475313400030073 5ustar ././@LongLink0000000000000000000000000000021600000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/java/org/springframework/ldap/demo/dao/PersonDaoIntegrationTest.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/java/org/springframework/ld0000644000000000000000000000726111475313400030101 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.demo.dao; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.util.List; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ldap.NameNotFoundException; import org.springframework.ldap.demo.domain.Person; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; /** * Integration tests for the PersonDao class. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ @ContextConfiguration(locations = { "/config/testContext.xml" }) public class PersonDaoIntegrationTest extends AbstractJUnit4SpringContextTests { private Person person; @Autowired private PersonDao personDao; @Before public void setUp() throws Exception { person = new Person(); person.setCountry("Sweden"); person.setCompany("company1"); person.setFullName("Some Person"); person.setLastName("Person"); person.setDescription("Sweden, Company1, Some Person"); person.setPhone("+46 555-123456"); } @After public void tearDown() throws Exception { person = null; personDao = null; } /** * Having a single test method test create, update and delete is not exactly * the ideal way of testing, since they depend on each other. A better way * would be to separate the tests and load a test fixture before each * operation, in order to guarantee the expected state every time. */ @Test public void testCreateUpdateDelete() { try { person.setFullName("Another Person"); personDao.create(person); personDao.findByPrimaryKey("Sweden", "company1", "Another Person"); // if we got here, create succeeded person.setDescription("Another description"); personDao.update(person); Person result = personDao.findByPrimaryKey("Sweden", "company1", "Another Person"); assertEquals("Another description", result.getDescription()); } finally { personDao.delete(person); try { personDao.findByPrimaryKey("Sweden", "company1", "Another Person"); fail("NameNotFoundException (when using Spring LDAP) or RuntimeException (when using traditional) expected"); } catch (NameNotFoundException expected) { // expected } catch (RuntimeException expected) { // expected } } } @Test public void testGetAllPersonNames() { List result = personDao.getAllPersonNames(); assertEquals(2, result.size()); String first = (String) result.get(0); assertEquals("Some Person", first); } @Test public void testFindAll() { List result = personDao.findAll(); assertEquals(2, result.size()); Person first = (Person) result.get(0); assertEquals("Some Person", first.getFullName()); } @Test public void testFindByPrimaryKey() { Person result = personDao.findByPrimaryKey("Sweden", "company1", "Some Person"); assertEquals(person, result); } } libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/resources/0002755000000000000000000000000011475313400024635 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/resources/log4j.properties0000644000000000000000000000040511475313400027767 0ustar log4j.rootCategory=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n log4j.logger.org.apache.directory=ERRORlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/resources/config/0002755000000000000000000000000011475313400026102 5ustar ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/resources/config/setup_data.ldiflibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/resources/config/setup_data0000644000000000000000000000156711475313400030165 0ustar dn: c=Sweden,dc=jayway,dc=se objectclass: top objectclass: country c: Sweden description: The country of Sweden dn: ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: organizationalUnit ou: company1 description: First company in Sweden dn: cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person userPassword: password cn: Some Person sn: Person description: Sweden, Company1, Some Person telephoneNumber: +46 555-123456 dn: cn=Some Person2,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person2 userPassword: password cn: Some Person2 sn: Person2 description: Sweden, Company1, Some Person2 telephoneNumber: +46 555-654321 ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/resources/config/testContext.xmllibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/resources/config/testContex0000644000000000000000000000256511475313400030173 0ustar ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/resources/config/ldap.propertieslibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/test/resources/config/ldap.prope0000644000000000000000000000013711475313400030070 0ustar urls=ldap://127.0.0.1:3900 userDn=uid=admin,ou=system password=secret base=dc=jayway,dc=se libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/0002755000000000000000000000000011475313400022570 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/0002755000000000000000000000000011475313400023511 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/overview.html0000644000000000000000000000013311475313400026240 0ustar This document is the API specification for the Spring LDAP Article sample. libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/0002755000000000000000000000000011475313400024300 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/0002755000000000000000000000000011475313400027520 5ustar ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ldap/libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400030040 5ustar ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ldap/demo/libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400030040 5ustar ././@LongLink0000000000000000000000000000016400000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ldap/demo/domain/libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400030040 5ustar ././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ldap/demo/domain/Person.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ld0000644000000000000000000000472511475313400030050 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.demo.domain; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; /** * Simple class representing a single person. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class Person { private String fullName; private String lastName; private String description; private String country; private String company; private String phone; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals( this, obj); } public int hashCode() { return HashCodeBuilder .reflectionHashCode(this); } public String toString() { return ToStringBuilder.reflectionToString( this, ToStringStyle.MULTI_LINE_STYLE); } } ././@LongLink0000000000000000000000000000016100000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ldap/demo/dao/libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400030040 5ustar ././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ldap/demo/dao/PersonDao.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ld0000644000000000000000000000222411475313400030040 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.demo.dao; import java.util.List; import org.springframework.ldap.demo.domain.Person; /** * Data Access Object interface for the Person entity. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public interface PersonDao { void create(Person person); void update(Person person); void delete(Person person); List getAllPersonNames(); List findAll(); Person findByPrimaryKey(String country, String company, String fullname); } ././@LongLink0000000000000000000000000000020300000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ldap/demo/dao/PersonDaoImpl.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ld0000644000000000000000000002224611475313400030046 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.demo.dao; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import javax.naming.Context; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import org.apache.commons.lang.StringUtils; import org.springframework.ldap.demo.dao.PersonDao; import org.springframework.ldap.demo.domain.Person; /** * Traditional implementation of PersonDao. This implementation uses the basic * JNDI interfaces and classes {@link DirContext}, {@link Attributes}, * {@link Attribute}, and {@link NamingEnumeration}. The purpose is to contrast * this implementation with an implementation based on Spring LDAP. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class PersonDaoImpl implements PersonDao { private String userName; private String password; private String url; private String base; /* * @see PersonDao#create(Person) */ public void create(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { Attributes attrs = getAttributesToBind(person); ctx.bind(dn, null, attrs); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#update(Person) */ public void update(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { ctx.rebind(dn, null, getAttributesToBind(person)); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#delete(Person) */ public void delete(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { ctx.unbind(dn); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#getAllPersonNames() */ public List getAllPersonNames() { DirContext ctx = createAnonymousContext(); LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls.setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search("", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results.next(); Attributes attributes = searchResult.getAttributes(); Attribute attr = attributes.get("cn"); String cn = (String) attr.get(); list.add(cn); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } /* * @see PersonDao#findAll() */ public List findAll() { DirContext ctx = createAnonymousContext(); LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls.setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search("", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results.next(); String dn = searchResult.getName(); Attributes attributes = searchResult.getAttributes(); list.add(mapToPerson(dn, attributes)); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } /* * @see PersonDao#findByPrimaryKey(java.lang.String, java.lang.String, * java.lang.String) */ public Person findByPrimaryKey(String country, String company, String fullname) { DirContext ctx = createAnonymousContext(); String dn = buildDn(country, company, fullname); try { Attributes attributes = ctx.getAttributes(dn); return mapToPerson(dn, attributes); } catch (NameNotFoundException e) { throw new RuntimeException("Did not find entry with primary key '" + dn + "'", e); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } private String buildDn(Person person) { return buildDn(person.getCountry(), person.getCompany(), person .getFullName()); } private String buildDn(String country, String company, String fullname) { StringBuffer sb = new StringBuffer(); sb.append("cn="); sb.append(fullname); sb.append(", "); sb.append("ou="); sb.append(company); sb.append(", "); sb.append("c="); sb.append(country); String dn = sb.toString(); return dn; } private DirContext createContext(Hashtable env) { env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); String tempUrl = createUrl(); env.put(Context.PROVIDER_URL, tempUrl); DirContext ctx; try { ctx = new InitialDirContext(env); } catch (NamingException e) { throw new RuntimeException(e); } return ctx; } private DirContext createAnonymousContext() { Hashtable hashtable = new Hashtable(); Hashtable env = hashtable; return createContext(env); } private DirContext createAuthenticatedContext() { Hashtable env = new Hashtable(); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, userName); env.put(Context.SECURITY_CREDENTIALS, password); return createContext(env); } private Attributes getAttributesToBind(Person person) { Attributes attrs = new BasicAttributes(); BasicAttribute ocattr = new BasicAttribute("objectclass"); ocattr.add("top"); ocattr.add("person"); attrs.put(ocattr); attrs.put("cn", person.getFullName()); attrs.put("sn", person.getLastName()); attrs.put("description", person.getDescription()); attrs.put("telephoneNumber", person.getPhone()); return attrs; } private Person mapToPerson(String dn, Attributes attributes) throws NamingException { Person person = new Person(); person.setFullName((String) attributes.get("cn").get()); person.setLastName((String) attributes.get("sn").get()); person.setDescription((String) attributes.get("description").get()); person.setPhone((String) attributes.get("telephoneNumber").get()); // Remove any trailing spaces after comma String cleanedDn = dn.replaceAll(", *", ","); String countryMarker = ",c="; int countryIndex = cleanedDn.lastIndexOf(countryMarker); String companyMarker = ",ou="; int companyIndex = cleanedDn.lastIndexOf(companyMarker); String country = cleanedDn.substring(countryIndex + countryMarker.length()); person.setCountry(country); String company = cleanedDn.substring(companyIndex + companyMarker.length(), countryIndex); person.setCompany(company); return person; } private String createUrl() { String tempUrl = url; if (!tempUrl.endsWith("/")) { tempUrl += "/"; } if (StringUtils.isNotEmpty(base)) { tempUrl += base; } return tempUrl; } public void setUrl(String url) { this.url = url; } public void setBase(String base) { this.base = base; } public void setPassword(String credentials) { this.password = credentials; } public void setUserDn(String principal) { this.userName = principal; } } ././@LongLink0000000000000000000000000000016600000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ldap/demo/solution/libspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400030040 5ustar ././@LongLink0000000000000000000000000000022300000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ldap/demo/solution/TraditionalPersonDaoImpl.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ld0000644000000000000000000002226611475313400030050 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.demo.solution; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import javax.naming.Context; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import org.apache.commons.lang.StringUtils; import org.springframework.ldap.demo.dao.PersonDao; import org.springframework.ldap.demo.domain.Person; /** * Traditional implementation of PersonDao. This implementation uses the basic * JNDI interfaces and classes {@link DirContext}, {@link Attributes}, * {@link Attribute}, and {@link NamingEnumeration}. The purpose is to contrast * this implementation with an implementation based on Spring LDAP. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class TraditionalPersonDaoImpl implements PersonDao { private String userName; private String password; private String url; private String base; /* * @see PersonDao#create(Person) */ public void create(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { Attributes attrs = getAttributesToBind(person); ctx.bind(dn, null, attrs); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#update(Person) */ public void update(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { ctx.rebind(dn, null, getAttributesToBind(person)); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#delete(Person) */ public void delete(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { ctx.unbind(dn); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#getAllPersonNames() */ public List getAllPersonNames() { DirContext ctx = createAnonymousContext(); LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls.setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search("", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results.next(); Attributes attributes = searchResult.getAttributes(); Attribute attr = attributes.get("cn"); String cn = (String) attr.get(); list.add(cn); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } /* * @see PersonDao#findAll() */ public List findAll() { DirContext ctx = createAnonymousContext(); LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls.setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search("", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results.next(); String dn = searchResult.getName(); Attributes attributes = searchResult.getAttributes(); list.add(mapToPerson(dn, attributes)); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } /* * @see PersonDao#findByPrimaryKey(java.lang.String, java.lang.String, * java.lang.String) */ public Person findByPrimaryKey(String country, String company, String fullname) { DirContext ctx = createAnonymousContext(); String dn = buildDn(country, company, fullname); try { Attributes attributes = ctx.getAttributes(dn); return mapToPerson(dn, attributes); } catch (NameNotFoundException e) { throw new RuntimeException("Did not find entry with primary key '" + dn + "'", e); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } private String buildDn(Person person) { return buildDn(person.getCountry(), person.getCompany(), person .getFullName()); } private String buildDn(String country, String company, String fullname) { StringBuffer sb = new StringBuffer(); sb.append("cn="); sb.append(fullname); sb.append(", "); sb.append("ou="); sb.append(company); sb.append(", "); sb.append("c="); sb.append(country); String dn = sb.toString(); return dn; } private DirContext createContext(Hashtable env) { env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); String tempUrl = createUrl(); env.put(Context.PROVIDER_URL, tempUrl); DirContext ctx; try { ctx = new InitialDirContext(env); } catch (NamingException e) { throw new RuntimeException(e); } return ctx; } private DirContext createAnonymousContext() { Hashtable hashtable = new Hashtable(); Hashtable env = hashtable; return createContext(env); } private DirContext createAuthenticatedContext() { Hashtable env = new Hashtable(); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, userName); env.put(Context.SECURITY_CREDENTIALS, password); return createContext(env); } private Attributes getAttributesToBind(Person person) { Attributes attrs = new BasicAttributes(); BasicAttribute ocattr = new BasicAttribute("objectclass"); ocattr.add("top"); ocattr.add("person"); attrs.put(ocattr); attrs.put("cn", person.getFullName()); attrs.put("sn", person.getLastName()); attrs.put("description", person.getDescription()); attrs.put("telephoneNumber", person.getPhone()); return attrs; } private Person mapToPerson(String dn, Attributes attributes) throws NamingException { Person person = new Person(); person.setFullName((String) attributes.get("cn").get()); person.setLastName((String) attributes.get("sn").get()); person.setDescription((String) attributes.get("description").get()); person.setPhone((String) attributes.get("telephoneNumber").get()); // Remove any trailing spaces after comma String cleanedDn = dn.replaceAll(", *", ","); String countryMarker = ",c="; int countryIndex = cleanedDn.lastIndexOf(countryMarker); String companyMarker = ",ou="; int companyIndex = cleanedDn.lastIndexOf(companyMarker); String country = cleanedDn.substring(countryIndex + countryMarker.length()); person.setCountry(country); String company = cleanedDn.substring(companyIndex + companyMarker.length(), countryIndex); person.setCompany(company); return person; } private String createUrl() { String tempUrl = url; if (!tempUrl.endsWith("/")) { tempUrl += "/"; } if (StringUtils.isNotEmpty(base)) { tempUrl += base; } return tempUrl; } public void setUrl(String url) { this.url = url; } public void setBase(String base) { this.base = base; } public void setPassword(String credentials) { this.password = credentials; } public void setUserDn(String principal) { this.userName = principal; } } ././@LongLink0000000000000000000000000000021000000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ldap/demo/solution/PersonDaoImpl.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/demos/demo-tiger/src/main/java/org/springframework/ld0000644000000000000000000001077211475313400030047 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.demo.solution; import java.util.List; import javax.naming.Name; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.simple.AbstractParameterizedContextMapper; import org.springframework.ldap.core.simple.SimpleLdapTemplate; import org.springframework.ldap.demo.dao.PersonDao; import org.springframework.ldap.demo.domain.Person; /** * Spring LDAP implementation of PersonDao. This implementation uses many Spring * LDAP features, such as the {@link DirContextAdapter}, * {@link AbstractParameterizedContextMapper}, and {@link SimpleLdapTemplate}. The purpose is to * contrast this implementation with that of {@link TraditionalPersonDaoImpl}. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class PersonDaoImpl implements PersonDao { private static final class PersonContextMapper extends AbstractParameterizedContextMapper { @Override protected Person doMapFromContext(DirContextOperations ctx) { Person person = new Person(); person.setFullName(ctx.getStringAttribute("cn")); person.setLastName(ctx.getStringAttribute("sn")); person.setDescription(ctx.getStringAttribute("description")); person.setPhone(ctx.getStringAttribute("telephoneNumber")); DistinguishedName dn = (DistinguishedName) ctx.getDn(); person.setCountry(dn.getValue("c")); person.setCompany(dn.getValue("ou")); return person; } } private SimpleLdapTemplate ldapTemplate; public void setLdapTemplate(SimpleLdapTemplate ldapTemplate) { this.ldapTemplate = ldapTemplate; } /* * @see PersonDao#create(Person) */ public void create(Person person) { DirContextOperations ctx = new DirContextAdapter(buildDn(person)); mapToContext(person, ctx); ldapTemplate.bind(ctx); } /* * @see PersonDao#update(Person) */ public void update(Person person) { DirContextOperations ctx = ldapTemplate.lookupContext(buildDn(person)); mapToContext(person, ctx); ldapTemplate.modifyAttributes(ctx); } /* * @see PersonDao#delete(Person) */ public void delete(Person person) { ldapTemplate.unbind(buildDn(person)); } /* * @see PersonDao#getAllPersonNames() */ public List getAllPersonNames() { return ldapTemplate.search("", "(objectclass=person)", new AbstractParameterizedContextMapper() { @Override protected String doMapFromContext(DirContextOperations ctx) { return ctx.getStringAttribute("cn"); } }); } /* * @see PersonDao#findAll() */ public List findAll() { return ldapTemplate.search("", "(objectclass=person)", new PersonContextMapper()); } /* * @see PersonDao#findByPrimaryKey(java.lang.String, java.lang.String, * java.lang.String) */ public Person findByPrimaryKey(String country, String company, String fullname) { Name dn = buildDn(country, company, fullname); return (Person) ldapTemplate.lookup(dn, new PersonContextMapper()); } private Name buildDn(Person person) { return buildDn(person.getCountry(), person.getCompany(), person .getFullName()); } private Name buildDn(String country, String company, String fullname) { DistinguishedName dn = new DistinguishedName(); dn.append("c", country); dn.append("ou", company); dn.append("cn", fullname); return dn; } private void mapToContext(Person person, DirContextOperations ctx) { ctx.setAttributeValues("objectclass", new String[] { "top", "person" }); ctx.setAttributeValue("cn", person.getFullName()); ctx.setAttributeValue("sn", person.getLastName()); ctx.setAttributeValue("description", person.getDescription()); ctx.setAttributeValue("telephoneNumber", person.getPhone()); } } libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/0002777000000000000000000000000011475315320021007 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/readme.txt0000644000000000000000000000214211475315306023002 0ustar Uses Spring 3.0. Sample application demonstrating how to do the most basic stuff in Spring LDAP. A very simple dao implementation is provided in org.springframework.ldap.samples.article.dao.PersonDaoImpl It demonstrates some basic operations using Spring LDAP. For reference purposes, a corresponding implementation using ordinary Java LDAP/JNDI implementation is available in TraditionalPersonDaoImpl. How to use: ----------- The project is in a Maven build structure. Make sure you have installed the samples-utils artifact, as this will be needed for this project to work. 'mvn jetty:run' will start up a web server demonstrating the capabilities. The web application will be available under http://localhost:8080/spring-ldap-person-article-spring30/ 'mvn eclipse:eclipse' will construct an Eclipse project for you to use. Import that project into Eclipse using File/Import/Existing Project, and select this directory. 'mvn test' will run some integration tests that require the LDAP server to be running. It's recommended to run 'mvn jetty:run' from another terminal window before 'mvn test'. libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/pom.xml0000644000000000000000000000645011475313400022320 0ustar org.springframework.ldap spring-ldap-parent 1.3.1.CI-SNAPSHOT 4.0.0 spring-ldap-article-spring30 Spring LDAP Article Sample (Spring 3.0) war Example code that matches the article published on java.net on April 18, 2006. 3.0.3.RELEASE maven-compiler-plugin 1.5 1.5 org.mortbay.jetty maven-jetty-plugin org.springframework.ldap spring-ldap-test log4j log4j 1.2.9 javax.servlet jstl 1.2 org.springframework.ldap spring-ldap-samples-utils org.springframework spring-core ${org.springframework.version} org.springframework spring-beans ${org.springframework.version} org.springframework spring-jdbc ${org.springframework.version} org.springframework spring-tx ${org.springframework.version} org.springframework spring-context ${org.springframework.version} org.springframework spring-aop ${org.springframework.version} org.springframework spring-web ${org.springframework.version} org.springframework spring-webmvc ${org.springframework.version} javax.servlet servlet-api provided org.springframework spring-test ${org.springframework.version} test libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/0002755000000000000000000000000011475313400021567 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/0002755000000000000000000000000011475313400022546 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/0002755000000000000000000000000011475313400023467 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/0002755000000000000000000000000011475313400024256 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/0002755000000000000000000000000011475313400027476 5ustar ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/ldap/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/ld0002755000000000000000000000000011475313400030016 5ustar ././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/ldap/samples/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/ld0002755000000000000000000000000011475313400030016 5ustar ././@LongLink0000000000000000000000000000017000000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/ldap/samples/article/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/ld0002755000000000000000000000000011475313400030016 5ustar ././@LongLink0000000000000000000000000000017400000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/ldap/samples/article/dao/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/ld0002755000000000000000000000000011475313400030016 5ustar ././@LongLink0000000000000000000000000000023500000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/ldap/samples/article/dao/PersonDaoImplIntegrationTest.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/ld0000644000000000000000000000211611475313400030016 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import org.springframework.ldap.samples.article.dao.PersonDaoImpl; /** * Integration tests for the PersonDaoImpl class. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class PersonDaoImplIntegrationTest extends AbstractPersonDaoIntegrationTest { public void setPersonDao( PersonDaoImpl personDao) { this.personDao = personDao; } } ././@LongLink0000000000000000000000000000025000000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/ldap/samples/article/dao/TraditionalPersonDaoImplIntegrationTest.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/ld0000644000000000000000000000205111475313400030014 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; /** * Integration tests for the TraditionalPersonDaoImpl class. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class TraditionalPersonDaoImplIntegrationTest extends AbstractPersonDaoIntegrationTest { public void setPersonDao( TraditionalPersonDaoImpl personDao) { this.personDao = personDao; } } ././@LongLink0000000000000000000000000000024100000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/ldap/samples/article/dao/AbstractPersonDaoIntegrationTest.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/java/org/springframework/ld0000644000000000000000000001004011475313400030011 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import java.util.List; import org.springframework.ldap.NameNotFoundException; import org.springframework.ldap.samples.article.dao.PersonDao; import org.springframework.ldap.samples.article.domain.Person; import org.springframework.test.AbstractDependencyInjectionSpringContextTests; /** * Abstract base class for PersonDao integration tests. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public abstract class AbstractPersonDaoIntegrationTest extends AbstractDependencyInjectionSpringContextTests { protected Person person; protected PersonDao personDao; protected String[] getConfigLocations() { return new String[] { "config/testContext.xml" }; } protected void onSetUp() throws Exception { super.onSetUp(); person = new Person(); person.setCountry("Sweden"); person.setCompany("company1"); person.setFullName("Some Person"); person.setLastName("Person"); person .setDescription("Sweden, Company1, Some Person"); person.setPhone("+46 555-123456"); } protected void onTearDown() throws Exception { super.onTearDown(); person = null; personDao = null; } /** * Having a single test method test create, update and delete is not exactly * the ideal way of testing, since they depend on each other. A better way * would be to separate the tests and load a test fixture before each * operation, in order to guarantee the expected state every time. See the * ldaptemplate-person sample for the correct way to do this. */ public void testCreateUpdateDelete() { try { person.setFullName("Another Person"); personDao.create(person); personDao.findByPrimaryKey( "Sweden", "company1", "Another Person"); // if we got here, create succeeded person .setDescription("Another description"); personDao.update(person); Person result = personDao .findByPrimaryKey( "Sweden", "company1", "Another Person"); assertEquals( "Another description", result .getDescription()); } finally { personDao.delete(person); try { personDao.findByPrimaryKey( "Sweden", "company1", "Another Person"); fail("NameNotFoundException (when using Spring LDAP) or RuntimeException (when using traditional) expected"); } catch (NameNotFoundException expected) { // expected } catch (RuntimeException expected) { // expected } } } public void testGetAllPersonNames() { List result = personDao.getAllPersonNames(); assertEquals(2, result.size()); String first = (String) result.get(0); assertEquals("Some Person", first); } public void testFindAll() { List result = personDao.findAll(); assertEquals(2, result.size()); Person first = (Person) result.get(0); assertEquals("Some Person", first .getFullName()); } public void testFindByPrimaryKey() { Person result = personDao.findByPrimaryKey( "Sweden", "company1", "Some Person"); assertEquals(person, result); } } libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/resources/0002755000000000000000000000000011475313400024560 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/resources/setup_data.ldif0000644000000000000000000000156711475313400027560 0ustar dn: c=Sweden,dc=jayway,dc=se objectclass: top objectclass: country c: Sweden description: The country of Sweden dn: ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: organizationalUnit ou: company1 description: First company in Sweden dn: cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person userPassword: password cn: Some Person sn: Person description: Sweden, Company1, Some Person telephoneNumber: +46 555-123456 dn: cn=Some Person2,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person2 userPassword: password cn: Some Person2 sn: Person2 description: Sweden, Company1, Some Person2 telephoneNumber: +46 555-654321 libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/resources/config/0002755000000000000000000000000011475313400026025 5ustar ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/resources/config/testContext.xmllibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/resources/config/testContex0000644000000000000000000000310511475313400030105 0ustar ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/resources/config/ldap.propertieslibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/test/resources/config/ldap.prope0000644000000000000000000000013711475313400030013 0ustar urls=ldap://127.0.0.1:3900 userDn=uid=admin,ou=system password=secret base=dc=jayway,dc=se libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/0002755000000000000000000000000011475313400022513 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/0002755000000000000000000000000011475313400023434 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/overview.html0000644000000000000000000000013311475313400026163 0ustar This document is the API specification for the Spring LDAP Article sample. libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/0002755000000000000000000000000011475313400024223 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/0002755000000000000000000000000011475313400027443 5ustar ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ldap/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400027763 5ustar ././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ldap/samples/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400027763 5ustar ././@LongLink0000000000000000000000000000017000000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ldap/samples/article/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400027763 5ustar ././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ldap/samples/article/domain/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400027763 5ustar ././@LongLink0000000000000000000000000000021200000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ldap/samples/article/domain/Person.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ld0000644000000000000000000000474011475313400027770 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.domain; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; /** * Simple class representing a single person. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class Person { private String fullName; private String lastName; private String description; private String country; private String company; private String phone; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals( this, obj); } public int hashCode() { return HashCodeBuilder .reflectionHashCode(this); } public String toString() { return ToStringBuilder.reflectionToString( this, ToStringStyle.MULTI_LINE_STYLE); } } ././@LongLink0000000000000000000000000000017400000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ldap/samples/article/web/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400027763 5ustar ././@LongLink0000000000000000000000000000022200000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ldap/samples/article/web/DefaultController.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ld0000644000000000000000000000746111475313400027773 0ustar package org.springframework.ldap.samples.article.web; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.samples.article.dao.PersonDao; import org.springframework.ldap.samples.article.domain.Person; import org.springframework.ldap.samples.utils.HtmlRowLdapTreeVisitor; import org.springframework.ldap.samples.utils.LdapTree; import org.springframework.ldap.samples.utils.LdapTreeBuilder; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; /** * Default controller. * * @author Mattias Hellborg Arthursson */ @Controller public class DefaultController { @Autowired private LdapTreeBuilder ldapTreeBuilder; @Autowired private PersonDao personDao; @RequestMapping("/welcome.do") public void welcomeHandler() { } @RequestMapping("/showTree.do") public ModelAndView showTree() { LdapTree ldapTree = ldapTreeBuilder.getLdapTree(DistinguishedName.EMPTY_PATH); HtmlRowLdapTreeVisitor visitor = new PersonLinkHtmlRowLdapTreeVisitor(); ldapTree.traverse(visitor); return new ModelAndView("showTree", "rows", visitor.getRows()); } @RequestMapping("/addPerson.do") public ModelAndView addPerson() { Person person = getPerson(); personDao.create(person); return showTree(); } @RequestMapping("/updatePhoneNumber.do") public ModelAndView updatePhoneNumber() { Person person = personDao.findByPrimaryKey("Sweden", "company1", "John Doe"); person.setPhone(StringUtils.join(new String[] { person.getPhone(), "0" })); personDao.update(person); return showTree(); } @RequestMapping("/removePerson.do") public ModelAndView removePerson() { Person person = getPerson(); personDao.delete(person); return showTree(); } @RequestMapping("/showPerson.do") public ModelMap showPerson(String country, String company, String fullName) { Person person = personDao.findByPrimaryKey(country, company, fullName); return new ModelMap("person", person); } private Person getPerson() { Person person = new Person(); person.setFullName("John Doe"); person.setLastName("Doe"); person.setCompany("company1"); person.setCountry("Sweden"); person.setDescription("Test user"); return person; } /** * Generates appropriate links for person leaves in the tree. * * @author Mattias Hellborg Arthursson */ private static final class PersonLinkHtmlRowLdapTreeVisitor extends HtmlRowLdapTreeVisitor { @Override protected String getLinkForNode(DirContextOperations node) { String[] objectClassValues = node.getStringAttributes("objectClass"); if (containsValue(objectClassValues, "person")) { DistinguishedName distinguishedName = (DistinguishedName) node.getDn(); String country = encodeValue(distinguishedName.getValue("c")); String company = encodeValue(distinguishedName.getValue("ou")); String fullName = encodeValue(distinguishedName.getValue("cn")); return "showPerson.do?country=" + country + "&company=" + company + "&fullName=" + fullName; } else { return super.getLinkForNode(node); } } private String encodeValue(String value) { try { return URLEncoder.encode(value, "UTF8"); } catch (UnsupportedEncodingException e) { // Not supposed to happen throw new RuntimeException("Unexpected encoding exception", e); } } private boolean containsValue(String[] values, String value) { for (String oneValue : values) { if (StringUtils.equals(oneValue, value)) { return true; } } return false; } } } ././@LongLink0000000000000000000000000000017400000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ldap/samples/article/dao/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ld0002755000000000000000000000000011475313400027763 5ustar ././@LongLink0000000000000000000000000000021200000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ldap/samples/article/dao/PersonDao.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ld0000644000000000000000000000225711475313400027771 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import java.util.List; import org.springframework.ldap.samples.article.domain.Person; /** * Data Access Object interface for the Person entity. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public interface PersonDao { void create(Person person); void update(Person person); void delete(Person person); List getAllPersonNames(); List findAll(); Person findByPrimaryKey(String country, String company, String fullname); } ././@LongLink0000000000000000000000000000023100000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ldap/samples/article/dao/TraditionalPersonDaoImpl.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ld0000644000000000000000000002516411475313400027773 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import javax.naming.Context; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import org.apache.commons.lang.StringUtils; import org.springframework.ldap.samples.article.domain.Person; /** * Traditional implementation of PersonDao. This implementation uses the basic * JNDI interfaces and classes {@link DirContext}, {@link Attributes}, * {@link Attribute}, and {@link NamingEnumeration}. The purpose is to * contrast this implementation with that of {@link PersonDaoImpl}. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class TraditionalPersonDaoImpl implements PersonDao { private String userName; private String password; private String url; private String base; /* * @see PersonDao#create(Person) */ public void create(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { Attributes attrs = getAttributesToBind(person); ctx.bind(dn, null, attrs); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#update(Person) */ public void update(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { ctx .rebind( dn, null, getAttributesToBind(person)); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#delete(Person) */ public void delete(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { ctx.unbind(dn); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#getAllPersonNames() */ public List getAllPersonNames() { DirContext ctx = createAnonymousContext(); LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls .setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search( "", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results .next(); Attributes attributes = searchResult .getAttributes(); Attribute attr = attributes.get("cn"); String cn = (String) attr.get(); list.add(cn); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } /* * @see PersonDao#findAll() */ public List findAll() { DirContext ctx = createAnonymousContext(); LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls .setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search( "", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results .next(); String dn = searchResult.getName(); Attributes attributes = searchResult .getAttributes(); list.add(mapToPerson(dn, attributes)); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } /* * @see PersonDao#findByPrimaryKey(java.lang.String, java.lang.String, * java.lang.String) */ public Person findByPrimaryKey(String country, String company, String fullname) { DirContext ctx = createAnonymousContext(); String dn = buildDn( country, company, fullname); try { Attributes attributes = ctx .getAttributes(dn); return mapToPerson(dn, attributes); } catch (NameNotFoundException e) { throw new RuntimeException( "Did not find entry with primary key '" + dn + "'", e); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } private String buildDn(Person person) { return buildDn(person.getCountry(), person .getCompany(), person.getFullName()); } private String buildDn(String country, String company, String fullname) { StringBuffer sb = new StringBuffer(); sb.append("cn="); sb.append(fullname); sb.append(", "); sb.append("ou="); sb.append(company); sb.append(", "); sb.append("c="); sb.append(country); String dn = sb.toString(); return dn; } private DirContext createContext(Hashtable env) { env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); String tempUrl = createUrl(); env.put(Context.PROVIDER_URL, tempUrl); DirContext ctx; try { ctx = new InitialDirContext(env); } catch (NamingException e) { throw new RuntimeException(e); } return ctx; } private DirContext createAnonymousContext() { Hashtable env = new Hashtable(); return createContext(env); } private DirContext createAuthenticatedContext() { Hashtable env = new Hashtable(); env.put( Context.SECURITY_AUTHENTICATION, "simple"); env.put( Context.SECURITY_PRINCIPAL, userName); env.put( Context.SECURITY_CREDENTIALS, password); return createContext(env); } private Attributes getAttributesToBind( Person person) { Attributes attrs = new BasicAttributes(); BasicAttribute ocattr = new BasicAttribute( "objectclass"); ocattr.add("top"); ocattr.add("person"); attrs.put(ocattr); attrs.put("cn", person.getFullName()); attrs.put("sn", person.getLastName()); attrs.put("description", person .getDescription()); attrs.put("telephoneNumber", person .getPhone()); return attrs; } private Person mapToPerson(String dn, Attributes attributes) throws NamingException { Person person = new Person(); person.setFullName((String) attributes.get( "cn").get()); person.setLastName((String) attributes.get( "sn").get()); person.setDescription((String) attributes .get("description").get()); person.setPhone((String) attributes.get( "telephoneNumber").get()); // Remove any trailing spaces after comma String cleanedDn = dn .replaceAll(", *", ","); String countryMarker = ",c="; int countryIndex = cleanedDn .lastIndexOf(countryMarker); String companyMarker = ",ou="; int companyIndex = cleanedDn .lastIndexOf(companyMarker); String country = cleanedDn .substring(countryIndex + countryMarker.length()); person.setCountry(country); String company = cleanedDn.substring( companyIndex + companyMarker.length(), countryIndex); person.setCompany(company); return person; } private String createUrl() { String tempUrl = url; if (!tempUrl.endsWith("/")) { tempUrl += "/"; } if (StringUtils.isNotEmpty(base)) { tempUrl += base; } return tempUrl; } public void setUrl(String url) { this.url = url; } public void setBase(String base) { this.base = base; } public void setPassword(String credentials) { this.password = credentials; } public void setUserDn(String principal) { this.userName = principal; } } ././@LongLink0000000000000000000000000000021600000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ldap/samples/article/dao/PersonDaoImpl.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/java/org/springframework/ld0000644000000000000000000001352611475313400027772 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import java.util.List; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.directory.Attributes; import org.springframework.ldap.core.AttributesMapper; import org.springframework.ldap.core.ContextMapper; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.filter.EqualsFilter; import org.springframework.ldap.samples.article.domain.Person; /** * Default implementation of PersonDao. This implementation uses * DirContextAdapter for managing attribute values. It has been specified in the * Spring Context that the DirObjectFactory should be used when creating objects * from contexts, which defaults to creating DirContextAdapter objects. This * means that we can use a ContextMapper to map from the found contexts to our * domain objects. This is especially useful since we in this case have * properties in our domain objects that depend on parts of the DN. * * We could have worked with Attributes and an AttributesMapper implementation * instead, but working with Attributes is a bore and also, working with * AttributesMapper objects (or, indeed Attributes) does not give us access to * the distinguished name. However, we do use it in one method that only needs a * single attribute: {@link #getAllPersonNames()}. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; /* * @see PersonDao#create(Person) */ public void create(Person person) { Name dn = buildDn(person); DirContextAdapter context = new DirContextAdapter(dn); mapToContext(person, context); ldapTemplate.bind(dn, context, null); } /* * @see PersonDao#update(Person) */ public void update(Person person) { Name dn = buildDn(person); DirContextAdapter context = (DirContextAdapter) ldapTemplate.lookup(dn); mapToContext(person, context); ldapTemplate.modifyAttributes(dn, context.getModificationItems()); } /* * @see PersonDao#delete(Person) */ public void delete(Person person) { ldapTemplate.unbind(buildDn(person)); } /* * @see PersonDao#getAllPersonNames() */ public List getAllPersonNames() { EqualsFilter filter = new EqualsFilter("objectclass", "person"); return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), new AttributesMapper() { public Object mapFromAttributes(Attributes attrs) throws NamingException { return attrs.get("cn").get(); } }); } /* * @see PersonDao#findAll() */ public List findAll() { EqualsFilter filter = new EqualsFilter("objectclass", "person"); return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), getContextMapper()); } /* * @see PersonDao#findByPrimaryKey(java.lang.String, java.lang.String, * java.lang.String) */ public Person findByPrimaryKey(String country, String company, String fullname) { DistinguishedName dn = buildDn(country, company, fullname); return (Person) ldapTemplate.lookup(dn, getContextMapper()); } private ContextMapper getContextMapper() { return new PersonContextMapper(); } private DistinguishedName buildDn(Person person) { return buildDn(person.getCountry(), person.getCompany(), person.getFullName()); } private DistinguishedName buildDn(String country, String company, String fullname) { DistinguishedName dn = new DistinguishedName(); dn.add("c", country); dn.add("ou", company); dn.add("cn", fullname); return dn; } private void mapToContext(Person person, DirContextAdapter context) { context.setAttributeValues("objectclass", new String[] { "top", "person" }); context.setAttributeValue("cn", person.getFullName()); context.setAttributeValue("sn", person.getLastName()); context.setAttributeValue("description", person.getDescription()); context.setAttributeValue("telephoneNumber", person.getPhone()); } /** * Maps from DirContextAdapter to Person objects. A DN for a person will be * of the form cn=[fullname],ou=[company],c=[country], so * the values of these attributes must be extracted from the DN. For this, * we use the DistinguishedName. * *Mattias Hellborg Arthurssonellborg Arthursson * @author Ulrik Sandberg */ private static class PersonContextMapper implements ContextMapper { public Object mapFromContext(Object ctx) { DirContextAdapter context = (DirContextAdapter) ctx; DistinguishedName dn = new DistinguishedName(context.getDn()); Person person = new Person(); person.setCountry(dn.getLdapRdn(0).getComponent().getValue()); person.setCompany(dn.getLdapRdn(1).getComponent().getValue()); person.setFullName(context.getStringAttribute("cn")); person.setLastName(context.getStringAttribute("sn")); person.setDescription(context.getStringAttribute("description")); person.setPhone(context.getStringAttribute("telephoneNumber")); return person; } } public void setLdapTemplate(LdapTemplate ldapTemplate) { this.ldapTemplate = ldapTemplate; } } libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/0002755000000000000000000000000011475313400023771 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/0002755000000000000000000000000011475313400025020 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/jsp/0002755000000000000000000000000011475313400025614 5ustar ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/jsp/showPerson.jsplibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/jsp/showPers0000644000000000000000000000053411475313400027351 0ustar <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> Back

Full name: ${person.fullName}
LastName: ${person.lastName}
Description: ${person.description}
Country: ${person.country}
Company: ${person.company}
Phone: ${person.phone}

././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/jsp/showTree.jsplibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/jsp/showTree0000644000000000000000000000130311475313400027332 0ustar <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

Operations

Clicking a link below performs the described operation which will be reflected in the LDAP tree below

Add new test person 'John Doe' (only works once)
Add a '0' to the phone number of test person (only works if the person has been created)
Remove test person

Tree contents

Click a person row to see the attribute values (country and company rows do not have additional info)

${row}

././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/setup_data.ldiflibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/setup_data.l0000644000000000000000000000156711475313400027335 0ustar dn: c=Sweden,dc=jayway,dc=se objectclass: top objectclass: country c: Sweden description: The country of Sweden dn: ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: organizationalUnit ou: company1 description: First company in Sweden dn: cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person userPassword: password cn: Some Person sn: Person description: Sweden, Company1, Some Person telephoneNumber: +46 555-123456 dn: cn=Some Person2,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person2 userPassword: password cn: Some Person2 sn: Person2 description: Sweden, Company1, Some Person2 telephoneNumber: +46 555-654321 ././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/applicationContext.xmllibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/applicationC0000644000000000000000000000250311475313400027347 0ustar ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/basic-servlet.xmllibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/basic-servle0000644000000000000000000000135411475313400027323 0ustar ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/ldap.propertieslibspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/ldap.propert0000644000000000000000000000013711475313400027354 0ustar urls=ldap://127.0.0.1:3900 userDn=uid=admin,ou=system password=secret base=dc=jayway,dc=se libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/WEB-INF/web.xml0000644000000000000000000000174111475313400026320 0ustar Spring LDAP Basic Example org.springframework.web.context.ContextLoaderListener basic org.springframework.web.servlet.DispatcherServlet contextConfigLocation /WEB-INF/basic-servlet.xml 1 basic *.do index.htm libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/webapp/index.htm0000644000000000000000000000012711475313400025610 0ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/resources/0002755000000000000000000000000011475313400024525 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article-spring30/src/main/resources/log4j.properties0000644000000000000000000000040511475313400027657 0ustar log4j.rootCategory=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n log4j.logger.org.apache.directory=ERRORlibspring-ldap-java-1.3.1.RELEASE.orig/samples/pom.xml0000644000000000000000000000344011475313400017226 0ustar org.springframework.ldap spring-ldap-parent 1.3.1.CI-SNAPSHOT ../parent 4.0.0 spring-ldap-samples pom Spring LDAP Samples samples-utils article article-spring20 article-spring30 demos spring-release Spring Release Repository http://maven.springframework.org/release org.mortbay.jetty maven-jetty-plugin org.apache.maven.plugins maven-war-plugin ${pom.artifactId} log4j log4j runtime libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/0002777000000000000000000000000011475315320020523 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/pom.xml0000644000000000000000000000245011475313400022030 0ustar org.springframework.ldap spring-ldap-parent 1.3.1.CI-SNAPSHOT ../../parent 4.0.0 spring-ldap-samples-utils jar Spring LDAP Samples Utilities maven-compiler-plugin 1.5 1.5 org.springframework.ldap spring-ldap-core-tiger org.springframework.ldap spring-ldap-test org.springframework spring-test junit junit libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/0002755000000000000000000000000011475313400021303 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/0002755000000000000000000000000011475313400022262 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/java/0002755000000000000000000000000011475313400023203 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/java/org/0002755000000000000000000000000011475313400023772 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/java/org/springframework/0002755000000000000000000000000011475313400027212 5ustar ././@LongLink0000000000000000000000000000014500000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/java/org/springframework/ldap/libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/java/org/springframework/ldap/0002755000000000000000000000000011475313400030132 5ustar ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/java/org/springframework/ldap/samples/libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/java/org/springframework/ldap/0002755000000000000000000000000011475313400030132 5ustar ././@LongLink0000000000000000000000000000016300000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/java/org/springframework/ldap/samples/utils/libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/java/org/springframework/ldap/0002755000000000000000000000000011475313400030132 5ustar ././@LongLink0000000000000000000000000000022600000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/java/org/springframework/ldap/samples/utils/LdapTreeBuilderIntegrationTest.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/java/org/springframework/ldap/0000644000000000000000000000355211475313400030137 0ustar package org.springframework.ldap.samples.utils; import static junit.framework.Assert.assertEquals; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DistinguishedName; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; @ContextConfiguration(locations = { "/conf/testContext.xml" }) public class LdapTreeBuilderIntegrationTest extends AbstractJUnit4SpringContextTests { @Autowired private LdapTreeBuilder tested; @Test public void testGetLdapTree() { LdapTree ldapTree = tested.getLdapTree(new DistinguishedName("c=Sweden")); ldapTree.traverse(new TestVisitor()); } private static final class TestVisitor implements LdapTreeVisitor { private static final DistinguishedName DN_1 = new DistinguishedName("c=Sweden"); private static final DistinguishedName DN_2 = new DistinguishedName("ou=company1,c=Sweden"); private static final DistinguishedName DN_3 = new DistinguishedName("cn=Some Person,ou=company1,c=Sweden"); private static final DistinguishedName DN_4 = new DistinguishedName("cn=Some Person2,ou=company1,c=Sweden"); private Map names = new LinkedHashMap(); private Iterator keyIterator; public TestVisitor() { names.put(DN_1, 0); names.put(DN_2, 1); names.put(DN_3, 2); names.put(DN_4, 2); keyIterator = names.keySet().iterator(); } public void visit(DirContextOperations node, int currentDepth) { DistinguishedName next = keyIterator.next(); assertEquals(next, node.getDn()); assertEquals(names.get(next).intValue(), currentDepth); } } } libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/resources/0002755000000000000000000000000011475313400024274 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/resources/conf/0002755000000000000000000000000011475313400025221 5ustar ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/resources/conf/commonTestContext.xmllibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/resources/conf/commonTestConte0000644000000000000000000000123311475313400030262 0ustar ././@LongLink0000000000000000000000000000014500000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/resources/conf/testContext.xmllibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/resources/conf/testContext.xml0000644000000000000000000000206511475313400030270 0ustar ././@LongLink0000000000000000000000000000014500000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/resources/conf/ldap.propertieslibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/resources/conf/ldap.properties0000644000000000000000000000013711475313400030256 0ustar urls=ldap://127.0.0.1:3900 userDn=uid=admin,ou=system password=secret base=dc=jayway,dc=se libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/resources/log4j.properties0000644000000000000000000000040711475313400027430 0ustar log4j.rootCategory=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n log4j.logger.org.apache.directory=ERROR libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/test/resources/setup_data.ldif0000644000000000000000000000157111475313400027267 0ustar dn: c=Sweden,dc=jayway,dc=se objectclass: top objectclass: country c: Sweden description: The country of Sweden dn: ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: organizationalUnit ou: company1 description: First company in Sweden dn: cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person userPassword: password cn: Some Person sn: Person description: Sweden, Company1, Some Person telephoneNumber: +46 555-123456 dn: cn=Some Person2,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person2 userPassword: password cn: Some Person2 sn: Person2 description: Sweden, Company1, Some Person2 telephoneNumber: +46 555-654321 libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/0002755000000000000000000000000011475313400022227 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/0002755000000000000000000000000011475313400023150 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/0002755000000000000000000000000011475313400023737 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/0002755000000000000000000000000011475313400027157 5ustar ././@LongLink0000000000000000000000000000014500000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/ldap/libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/ldap/0002755000000000000000000000000011475313400030077 5ustar ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/ldap/samples/libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/ldap/0002755000000000000000000000000011475313400030077 5ustar ././@LongLink0000000000000000000000000000016300000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/ldap/samples/utils/libspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/ldap/0002755000000000000000000000000011475313400030077 5ustar ././@LongLink0000000000000000000000000000020700000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/ldap/samples/utils/LdapTreeVisitor.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/ldap/0000644000000000000000000000032411475313400030076 0ustar package org.springframework.ldap.samples.utils; import org.springframework.ldap.core.DirContextOperations; public interface LdapTreeVisitor { public void visit(DirContextOperations node, int currentDepth); } ././@LongLink0000000000000000000000000000021600000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/ldap/samples/utils/HtmlRowLdapTreeVisitor.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/ldap/0000644000000000000000000000140611475313400030100 0ustar package org.springframework.ldap.samples.utils; import java.util.LinkedList; import java.util.List; import org.springframework.ldap.core.DirContextOperations; public class HtmlRowLdapTreeVisitor implements LdapTreeVisitor { private List rows = new LinkedList(); public void visit(DirContextOperations node, int currentDepth) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < currentDepth; i++) { sb.append("    "); } sb.append("").append(node.getDn()).append("") .append("
\n"); rows.add(sb.toString()); } protected String getLinkForNode(DirContextOperations node) { return "#"; } public List getRows() { return rows; } } ././@LongLink0000000000000000000000000000020700000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/ldap/samples/utils/LdapTreeBuilder.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/ldap/0000644000000000000000000000222411475313400030077 0ustar package org.springframework.ldap.samples.utils; import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.support.AbstractContextMapper; public class LdapTreeBuilder { private LdapTemplate ldapTemplate; public LdapTreeBuilder(LdapTemplate ldapTemplate) { this.ldapTemplate = ldapTemplate; } public LdapTree getLdapTree(DistinguishedName root) { DirContextOperations context = ldapTemplate.lookupContext(root .toString()); return getLdapTree(context); } private LdapTree getLdapTree(final DirContextOperations rootContext) { final LdapTree ldapTree = new LdapTree(rootContext); ldapTemplate.listBindings(rootContext.getDn(), new AbstractContextMapper() { @Override protected Object doMapFromContext(DirContextOperations ctx) { DistinguishedName dn = (DistinguishedName) ctx.getDn(); dn.prepend((DistinguishedName) rootContext.getDn()); ldapTree.addSubTree(getLdapTree(ldapTemplate .lookupContext(dn))); return null; } }); return ldapTree; } } ././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/ldap/samples/utils/LdapTree.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/samples-utils/src/main/java/org/springframework/ldap/0000644000000000000000000000167711475313400030112 0ustar package org.springframework.ldap.samples.utils; import java.util.LinkedList; import java.util.List; import org.springframework.ldap.core.DirContextOperations; public class LdapTree { private final DirContextOperations node; private List subContexts = new LinkedList(); public LdapTree(DirContextOperations node) { this.node = node; } public DirContextOperations getNode() { return node; } public List getSubContexts() { return subContexts; } public void setSubContexts(List subContexts) { this.subContexts = subContexts; } public void addSubTree(LdapTree ldapTree) { subContexts.add(ldapTree); } public void traverse(LdapTreeVisitor visitor) { traverse(visitor, 0); } private void traverse(LdapTreeVisitor visitor, int currentDepth) { visitor.visit(node, currentDepth); for (LdapTree subContext : subContexts) { subContext.traverse(visitor, currentDepth + 1); } } } libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/0002777000000000000000000000000011475315320017344 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/readme.txt0000644000000000000000000000210711475315306021340 0ustar Sample application demonstrating how to do the most basic stuff in Spring LDAP. A very simple dao implementation is provided in org.springframework.ldap.samples.article.dao.PersonDaoImpl It demonstrates some basic operations using Spring LDAP. For reference purposes, a corresponding implementation using ordinary Java LDAP/JNDI implementation is available in TraditionalPersonDaoImpl. How to use: ----------- The project is in a Maven build structure. Make sure you have installed the samples-utils artifact, as this will be needed for this project to work. 'mvn jetty:run' will start up a web server demonstrating the capabilities. The web application will be available under http://localhost:8080/spring-ldap-person-article/ 'mvn eclipse:eclipse' will construct an Eclipse project for you to use. Import that project into Eclipse using File/Import/Existing Project, and select this directory. 'mvn test' will run some integration tests that require the LDAP server to be running. It's recommended to run 'mvn jetty:run' from another terminal window before 'mvn test'. libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/pom.xml0000644000000000000000000000423211475313400020651 0ustar org.springframework.ldap spring-ldap-parent 1.3.1.CI-SNAPSHOT 4.0.0 spring-ldap-article Spring LDAP Article Sample war Example code that matches the article published on java.net on April 18, 2006. maven-compiler-plugin 1.5 1.5 org.mortbay.jetty maven-jetty-plugin org.springframework.ldap spring-ldap-test log4j log4j 1.2.9 javax.servlet jstl 1.2 org.springframework.ldap spring-ldap-samples-utils org.springframework spring-jdbc org.springframework spring-context org.springframework spring-webmvc javax.servlet servlet-api provided org.springframework spring-test test libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/0002755000000000000000000000000011475313400020124 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/0002755000000000000000000000000011475313400021103 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/0002755000000000000000000000000011475313400022024 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/0002755000000000000000000000000011475313400022613 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/springframework/0002755000000000000000000000000011475313400026033 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/springframework/ldap/0002755000000000000000000000000011475313400026753 5ustar ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/springframework/ldap/samples/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/springframework/ldap/sample0002755000000000000000000000000011475313400030155 5ustar ././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/springframework/ldap/samples/article/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/springframework/ldap/sample0002755000000000000000000000000011475313400030155 5ustar ././@LongLink0000000000000000000000000000016300000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/springframework/ldap/samples/article/dao/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/springframework/ldap/sample0002755000000000000000000000000011475313400030155 5ustar ././@LongLink0000000000000000000000000000022400000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/springframework/ldap/samples/article/dao/PersonDaoImplIntegrationTest.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/springframework/ldap/sample0000644000000000000000000000211611475313400030155 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import org.springframework.ldap.samples.article.dao.PersonDaoImpl; /** * Integration tests for the PersonDaoImpl class. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class PersonDaoImplIntegrationTest extends AbstractPersonDaoIntegrationTest { public void setPersonDao( PersonDaoImpl personDao) { this.personDao = personDao; } } ././@LongLink0000000000000000000000000000023700000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/springframework/ldap/samples/article/dao/TraditionalPersonDaoImplIntegrationTest.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/springframework/ldap/sample0000644000000000000000000000205111475313400030153 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; /** * Integration tests for the TraditionalPersonDaoImpl class. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class TraditionalPersonDaoImplIntegrationTest extends AbstractPersonDaoIntegrationTest { public void setPersonDao( TraditionalPersonDaoImpl personDao) { this.personDao = personDao; } } ././@LongLink0000000000000000000000000000023000000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/springframework/ldap/samples/article/dao/AbstractPersonDaoIntegrationTest.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/java/org/springframework/ldap/sample0000644000000000000000000001004011475313400030150 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import java.util.List; import org.springframework.ldap.NameNotFoundException; import org.springframework.ldap.samples.article.dao.PersonDao; import org.springframework.ldap.samples.article.domain.Person; import org.springframework.test.AbstractDependencyInjectionSpringContextTests; /** * Abstract base class for PersonDao integration tests. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public abstract class AbstractPersonDaoIntegrationTest extends AbstractDependencyInjectionSpringContextTests { protected Person person; protected PersonDao personDao; protected String[] getConfigLocations() { return new String[] { "config/testContext.xml" }; } protected void onSetUp() throws Exception { super.onSetUp(); person = new Person(); person.setCountry("Sweden"); person.setCompany("company1"); person.setFullName("Some Person"); person.setLastName("Person"); person .setDescription("Sweden, Company1, Some Person"); person.setPhone("+46 555-123456"); } protected void onTearDown() throws Exception { super.onTearDown(); person = null; personDao = null; } /** * Having a single test method test create, update and delete is not exactly * the ideal way of testing, since they depend on each other. A better way * would be to separate the tests and load a test fixture before each * operation, in order to guarantee the expected state every time. See the * ldaptemplate-person sample for the correct way to do this. */ public void testCreateUpdateDelete() { try { person.setFullName("Another Person"); personDao.create(person); personDao.findByPrimaryKey( "Sweden", "company1", "Another Person"); // if we got here, create succeeded person .setDescription("Another description"); personDao.update(person); Person result = personDao .findByPrimaryKey( "Sweden", "company1", "Another Person"); assertEquals( "Another description", result .getDescription()); } finally { personDao.delete(person); try { personDao.findByPrimaryKey( "Sweden", "company1", "Another Person"); fail("NameNotFoundException (when using Spring LDAP) or RuntimeException (when using traditional) expected"); } catch (NameNotFoundException expected) { // expected } catch (RuntimeException expected) { // expected } } } public void testGetAllPersonNames() { List result = personDao.getAllPersonNames(); assertEquals(2, result.size()); String first = (String) result.get(0); assertEquals("Some Person", first); } public void testFindAll() { List result = personDao.findAll(); assertEquals(2, result.size()); Person first = (Person) result.get(0); assertEquals("Some Person", first .getFullName()); } public void testFindByPrimaryKey() { Person result = personDao.findByPrimaryKey( "Sweden", "company1", "Some Person"); assertEquals(person, result); } } libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/resources/0002755000000000000000000000000011475313400023115 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/resources/setup_data.ldif0000644000000000000000000000156711475313400026115 0ustar dn: c=Sweden,dc=jayway,dc=se objectclass: top objectclass: country c: Sweden description: The country of Sweden dn: ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: organizationalUnit ou: company1 description: First company in Sweden dn: cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person userPassword: password cn: Some Person sn: Person description: Sweden, Company1, Some Person telephoneNumber: +46 555-123456 dn: cn=Some Person2,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person2 userPassword: password cn: Some Person2 sn: Person2 description: Sweden, Company1, Some Person2 telephoneNumber: +46 555-654321 libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/resources/config/0002755000000000000000000000000011475313400024362 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/resources/config/testContext.xml0000644000000000000000000000310511475313400027425 0ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/test/resources/config/ldap.properties0000644000000000000000000000013711475313400027417 0ustar urls=ldap://127.0.0.1:3900 userDn=uid=admin,ou=system password=secret base=dc=jayway,dc=se libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/0002755000000000000000000000000011475313400021050 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/0002755000000000000000000000000011475313400021771 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/overview.html0000644000000000000000000000013311475313400024520 0ustar This document is the API specification for the Spring LDAP Article sample. libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/0002755000000000000000000000000011475313400022560 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/0002755000000000000000000000000011475313400026000 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/0002755000000000000000000000000011475313400026720 5ustar ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/samples/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/sample0002755000000000000000000000000011475313400030122 5ustar ././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/samples/article/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/sample0002755000000000000000000000000011475313400030122 5ustar ././@LongLink0000000000000000000000000000016600000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/samples/article/domain/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/sample0002755000000000000000000000000011475313400030122 5ustar ././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/samples/article/domain/Person.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/sample0000644000000000000000000000474011475313400030127 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.domain; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; /** * Simple class representing a single person. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class Person { private String fullName; private String lastName; private String description; private String country; private String company; private String phone; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals( this, obj); } public int hashCode() { return HashCodeBuilder .reflectionHashCode(this); } public String toString() { return ToStringBuilder.reflectionToString( this, ToStringStyle.MULTI_LINE_STYLE); } } ././@LongLink0000000000000000000000000000016300000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/samples/article/web/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/sample0002755000000000000000000000000011475313400030122 5ustar ././@LongLink0000000000000000000000000000021100000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/samples/article/web/DefaultController.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/sample0000644000000000000000000000746111475313400030132 0ustar package org.springframework.ldap.samples.article.web; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.samples.article.dao.PersonDao; import org.springframework.ldap.samples.article.domain.Person; import org.springframework.ldap.samples.utils.HtmlRowLdapTreeVisitor; import org.springframework.ldap.samples.utils.LdapTree; import org.springframework.ldap.samples.utils.LdapTreeBuilder; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; /** * Default controller. * * @author Mattias Hellborg Arthursson */ @Controller public class DefaultController { @Autowired private LdapTreeBuilder ldapTreeBuilder; @Autowired private PersonDao personDao; @RequestMapping("/welcome.do") public void welcomeHandler() { } @RequestMapping("/showTree.do") public ModelAndView showTree() { LdapTree ldapTree = ldapTreeBuilder.getLdapTree(DistinguishedName.EMPTY_PATH); HtmlRowLdapTreeVisitor visitor = new PersonLinkHtmlRowLdapTreeVisitor(); ldapTree.traverse(visitor); return new ModelAndView("showTree", "rows", visitor.getRows()); } @RequestMapping("/addPerson.do") public ModelAndView addPerson() { Person person = getPerson(); personDao.create(person); return showTree(); } @RequestMapping("/updatePhoneNumber.do") public ModelAndView updatePhoneNumber() { Person person = personDao.findByPrimaryKey("Sweden", "company1", "John Doe"); person.setPhone(StringUtils.join(new String[] { person.getPhone(), "0" })); personDao.update(person); return showTree(); } @RequestMapping("/removePerson.do") public ModelAndView removePerson() { Person person = getPerson(); personDao.delete(person); return showTree(); } @RequestMapping("/showPerson.do") public ModelMap showPerson(String country, String company, String fullName) { Person person = personDao.findByPrimaryKey(country, company, fullName); return new ModelMap("person", person); } private Person getPerson() { Person person = new Person(); person.setFullName("John Doe"); person.setLastName("Doe"); person.setCompany("company1"); person.setCountry("Sweden"); person.setDescription("Test user"); return person; } /** * Generates appropriate links for person leaves in the tree. * * @author Mattias Hellborg Arthursson */ private static final class PersonLinkHtmlRowLdapTreeVisitor extends HtmlRowLdapTreeVisitor { @Override protected String getLinkForNode(DirContextOperations node) { String[] objectClassValues = node.getStringAttributes("objectClass"); if (containsValue(objectClassValues, "person")) { DistinguishedName distinguishedName = (DistinguishedName) node.getDn(); String country = encodeValue(distinguishedName.getValue("c")); String company = encodeValue(distinguishedName.getValue("ou")); String fullName = encodeValue(distinguishedName.getValue("cn")); return "showPerson.do?country=" + country + "&company=" + company + "&fullName=" + fullName; } else { return super.getLinkForNode(node); } } private String encodeValue(String value) { try { return URLEncoder.encode(value, "UTF8"); } catch (UnsupportedEncodingException e) { // Not supposed to happen throw new RuntimeException("Unexpected encoding exception", e); } } private boolean containsValue(String[] values, String value) { for (String oneValue : values) { if (StringUtils.equals(oneValue, value)) { return true; } } return false; } } } ././@LongLink0000000000000000000000000000016300000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/samples/article/dao/libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/sample0002755000000000000000000000000011475313400030122 5ustar ././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/samples/article/dao/PersonDao.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/sample0000644000000000000000000000225711475313400030130 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import java.util.List; import org.springframework.ldap.samples.article.domain.Person; /** * Data Access Object interface for the Person entity. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public interface PersonDao { void create(Person person); void update(Person person); void delete(Person person); List getAllPersonNames(); List findAll(); Person findByPrimaryKey(String country, String company, String fullname); } ././@LongLink0000000000000000000000000000022000000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/samples/article/dao/TraditionalPersonDaoImpl.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/sample0000644000000000000000000002516411475313400030132 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import javax.naming.Context; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import org.apache.commons.lang.StringUtils; import org.springframework.ldap.samples.article.domain.Person; /** * Traditional implementation of PersonDao. This implementation uses the basic * JNDI interfaces and classes {@link DirContext}, {@link Attributes}, * {@link Attribute}, and {@link NamingEnumeration}. The purpose is to * contrast this implementation with that of {@link PersonDaoImpl}. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class TraditionalPersonDaoImpl implements PersonDao { private String userName; private String password; private String url; private String base; /* * @see PersonDao#create(Person) */ public void create(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { Attributes attrs = getAttributesToBind(person); ctx.bind(dn, null, attrs); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#update(Person) */ public void update(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { ctx .rebind( dn, null, getAttributesToBind(person)); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#delete(Person) */ public void delete(Person person) { DirContext ctx = createAuthenticatedContext(); String dn = buildDn(person); try { ctx.unbind(dn); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } /* * @see PersonDao#getAllPersonNames() */ public List getAllPersonNames() { DirContext ctx = createAnonymousContext(); LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls .setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search( "", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results .next(); Attributes attributes = searchResult .getAttributes(); Attribute attr = attributes.get("cn"); String cn = (String) attr.get(); list.add(cn); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } /* * @see PersonDao#findAll() */ public List findAll() { DirContext ctx = createAnonymousContext(); LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls .setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search( "", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results .next(); String dn = searchResult.getName(); Attributes attributes = searchResult .getAttributes(); list.add(mapToPerson(dn, attributes)); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } /* * @see PersonDao#findByPrimaryKey(java.lang.String, java.lang.String, * java.lang.String) */ public Person findByPrimaryKey(String country, String company, String fullname) { DirContext ctx = createAnonymousContext(); String dn = buildDn( country, company, fullname); try { Attributes attributes = ctx .getAttributes(dn); return mapToPerson(dn, attributes); } catch (NameNotFoundException e) { throw new RuntimeException( "Did not find entry with primary key '" + dn + "'", e); } catch (NamingException e) { throw new RuntimeException(e); } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } } private String buildDn(Person person) { return buildDn(person.getCountry(), person .getCompany(), person.getFullName()); } private String buildDn(String country, String company, String fullname) { StringBuffer sb = new StringBuffer(); sb.append("cn="); sb.append(fullname); sb.append(", "); sb.append("ou="); sb.append(company); sb.append(", "); sb.append("c="); sb.append(country); String dn = sb.toString(); return dn; } private DirContext createContext(Hashtable env) { env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); String tempUrl = createUrl(); env.put(Context.PROVIDER_URL, tempUrl); DirContext ctx; try { ctx = new InitialDirContext(env); } catch (NamingException e) { throw new RuntimeException(e); } return ctx; } private DirContext createAnonymousContext() { Hashtable env = new Hashtable(); return createContext(env); } private DirContext createAuthenticatedContext() { Hashtable env = new Hashtable(); env.put( Context.SECURITY_AUTHENTICATION, "simple"); env.put( Context.SECURITY_PRINCIPAL, userName); env.put( Context.SECURITY_CREDENTIALS, password); return createContext(env); } private Attributes getAttributesToBind( Person person) { Attributes attrs = new BasicAttributes(); BasicAttribute ocattr = new BasicAttribute( "objectclass"); ocattr.add("top"); ocattr.add("person"); attrs.put(ocattr); attrs.put("cn", person.getFullName()); attrs.put("sn", person.getLastName()); attrs.put("description", person .getDescription()); attrs.put("telephoneNumber", person .getPhone()); return attrs; } private Person mapToPerson(String dn, Attributes attributes) throws NamingException { Person person = new Person(); person.setFullName((String) attributes.get( "cn").get()); person.setLastName((String) attributes.get( "sn").get()); person.setDescription((String) attributes .get("description").get()); person.setPhone((String) attributes.get( "telephoneNumber").get()); // Remove any trailing spaces after comma String cleanedDn = dn .replaceAll(", *", ","); String countryMarker = ",c="; int countryIndex = cleanedDn .lastIndexOf(countryMarker); String companyMarker = ",ou="; int companyIndex = cleanedDn .lastIndexOf(companyMarker); String country = cleanedDn .substring(countryIndex + countryMarker.length()); person.setCountry(country); String company = cleanedDn.substring( companyIndex + companyMarker.length(), countryIndex); person.setCompany(company); return person; } private String createUrl() { String tempUrl = url; if (!tempUrl.endsWith("/")) { tempUrl += "/"; } if (StringUtils.isNotEmpty(base)) { tempUrl += base; } return tempUrl; } public void setUrl(String url) { this.url = url; } public void setBase(String base) { this.base = base; } public void setPassword(String credentials) { this.password = credentials; } public void setUserDn(String principal) { this.userName = principal; } } ././@LongLink0000000000000000000000000000020500000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/samples/article/dao/PersonDaoImpl.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/java/org/springframework/ldap/sample0000644000000000000000000001352611475313400030131 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.samples.article.dao; import java.util.List; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.directory.Attributes; import org.springframework.ldap.core.AttributesMapper; import org.springframework.ldap.core.ContextMapper; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.filter.EqualsFilter; import org.springframework.ldap.samples.article.domain.Person; /** * Default implementation of PersonDao. This implementation uses * DirContextAdapter for managing attribute values. It has been specified in the * Spring Context that the DirObjectFactory should be used when creating objects * from contexts, which defaults to creating DirContextAdapter objects. This * means that we can use a ContextMapper to map from the found contexts to our * domain objects. This is especially useful since we in this case have * properties in our domain objects that depend on parts of the DN. * * We could have worked with Attributes and an AttributesMapper implementation * instead, but working with Attributes is a bore and also, working with * AttributesMapper objects (or, indeed Attributes) does not give us access to * the distinguished name. However, we do use it in one method that only needs a * single attribute: {@link #getAllPersonNames()}. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; /* * @see PersonDao#create(Person) */ public void create(Person person) { Name dn = buildDn(person); DirContextAdapter context = new DirContextAdapter(dn); mapToContext(person, context); ldapTemplate.bind(dn, context, null); } /* * @see PersonDao#update(Person) */ public void update(Person person) { Name dn = buildDn(person); DirContextAdapter context = (DirContextAdapter) ldapTemplate.lookup(dn); mapToContext(person, context); ldapTemplate.modifyAttributes(dn, context.getModificationItems()); } /* * @see PersonDao#delete(Person) */ public void delete(Person person) { ldapTemplate.unbind(buildDn(person)); } /* * @see PersonDao#getAllPersonNames() */ public List getAllPersonNames() { EqualsFilter filter = new EqualsFilter("objectclass", "person"); return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), new AttributesMapper() { public Object mapFromAttributes(Attributes attrs) throws NamingException { return attrs.get("cn").get(); } }); } /* * @see PersonDao#findAll() */ public List findAll() { EqualsFilter filter = new EqualsFilter("objectclass", "person"); return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), getContextMapper()); } /* * @see PersonDao#findByPrimaryKey(java.lang.String, java.lang.String, * java.lang.String) */ public Person findByPrimaryKey(String country, String company, String fullname) { DistinguishedName dn = buildDn(country, company, fullname); return (Person) ldapTemplate.lookup(dn, getContextMapper()); } private ContextMapper getContextMapper() { return new PersonContextMapper(); } private DistinguishedName buildDn(Person person) { return buildDn(person.getCountry(), person.getCompany(), person.getFullName()); } private DistinguishedName buildDn(String country, String company, String fullname) { DistinguishedName dn = new DistinguishedName(); dn.add("c", country); dn.add("ou", company); dn.add("cn", fullname); return dn; } private void mapToContext(Person person, DirContextAdapter context) { context.setAttributeValues("objectclass", new String[] { "top", "person" }); context.setAttributeValue("cn", person.getFullName()); context.setAttributeValue("sn", person.getLastName()); context.setAttributeValue("description", person.getDescription()); context.setAttributeValue("telephoneNumber", person.getPhone()); } /** * Maps from DirContextAdapter to Person objects. A DN for a person will be * of the form cn=[fullname],ou=[company],c=[country], so * the values of these attributes must be extracted from the DN. For this, * we use the DistinguishedName. * *Mattias Hellborg Arthurssonellborg Arthursson * @author Ulrik Sandberg */ private static class PersonContextMapper implements ContextMapper { public Object mapFromContext(Object ctx) { DirContextAdapter context = (DirContextAdapter) ctx; DistinguishedName dn = new DistinguishedName(context.getDn()); Person person = new Person(); person.setCountry(dn.getLdapRdn(0).getComponent().getValue()); person.setCompany(dn.getLdapRdn(1).getComponent().getValue()); person.setFullName(context.getStringAttribute("cn")); person.setLastName(context.getStringAttribute("sn")); person.setDescription(context.getStringAttribute("description")); person.setPhone(context.getStringAttribute("telephoneNumber")); return person; } } public void setLdapTemplate(LdapTemplate ldapTemplate) { this.ldapTemplate = ldapTemplate; } } libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/webapp/0002755000000000000000000000000011475313400022326 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/webapp/WEB-INF/0002755000000000000000000000000011475313400023355 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/webapp/WEB-INF/jsp/0002755000000000000000000000000011475313400024151 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/webapp/WEB-INF/jsp/showPerson.jsp0000644000000000000000000000053411475313400027036 0ustar <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> Back

Full name: ${person.fullName}
LastName: ${person.lastName}
Description: ${person.description}
Country: ${person.country}
Company: ${person.company}
Phone: ${person.phone}

libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/webapp/WEB-INF/jsp/showTree.jsp0000644000000000000000000000130311475313400026462 0ustar <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

Operations

Clicking a link below performs the described operation which will be reflected in the LDAP tree below

Add new test person 'John Doe' (only works once)
Add a '0' to the phone number of test person (only works if the person has been created)
Remove test person

Tree contents

Click a person row to see the attribute values (country and company rows do not have additional info)

${row}

libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/webapp/WEB-INF/setup_data.ldif0000644000000000000000000000156711475313400026355 0ustar dn: c=Sweden,dc=jayway,dc=se objectclass: top objectclass: country c: Sweden description: The country of Sweden dn: ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: organizationalUnit ou: company1 description: First company in Sweden dn: cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person userPassword: password cn: Some Person sn: Person description: Sweden, Company1, Some Person telephoneNumber: +46 555-123456 dn: cn=Some Person2,ou=company1,c=Sweden,dc=jayway,dc=se objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: some.person2 userPassword: password cn: Some Person2 sn: Person2 description: Sweden, Company1, Some Person2 telephoneNumber: +46 555-654321 ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/webapp/WEB-INF/applicationContext.xmllibspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/webapp/WEB-INF/applicationContext.xm0000644000000000000000000000250311475313400027571 0ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/webapp/WEB-INF/basic-servlet.xml0000644000000000000000000000135411475313400026643 0ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/webapp/WEB-INF/ldap.properties0000644000000000000000000000013711475313400026412 0ustar urls=ldap://127.0.0.1:3900 userDn=uid=admin,ou=system password=secret base=dc=jayway,dc=se libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/webapp/WEB-INF/web.xml0000644000000000000000000000174111475313400024655 0ustar Spring LDAP Basic Example org.springframework.web.context.ContextLoaderListener basic org.springframework.web.servlet.DispatcherServlet contextConfigLocation /WEB-INF/basic-servlet.xml 1 basic *.do index.htm libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/webapp/index.htm0000644000000000000000000000012711475313400024145 0ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/resources/0002755000000000000000000000000011475313400023062 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/article/src/main/resources/log4j.properties0000644000000000000000000000040511475313400026214 0ustar log4j.rootCategory=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n log4j.logger.org.apache.directory=ERRORlibspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/0002777000000000000000000000000011475315320017767 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/pom.xml0000644000000000000000000000726511475313400021305 0ustar org.springframework.ldap spring-ldap-parent 1.3.1.CI-SNAPSHOT 4.0.0 org.springframework.ldap spring-ldap-odm-sample Simple Spring LDAP ODM Sample A very simple example of using the the Spring LDAP ODM Paul Harvey paul@pauls-place.me.uk Developer 0 org.apache.maven.plugins maven-jar-plugin org.springframework.ldap.odm.sample.SearchForPeople org.apache.maven.plugins maven-compiler-plugin 1.5 1.5 org.apache.maven.plugins maven-surefire-report-plugin always log4j log4j runtime org.springframework.ldap spring-ldap-odm ${version} junit junit jar 4.4 test org.springframework.ldap spring-ldap-test ${version} test org.springframework spring-core org.springframework spring-context commons-logging commons-logging org.springframework.ldap spring-ldap-core ${version} commons-lang commons-lang jar libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/0002755000000000000000000000000011475313400020547 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/0002755000000000000000000000000011475313400021526 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/java/0002755000000000000000000000000011475313400022447 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/java/org/0002755000000000000000000000000011475313400023236 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/java/org/springframework/0002755000000000000000000000000011475313400026456 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/java/org/springframework/ldap/0002755000000000000000000000000011475313400027376 5ustar ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/java/org/springframework/ldap/odm/libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/java/org/springframework/ldap/odm0002755000000000000000000000000011475313400030076 5ustar ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/java/org/springframework/ldap/odm/sample/libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/java/org/springframework/ldap/odm0002755000000000000000000000000011475313400030076 5ustar ././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/java/org/springframework/ldap/odm/sample/test/libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/java/org/springframework/ldap/odm0002755000000000000000000000000011475313400030076 5ustar ././@LongLink0000000000000000000000000000021200000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/java/org/springframework/ldap/odm/sample/test/TestSearchForPeople.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/java/org/springframework/ldap/odm0000644000000000000000000000567711475313400030115 0ustar package org.springframework.ldap.odm.sample.test; import static org.junit.Assert.assertEquals; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.core.io.ClassPathResource; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.support.LdapContextSource; import org.springframework.ldap.odm.sample.SearchForPeople; import org.springframework.ldap.test.LdapTestUtils; public class TestSearchForPeople { // Base DN for test data private static final DistinguishedName baseName = new DistinguishedName("o=Whoniverse"); private static final String PRINCIPAL="uid=admin,ou=system"; private static final String CREDENTIALS="secret"; // This port MUST be free on local host for these unit tests to function. private static int PORT=10389; @BeforeClass public static void setUpClass() throws Exception { // Start an LDAP server and import test data LdapTestUtils.startApacheDirectoryServer(PORT, baseName.toString(), "odm-test", PRINCIPAL, CREDENTIALS, null); } @AfterClass public static void tearDownClass() throws Exception { LdapTestUtils.destroyApacheDirectoryServer(PRINCIPAL, CREDENTIALS); } @Before public void setUp() throws Exception { // Bind to the directory LdapContextSource contextSource = new LdapContextSource(); contextSource.setUrl("ldap://127.0.0.1:" + PORT); contextSource.setUserDn(""); contextSource.setPassword(""); contextSource.setPooled(false); contextSource.afterPropertiesSet(); // Create the Sprint LDAP template LdapTemplate template = new LdapTemplate(contextSource); // Clear out any old data - and load the test data LdapTestUtils.cleanAndSetup(template.getContextSource(), baseName, new ClassPathResource("testdata.ldif")); } @After public void tearDown() { } // Very simple test - mainly just to exercise the code and to // ensure we get representative test coverage @Test public void runSample() throws Exception { PrintStream originalOut=System.out; try { ByteArrayOutputStream output = new ByteArrayOutputStream(); System.setOut(new PrintStream(output)); SearchForPeople.main(null); assertEquals("dn=cn=Bramble Harvey,ou=Doctors,o=Whoniverse | objectClass=[person, top] | cn=[Bramble Harvey] | sn=[Harvey] | description=[Really not a Doctor] | userPassword=[] | telephoneNumber=[22] | seeAlso=[]", output.toString().trim()); } finally { System.setOut(originalOut); } } } libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/resources/0002755000000000000000000000000011475313400023540 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/test/resources/testdata.ldif0000644000000000000000000000505411475313400026213 0ustar dn: ou=Enemies,o=Whoniverse objectClass: organizationalUnit objectClass: top ou: Blizzard dn: ou=Assistants,o=Whoniverse objectClass: organizationalUnit objectClass: top ou: Blizzard dn: ou=Doctors,o=Whoniverse objectClass: organizationalUnit objectClass: top ou: NCSoft dn: cn=William Hartnell,ou=Doctors,o=Whoniverse objectClass: person objectClass: inetorgperson objectclass: organizationalperson objectClass: top cn: William Hartnell description: First Doctor description: Grumpy sn: Hartnell telephonenumber: 1 dn: cn=Patrick Troughton,ou=Doctors,o=Whoniverse objectClass: person objectClass: inetorgperson objectclass: organizationalperson objectClass: top cn: Patrick Troughton description: Second Doctor description:Clown sn: Troughton telephonenumber: 2 dn: cn=Jon Pertwee,ou=Doctors,o=Whoniverse objectClass: person objectClass: inetorgperson objectclass: organizationalperson objectClass: top cn: Jon Pertwee description: Third Doctor description: Dandy sn: Pertwee telephonenumber: 3 dn: cn=Tom Baker,ou=Doctors,o=Whoniverse objectClass: person objectClass: inetorgperson objectclass: organizationalperson objectClass: top cn: Tom Baker description: Fourth Doctor description: The one and only! sn: Baker telephonenumber: 4 dn: cn=Peter Davison,ou=Doctors,o=Whoniverse objectClass: person objectClass: inetorgperson objectclass: organizationalperson objectClass: top cn: Peter Davison description: Fifth Doctor sn: Davison telephonenumber: 5 dn: cn=Paul Harvey,ou=Doctors,o=Whoniverse objectClass: person objectClass: inetorgperson objectclass: organizationalperson objectClass: top objectClass: userSecurityInformation cn: Paul Harvey description: Not a Doctor sn: Harvey telephonenumber: 11 dn: cn=Bramble Harvey,ou=Doctors,o=Whoniverse objectClass: person objectClass: top cn: Bramble description: Really not a Doctor sn: Harvey telephonenumber: 22 dn: cn=Davros,ou=Enemies,o=Whoniverse objectClass: person objectClass: inetorgperson objectclass: organizationalperson objectClass: top cn: Davros description: Creator of the Daleks description: Kaled head scientist sn: Unknown dn: cn=Daleks,ou=Enemies,o=Whoniverse objectClass: person objectClass: inetorgperson objectclass: organizationalperson objectClass: top cn: Daleks description: The Doctor's greatest foe sn: NA dn: cn=Master,ou=Enemies,o=Whoniverse objectClass: person objectClass: inetorgperson objectclass: organizationalperson objectClass: top cn: Master description: An evil Time Lord sn: Unknown libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/0002755000000000000000000000000011475313400021473 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/java/0002755000000000000000000000000011475313400022414 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/java/org/0002755000000000000000000000000011475313400023203 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/java/org/springframework/0002755000000000000000000000000011475313400026423 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/java/org/springframework/ldap/0002755000000000000000000000000011475313400027343 5ustar ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/java/org/springframework/ldap/odm/libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/java/org/springframework/ldap/odm0002755000000000000000000000000011475313400030043 5ustar ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/java/org/springframework/ldap/odm/sample/libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/java/org/springframework/ldap/odm0002755000000000000000000000000011475313400030043 5ustar ././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/java/org/springframework/ldap/odm/sample/SearchForPeople.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/java/org/springframework/ldap/odm0000644000000000000000000000272111475313400030045 0ustar package org.springframework.ldap.odm.sample; import java.util.List; import javax.naming.directory.SearchControls; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.odm.core.OdmManager; // A very simple example - just showing how little code you actually need to write // when using Spring LDAP ODM public class SearchForPeople { private static final SearchControls searchControls = new SearchControls(SearchControls.SUBTREE_SCOPE, 100, 10000, null, true, false); private static final DistinguishedName baseDn = new DistinguishedName("o=Whoniverse"); private static void print(List personList) { for (SimplePerson person : personList) { System.out.println(person); } } public static void main(String[] argv) { ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "spring.xml" }); // Grab the OdmManager wired by Spring OdmManager odmManager = (OdmManager)context.getBean("odmManager"); // Find people with a surname of Harvey List searchResults = odmManager.search(SimplePerson.class, baseDn, "sn=Harvey", searchControls); // Print the results print(searchResults); } } ././@LongLink0000000000000000000000000000017600000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/java/org/springframework/ldap/odm/sample/package-info.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/java/org/springframework/ldap/odm0000644000000000000000000000025111475313400030041 0ustar /** * A very simple example of the use of Spring ODM. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ package org.springframework.ldap.odm.sample;././@LongLink0000000000000000000000000000017600000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/java/org/springframework/ldap/odm/sample/SimplePerson.javalibspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/java/org/springframework/ldap/odm0000644000000000000000000001721011475313400030044 0ustar package org.springframework.ldap.odm.sample; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.HashSet; import java.util.ArrayList; import javax.naming.Name; import static org.springframework.ldap.odm.annotations.Attribute.*; import org.springframework.ldap.odm.annotations.Attribute; import org.springframework.ldap.odm.annotations.Entry; import org.springframework.ldap.odm.annotations.Id; /** * Automatically generated to represent the LDAP object classes * "person", "top". */ @Entry(objectClasses={"person", "top"}) public final class SimplePerson { @Id private Name dn; @Attribute(name="objectClass", syntax="1.3.6.1.4.1.1466.115.121.1.38") private List objectClass=new ArrayList(); @Attribute(name="cn", syntax="1.3.6.1.4.1.1466.115.121.1.15") private List cn=new ArrayList(); @Attribute(name="sn", syntax="1.3.6.1.4.1.1466.115.121.1.15") private List sn=new ArrayList(); @Attribute(name="description", syntax="1.3.6.1.4.1.1466.115.121.1.15") private List description=new ArrayList(); @Attribute(name="userPassword", syntax="1.3.6.1.4.1.1466.115.121.1.40", type=Type.BINARY) private List userPassword=new ArrayList(); @Attribute(name="telephoneNumber", syntax="1.3.6.1.4.1.1466.115.121.1.50") private List telephoneNumber=new ArrayList(); @Attribute(name="seeAlso", syntax="1.3.6.1.4.1.1466.115.121.1.12") private List seeAlso=new ArrayList(); public Name getDn() { return dn; } public void setDn(Name dn) { this.dn=dn; } public Iterator getObjectClassIterator() { return Collections.unmodifiableList(objectClass).iterator(); } public void addCn(String cn) { this.cn.add(cn); } public void removeCn(String cn) { this.cn.remove(cn); } public Iterator getCnIterator() { return cn.iterator(); } public void addSn(String sn) { this.sn.add(sn); } public void removeSn(String sn) { this.sn.remove(sn); } public Iterator getSnIterator() { return sn.iterator(); } public void addDescription(String description) { this.description.add(description); } public void removeDescription(String description) { this.description.remove(description); } public Iterator getDescriptionIterator() { return description.iterator(); } public void addUserPassword(byte[] userPassword) { this.userPassword.add(userPassword); } public void removeUserPassword(byte[] userPassword) { this.userPassword.remove(userPassword); } public Iterator getUserPasswordIterator() { return userPassword.iterator(); } public void addTelephoneNumber(String telephoneNumber) { this.telephoneNumber.add(telephoneNumber); } public void removeTelephoneNumber(String telephoneNumber) { this.telephoneNumber.remove(telephoneNumber); } public Iterator getTelephoneNumberIterator() { return telephoneNumber.iterator(); } public void addSeeAlso(String seeAlso) { this.seeAlso.add(seeAlso); } public void removeSeeAlso(String seeAlso) { this.seeAlso.remove(seeAlso); } public Iterator getSeeAlsoIterator() { return seeAlso.iterator(); } @Override public String toString() { StringBuilder result=new StringBuilder(); result.append(String.format("dn=%1$s", dn)); result.append(String.format(" | objectClass=%1$s", objectClass)); result.append(String.format(" | cn=%1$s", cn)); result.append(String.format(" | sn=%1$s", sn)); result.append(String.format(" | description=%1$s", description)); result.append(String.format(" | userPassword=%1$s", userPassword)); result.append(String.format(" | telephoneNumber=%1$s", telephoneNumber)); result.append(String.format(" | seeAlso=%1$s", seeAlso)); return result.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((dn == null) ? 0 : dn.hashCode()); result = prime * result + ((objectClass == null) ? 0 : (new HashSet(objectClass)).hashCode()); result = prime * result + ((cn == null) ? 0 : (new HashSet(cn)).hashCode()); result = prime * result + ((sn == null) ? 0 : (new HashSet(sn)).hashCode()); result = prime * result + ((description == null) ? 0 : (new HashSet(description)).hashCode()); result = prime * result + ((userPassword == null) ? 0 : (new HashSet(userPassword)).hashCode()); result = prime * result + ((telephoneNumber == null) ? 0 : (new HashSet(telephoneNumber)).hashCode()); result = prime * result + ((seeAlso == null) ? 0 : (new HashSet(seeAlso)).hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; SimplePerson other = (SimplePerson) obj; if (dn == null) { if (other.dn != null) return false; } else if (!dn.equals(other.dn)) return false; if (objectClass == null) { if (other.objectClass != null) return false; } else if (!(new HashSet(objectClass)).equals(new HashSet(other.objectClass))) return false; if (cn == null) { if (other.cn != null) return false; } else if (!(new HashSet(cn)).equals(new HashSet(other.cn))) return false; if (sn == null) { if (other.sn != null) return false; } else if (!(new HashSet(sn)).equals(new HashSet(other.sn))) return false; if (description == null) { if (other.description != null) return false; } else if (!(new HashSet(description)).equals(new HashSet(other.description))) return false; if (userPassword == null) { if (other.userPassword != null) return false; } else if (!(new HashSet(userPassword)).equals(new HashSet(other.userPassword))) return false; if (telephoneNumber == null) { if (other.telephoneNumber != null) return false; } else if (!(new HashSet(telephoneNumber)).equals(new HashSet(other.telephoneNumber))) return false; if (seeAlso == null) { if (other.seeAlso != null) return false; } else if (!(new HashSet(seeAlso)).equals(new HashSet(other.seeAlso))) return false; return true; } } libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/resources/0002755000000000000000000000000011475313400023505 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/resources/log4j.properties0000644000000000000000000000122111475313400026634 0ustar log4j.rootLogger=error, stdout log4j.logger.org.springframework.ldap.odm=error log4j.logger.org.springframework=error # Messages to the console log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n # Message to a log file log4j.appender.log=org.apache.log4j.RollingFileAppender log4j.appender.log.File=jndi.log log4j.appender.log.MaxFileSize=100KB log4j.appender.log.MaxBackupIndex=1 log4j.appender.log.layout=org.apache.log4j.PatternLayout log4j.appender.log.layout.ConversionPattern=%p %t %c - %m%n libspring-ldap-java-1.3.1.RELEASE.orig/samples/simple-odm/src/main/resources/spring.xml0000644000000000000000000001144011475313400025527 0ustar java.lang.String java.lang.Byte java.lang.Short java.lang.Integer java.lang.Long java.lang.Float java.lang.Double java.lang.Boolean java.lang.Byte java.lang.Short java.lang.Integer java.lang.Long java.lang.Float java.lang.Double java.lang.Boolean java.lang.String org.springframework.ldap.odm.sample.SimplePerson libspring-ldap-java-1.3.1.RELEASE.orig/readme.txt0000644000000000000000000001543711475315306016263 0ustar Spring LDAP 1.3.1 (Nov 2010) ---------------------------- http://www.springframework.org/ldap http://forum.springframework.org/forumdisplay.php?f=40 1. INTRODUCTION Spring LDAP is a library to simplify LDAP programming in Java, built on the same principles as Spring Jdbc. The LdapTemplate class encapsulates all the plumbing work involved in traditional LDAP programming, such as creating, looping through NamingEnumerations, handling Exceptions and cleaning up resources. This leaves the programmer to handle the important stuff - where to find data (DNs and Filters) and what do do with it (map to and from domain objects, bind, modify, unbind, etc.), in the same way that JdbcTemplate relieves the programmer of all but the actual SQL and how the data maps to the domain model. In addition to this, Spring LDAP provides Exception translation from NamingExceptions to an unchecked exception hirearchy, as well as several utilities for working with filters, LDAP paths and Attributes. As of version 1.2, support for client-side compensating transaction is provided, as well as Java 5 generics support with the SimpleLdapTemplate. As of version 1.3.1, there is support for LDIF parsing and Object-Directory Mapping (ODM). See changelog.txt for detailed information on the changes included in the current release. 2. RELEASE INFO Spring LDAP requires J2SE 1.4 and Spring 2.x for running. J2SE 1.5 is required for building. J2EE 1.4 (Servlet 2.3, JSP 1.2) is required for running the example. "." contains Spring LDAP distribution units (jars and source zip archives), readme, and copyright "dist" contains the Spring LDAP distribution "dist/modules" contains the Spring LDAP modules The -with-dependencies distribution contains the following additional content: "dist/module-sources" contains the Spring LDAP modules "docs" contains the Spring LDAP reference manual and API Javadocs "samples" contains buildable Spring LDAP sample application sources "lib" contains the Spring LDAP dependencies Nightly builds are available for download from: http://static.springframework.org/spring-ldap/downloads/1.3-snapshot-download.php Spring LDAP is released under the terms of the Apache Software License (see license.txt). 3. DISTRIBUTION JAR FILES The following distinct jar files are included in the distribution. This list specifies the respective contents and third-party dependencies. * spring-ldap-core-1.3.1.RELEASE.jar - Contents: The Spring LDAP library - Dependencies: Commons Logging, Commons Lang, Commons Pool, spring-beans, spring-core, spring-context, spring-jdbc, spring-tx, ldapbp * spring-ldap-core-tiger-1.3.1.RELEASE.jar - Contents: The Spring LDAP Java 5 support library - Dependencies: Commons Logging, Commons Lang, Commons Pool, spring-beans, spring-core, spring-context, spring-jdbc, spring-tx, ldapbp * spring-ldap-test-1.3.1.RELEASE.jar - Contents: Support classes that helps LDAP with integration testing. - Dependencies: Commons Logging, Commons Lang, Commons Pool, spring-beans, spring-core, spring-context, spring-jdbc, spring-tx, ldapbp * spring-ldap-ldif-core-1.3.1.RELEASE.jar - Contents: The Spring LDAP LDIF parsing library. - Dependencies: Commons Logging, Commons Lang, spring-beans, spring-core, spring-ldap-core * spring-ldap-ldif-batch-1.3.1.RELEASE.jar - Contents: The Spring Batch integration layer for the LDIF parsing library. - Dependencies: Commons Logging, spring-batch, spring-beans, spring-core, spring-ldap-core, spring-ldap-ldif-core * spring-ldap-odm-1.3.1.RELEASE.jar - Contents: The Object-Directory Mapping (ODM) framework. - Dependencies: Commons Logging, Commons CLI, spring-beans, spring-ldap-core, spring-ldap-core-tiger 4. MAVEN USERS All major releases of this library are available in the central Maven repository. Note that the artifacts have changed names between the 1.2.x and 1.3 releases: spring-ldap is now spring-ldap-core spring-ldap-tiger is now spring-ldap-core-tiger This means that in order to use the latest release (1.3.1.RELEASE), you need to include the following dependencies: org.springframework.ldap spring-ldap-core 1.3.1.RELEASE For Java 1.5 support: org.springframework.ldap spring-ldap-core-tiger 1.3.1.RELEASE Milestone releases (such as release candidates) are available from the Spring framework milestone repo: spring-milestone Spring Portfolio Milestone Repository http://s3.amazonaws.com/maven.springframework.org/milestone This means that in order to use a milestone or release candidate, you need to specify the repository above and include the following dependencies: org.springframework.ldap spring-ldap-core 2.0.0.RC1 For Java 1.5 support: org.springframework.ldap spring-ldap-core-tiger 2.0.0.RC1 Nighly builds are published to the snapshot repository: spring-snapshot Spring Portfolio Snapshot Repository http://s3.amazonaws.com/maven.springframework.org/snapshot org.springframework.ldap spring-ldap-core 2.0.0.CI-SNAPSHOT For Java 1.5 support: org.springframework.ldap spring-ldap-core-tiger 2.0.0.CI-SNAPSHOT 5. WHERE TO START This distribution contains documentation and a sample application illustrating the features of Spring LDAP. A great way to get started is to review and run the sample application, supplementing with reference manual material as needed. You will require Maven 2, which can be downloaded from http://maven.apache.org/, for building Spring LDAP. To build deployable .war files for all samples, simply access the "samples" directory and execute the "mvn package" command. Alternatively, go to a sample and run "mvn jetty:run" to run the sample directly in a Jetty 6 Web container. 6. ADDITIONAL RESOURCES The Spring LDAP homepage can be found at the following URL: http://www.springframework.org/ldap Spring LDAP support forums are located at: http://forum.springframework.org/forumdisplay.php?f=40 The Spring Framework portal is located at: http://www.springframework.org libspring-ldap-java-1.3.1.RELEASE.orig/dist/0002777000000000000000000000000011475315320015220 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/0002777000000000000000000000000011475315322020170 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/0002755000000000000000000000000011475313400024372 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/0002755000000000000000000000000011475313400025161 5ustar ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframework/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframewor0002755000000000000000000000000011475313400030147 5ustar ././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframework/ldap/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframewor0002755000000000000000000000000011475313400030147 5ustar ././@LongLink0000000000000000000000000000016100000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframework/ldap/ldif/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframewor0002755000000000000000000000000011475313400030147 5ustar ././@LongLink0000000000000000000000000000016700000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframework/ldap/ldif/batch/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframewor0002755000000000000000000000000011475313400030147 5ustar ././@LongLink0000000000000000000000000000020300000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframework/ldap/ldif/batch/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframewor0000644000000000000000000000021511475313400030145 0ustar This package contains the classes required for using the LdifParser with the Spring Batch framework. ././@LongLink0000000000000000000000000000021200000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframework/ldap/ldif/batch/LdifAggregator.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframewor0000644000000000000000000000167511475313400030160 0ustar /** * */ package org.springframework.ldap.ldif.batch; import org.springframework.batch.item.file.transform.LineAggregator; import org.springframework.ldap.core.LdapAttributes; /** * The {@link LdifAggregator LdifAggregator} object is an implementation of the {@link org.springframework.batch.item.file.transform.LineAggregator LineAggregator} * interface for use with a {@link org.springframework.batch.item.file.FlatFileItemWriter FlatFileItemWriter} to write LDIF records to a file. * * @author Keith Barlow * */ public class LdifAggregator implements LineAggregator { /** * Returns a {@link java.lang.String String} containing a properly formated LDIF. * * @param item LdapAttributes object to convert to string. * @return string representation of the object LDIF format (in accordance with RFC 2849). */ public String aggregate(LdapAttributes item) { return item.toString(); } } ././@LongLink0000000000000000000000000000021500000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframework/ldap/ldif/batch/MappingLdifReader.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframewor0000644000000000000000000001337711475313400030162 0ustar package org.springframework.ldap.ldif.batch; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.batch.item.file.ResourceAwareItemReaderItemStream; import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; import org.springframework.ldap.core.LdapAttributes; import org.springframework.ldap.ldif.parser.LdifParser; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** * The {@link MappingLdifReader MappingLdifReader} is an adaptation of the {@link org.springframework.batch.item.file.FlatFileItemReader FlatFileItemReader} * built around an {@link LdifParser LdifParser}. It differs from the standard {@link LdifReader LdifReader} in its ability to map * {@link LdapAttributes LdapAttributes} objects to POJOs. *

* The {@link MappingLdifReader MappingLdifReader} requires an {@link RecordMapper RecordMapper} implementation. If mapping * is not required, the {@link LdifReader LdifReader} should be used instead. It simply returns an {@link LdapAttributes LdapAttributes} * object which can be consumed and manipulated as necessary by {@link org.springframework.batch.item.ItemProcessor ItemProcessor} or any * output service. *

* {@link LdifReader LdifReader} usage is mimics that of the FlatFileItemReader for all intensive purposes. Adjustments have been made to * process records instead of lines, however. As such, the {@link #recordsToSkip recordsToSkip} attribute indicates the number of records * from the top of the file that should not be processed. Implementations of the {@link RecordCallbackHandler RecordCallbackHandler} * interface can be used to execute operations on those skipped records. *

* As with the {@link org.springframework.batch.item.file.FlatFileItemReader FlatFileItemReader}, the {@link #strict strict} option * differentiates between whether or not to require the resource to exist before processing. In the case of a value set to false, a warning * is logged instead of an exception being thrown. * * @author Keith Barlow * */ public class MappingLdifReader extends AbstractItemCountingItemStreamItemReader implements ResourceAwareItemReaderItemStream, InitializingBean { private static final Log log = LogFactory.getLog(MappingLdifReader.class); private Resource resource; private LdifParser ldifParser; private int recordCount = 0; private int recordsToSkip = 0; private boolean strict = true; private RecordCallbackHandler skippedRecordsCallback; private RecordMapper recordMapper; public MappingLdifReader() { setName(ClassUtils.getShortName(MappingLdifReader.class)); } /** * In strict mode the reader will throw an exception on * {@link #open(org.springframework.batch.item.ExecutionContext)} if the * input resource does not exist. * @param strict false by default */ public void setStrict(boolean strict) { this.strict = strict; } /** * {@link RecordCallbackHandler RecordCallbackHandler} implementations can be used to take action on skipped records. * * @param skippedRecordsCallback will be called for each one of the initial * skipped lines before any items are read. */ public void setSkippedRecordsCallback(RecordCallbackHandler skippedRecordsCallback) { this.skippedRecordsCallback = skippedRecordsCallback; } /** * Public setter for the number of lines to skip at the start of a file. Can * be used if the file contains a header without useful (column name) * information, and without a comment delimiter at the beginning of the * lines. * * @param recordsToSkip the number of lines to skip */ public void setRecordsToSkip(int recordsToSkip) { this.recordsToSkip = recordsToSkip; } /** * Setter for object mapper. This property is required to be set. * @param recordMapper maps record to an object */ public void setRecordMapper(RecordMapper recordMapper) { this.recordMapper = recordMapper; } @Override protected void doClose() throws Exception { if (ldifParser != null) { ldifParser.close(); } this.recordCount = 0; } @Override protected void doOpen() throws Exception { if (resource == null) throw new IllegalStateException("A resource has not been set."); if (!resource.exists()) { if (strict) { throw new IllegalStateException("Input resource must exist (reader is in 'strict' mode): "+resource); } else { log.warn("Input resource does not exist " + resource.getDescription()); return; } } ldifParser.open(); for (int i = 0; i < recordsToSkip; i++) { LdapAttributes record = ldifParser.getRecord(); if (skippedRecordsCallback != null) { skippedRecordsCallback.handleRecord(record); } } } @Override protected T doRead() throws Exception { LdapAttributes attributes = null; try { if (ldifParser != null) { while (attributes == null && ldifParser.hasMoreRecords()) { attributes = ldifParser.getRecord(); } recordCount++; return recordMapper.mapRecord(attributes); } return null; } catch(Exception ex){ log.error("Parsing error at record " + recordCount + " in resource=" + resource.getDescription() + ", input=[" + attributes + "]", ex); throw ex; } } public void setResource(Resource resource) { this.resource = resource; this.ldifParser = new LdifParser(resource); } public void afterPropertiesSet() throws Exception { Assert.notNull(resource, "A resource is required to parse."); Assert.notNull(ldifParser); } } ././@LongLink0000000000000000000000000000020600000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframework/ldap/ldif/batch/LdifReader.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframewor0000644000000000000000000001305111475313400030147 0ustar package org.springframework.ldap.ldif.batch; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.batch.item.file.ResourceAwareItemReaderItemStream; import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; import org.springframework.ldap.core.LdapAttributes; import org.springframework.ldap.ldif.parser.LdifParser; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** * The {@link LdifReader LdifReader} is an adaptation of the {@link org.springframework.batch.item.file.FlatFileItemReader FlatFileItemReader} * built around an {@link LdifParser LdifParser}. *

* Unlike the {@link org.springframework.batch.item.file.FlatFileItemReader FlatFileItemReader}, the {@link LdifReader LdifReader} * does not require a mapper. Instead, this version of the {@link LdifReader LdifReader} simply returns an {@link LdapAttributes LdapAttributes} * object which can be consumed and manipulated as necessary by {@link org.springframework.batch.item.ItemProcessor ItemProcessor} or any * output service. Alternatively, the {@link RecordMapper RecordMapper} interface can be implemented and set in a * {@link MappingLdifReader MappingLdifReader} to map records to objects for return. *

* {@link LdifReader LdifReader} usage is mimics that of the {@link org.springframework.batch.item.file.FlatFileItemReader FlatFileItemReader} * for all intensive purposes. Adjustments have been made to process records instead of lines, however. As such, the * {@link #recordsToSkip recordsToSkip} attribute indicates the number of records from the top of the file that should not be processed. * Implementations of the {@link RecordCallbackHandler RecordCallbackHandler} interface can be used to execute operations on those skipped records. *

* As with the {@link org.springframework.batch.item.file.FlatFileItemReader FlatFileItemReader}, the {@link #strict strict} option differentiates * between whether or not to require the resource to exist before processing. In the case of a value set to false, a warning is logged instead of * an exception being thrown. * * @author Keith Barlow * */ public class LdifReader extends AbstractItemCountingItemStreamItemReader implements ResourceAwareItemReaderItemStream, InitializingBean { private static final Log log = LogFactory.getLog(LdifReader.class); private Resource resource; private LdifParser ldifParser; private int recordCount = 0; private int recordsToSkip = 0; private boolean strict = true; private RecordCallbackHandler skippedRecordsCallback; public LdifReader() { setName(ClassUtils.getShortName(LdifReader.class)); } /** * In strict mode the reader will throw an exception on * {@link #open(org.springframework.batch.item.ExecutionContext)} if the * input resource does not exist. * @param strict false by default */ public void setStrict(boolean strict) { this.strict = strict; } /** * {@link RecordCallbackHandler RecordCallbackHandler} implementations can be used to take action on skipped records. * * @param skippedRecordsCallback will be called for each one of the initial * skipped lines before any items are read. */ public void setSkippedRecordsCallback(RecordCallbackHandler skippedRecordsCallback) { this.skippedRecordsCallback = skippedRecordsCallback; } /** * Public setter for the number of lines to skip at the start of a file. Can * be used if the file contains a header without useful (column name) * information, and without a comment delimiter at the beginning of the * lines. * * @param recordsToSkip the number of lines to skip */ public void setRecordsToSkip(int recordsToSkip) { this.recordsToSkip = recordsToSkip; } @Override protected void doClose() throws Exception { if (ldifParser != null) { ldifParser.close(); } this.recordCount = 0; } @Override protected void doOpen() throws Exception { if (resource == null) throw new IllegalStateException("A resource has not been set."); if (!resource.exists()) { if (strict) { throw new IllegalStateException("Input resource must exist (reader is in 'strict' mode): "+resource); } else { log.warn("Input resource does not exist " + resource.getDescription()); return; } } ldifParser.open(); for (int i = 0; i < recordsToSkip; i++) { LdapAttributes record = ldifParser.getRecord(); if (skippedRecordsCallback != null) { skippedRecordsCallback.handleRecord(record); } } } @Override protected LdapAttributes doRead() throws Exception { LdapAttributes attributes = null; try { if (ldifParser != null) { while (attributes == null && ldifParser.hasMoreRecords()) { attributes = ldifParser.getRecord(); } recordCount++; } return attributes; } catch(Exception ex){ log.error("Parsing error at record " + recordCount + " in resource=" + resource.getDescription() + ", input=[" + attributes + "]", ex); throw ex; } } public void setResource(Resource resource) { this.resource = resource; this.ldifParser = new LdifParser(resource); } public void afterPropertiesSet() throws Exception { Assert.notNull(resource, "A resource is required to parse."); Assert.notNull(ldifParser); } } ././@LongLink0000000000000000000000000000022100000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframework/ldap/ldif/batch/RecordCallbackHandler.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframewor0000644000000000000000000000077211475313400030155 0ustar /** * */ package org.springframework.ldap.ldif.batch; import org.springframework.ldap.core.LdapAttributes; /** * This interface can be used to operate on skipped records in the {@link LdifReader LdifReader} and the * {@link MappingLdifReader MappingLdifReader}. * * @author Keith Barlow * */ public interface RecordCallbackHandler { /** * Execute operations on the supplied record. * * @param attributes */ void handleRecord(LdapAttributes attributes); } ././@LongLink0000000000000000000000000000021000000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframework/ldap/ldif/batch/RecordMapper.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-batch/org/springframewor0000644000000000000000000000113411475313400030146 0ustar package org.springframework.ldap.ldif.batch; import org.springframework.ldap.core.LdapAttributes; /** * This interface should be implemented to map {@link LdapAttributes LdapAttributes} objects to POJOs. The resulting * implementations can be used in the {@link MappingLdifReader MappingLdifReader}. * * @author Keith Barlow * * @param */ public interface RecordMapper { /** * Maps an {@link LdapAttributes LdapAttributes} object to the specified type. * * @param attributes * @return object of type T */ T mapRecord(LdapAttributes attributes); } libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/0002755000000000000000000000000011475313376023341 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/overview.html0000644000000000000000000000012611475313376026072 0ustar This document is the API specification for the Spring LDAP Framework. libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/0002755000000000000000000000000011475313376024130 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/0002755000000000000000000000000011475313376027350 5ustar ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0002755000000000000000000000000011475313376030211 5ustar ././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/LimitExceededException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000177411475313376030222 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI LimitExceededException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.LimitExceededException */ public class LimitExceededException extends NamingException { public LimitExceededException(javax.naming.LimitExceededException cause) { super(cause); } } ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0002755000000000000000000000000011475313376030211 5ustar ././@LongLink0000000000000000000000000000020400000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/DelegatingDirContext.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000003315111475313376030214 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.pool; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.ModificationItem; import javax.naming.directory.SearchControls; import org.apache.commons.lang.Validate; import org.apache.commons.pool.KeyedObjectPool; import org.springframework.ldap.core.DirContextProxy; import org.springframework.ldap.pool.factory.PoolingContextSource; /** * Used by {@link PoolingContextSource} to wrap a {@link DirContext}, delegating most methods * to the underlying context. This class extends {@link DelegatingContext} which handles returning * the context to the pool on a call to {@link #close()} * * @author Eric Dalquist */ public class DelegatingDirContext extends DelegatingContext implements DirContext, DirContextProxy { private DirContext delegateDirContext; /** * Create a new delegating dir context for the specified pool, context and context type. * * @param keyedObjectPool The pool the delegate context was checked out from. * @param delegateDirContext The dir context to delegate operations to. * @param dirContextType The type of context, used as a key for the pool. * @throws IllegalArgumentException if any of the arguments are null */ public DelegatingDirContext(KeyedObjectPool keyedObjectPool, DirContext delegateDirContext, DirContextType dirContextType) { super(keyedObjectPool, delegateDirContext, dirContextType); Validate.notNull(delegateDirContext, "delegateDirContext may not be null"); this.delegateDirContext = delegateDirContext; } //***** Helper Methods *****// /** * @return The direct delegate for this dir context proxy */ public DirContext getDelegateDirContext() { return this.delegateDirContext; } public Context getDelegateContext() { return this.getDelegateDirContext(); } /** * Recursivley inspect delegates until a non-delegating dir context is found. * * @return The innermost (real) DirContext that is being delegated to. */ public DirContext getInnermostDelegateDirContext() { final DirContext delegateDirContext = this.getDelegateDirContext(); if (delegateDirContext instanceof DelegatingDirContext) { return ((DelegatingDirContext)delegateDirContext).getInnermostDelegateDirContext(); } return delegateDirContext; } protected void assertOpen() throws NamingException { if (this.delegateDirContext == null) { throw new NamingException("DirContext is closed."); } super.assertOpen(); } //***** Object methods *****// /** * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof DirContext)) { return false; } final DirContext thisDirContext = this.getInnermostDelegateDirContext(); DirContext otherDirContext = (DirContext)obj; if (otherDirContext instanceof DelegatingDirContext) { otherDirContext = ((DelegatingDirContext)otherDirContext).getInnermostDelegateDirContext(); } return thisDirContext == otherDirContext || (thisDirContext != null && thisDirContext.equals(otherDirContext)); } /** * @see java.lang.Object#hashCode() */ public int hashCode() { final DirContext context = this.getInnermostDelegateDirContext(); return (context != null ? context.hashCode() : 0); } /** * @see java.lang.Object#toString() */ public String toString() { final DirContext context = this.getInnermostDelegateDirContext(); return (context != null ? context.toString() : "DirContext is closed"); } //***** DirContextProxy Interface Methods *****// /* (non-Javadoc) * @see org.springframework.ldap.core.DirContextProxy#getTargetContext() */ public DirContext getTargetContext() { return this.getInnermostDelegateDirContext(); } //***** DirContext Interface Delegates *****// /** * @see javax.naming.directory.DirContext#bind(javax.naming.Name, java.lang.Object, javax.naming.directory.Attributes) */ public void bind(Name name, Object obj, Attributes attrs) throws NamingException { this.assertOpen(); this.getDelegateDirContext().bind(name, obj, attrs); } /** * @see javax.naming.directory.DirContext#bind(java.lang.String, java.lang.Object, javax.naming.directory.Attributes) */ public void bind(String name, Object obj, Attributes attrs) throws NamingException { this.assertOpen(); this.getDelegateDirContext().bind(name, obj, attrs); } /** * @see javax.naming.directory.DirContext#createSubcontext(javax.naming.Name, javax.naming.directory.Attributes) */ public DirContext createSubcontext(Name name, Attributes attrs) throws NamingException { throw new UnsupportedOperationException("Cannot call createSubcontext on a pooled context"); } /** * @see javax.naming.directory.DirContext#createSubcontext(java.lang.String, javax.naming.directory.Attributes) */ public DirContext createSubcontext(String name, Attributes attrs) throws NamingException { throw new UnsupportedOperationException("Cannot call createSubcontext on a pooled context"); } /** * @see javax.naming.directory.DirContext#getAttributes(javax.naming.Name, java.lang.String[]) */ public Attributes getAttributes(Name name, String[] attrIds) throws NamingException { this.assertOpen(); return this.getDelegateDirContext().getAttributes(name, attrIds); } /** * @see javax.naming.directory.DirContext#getAttributes(javax.naming.Name) */ public Attributes getAttributes(Name name) throws NamingException { this.assertOpen(); return this.getDelegateDirContext().getAttributes(name); } /** * @see javax.naming.directory.DirContext#getAttributes(java.lang.String, java.lang.String[]) */ public Attributes getAttributes(String name, String[] attrIds) throws NamingException { this.assertOpen(); return this.getDelegateDirContext().getAttributes(name, attrIds); } /** * @see javax.naming.directory.DirContext#getAttributes(java.lang.String) */ public Attributes getAttributes(String name) throws NamingException { this.assertOpen(); return this.getDelegateDirContext().getAttributes(name); } /** * @see javax.naming.directory.DirContext#getSchema(javax.naming.Name) */ public DirContext getSchema(Name name) throws NamingException { throw new UnsupportedOperationException("Cannot call getSchema on a pooled context"); } /** * @see javax.naming.directory.DirContext#getSchema(java.lang.String) */ public DirContext getSchema(String name) throws NamingException { throw new UnsupportedOperationException("Cannot call getSchema on a pooled context"); } /** * @see javax.naming.directory.DirContext#getSchemaClassDefinition(javax.naming.Name) */ public DirContext getSchemaClassDefinition(Name name) throws NamingException { throw new UnsupportedOperationException("Cannot call getSchemaClassDefinition on a pooled context"); } /** * @see javax.naming.directory.DirContext#getSchemaClassDefinition(java.lang.String) */ public DirContext getSchemaClassDefinition(String name) throws NamingException { throw new UnsupportedOperationException("Cannot call getSchemaClassDefinition on a pooled context"); } /** * @see javax.naming.directory.DirContext#modifyAttributes(javax.naming.Name, int, javax.naming.directory.Attributes) */ public void modifyAttributes(Name name, int mod_op, Attributes attrs) throws NamingException { this.assertOpen(); this.getDelegateDirContext().modifyAttributes(name, mod_op, attrs); } /** * @see javax.naming.directory.DirContext#modifyAttributes(javax.naming.Name, javax.naming.directory.ModificationItem[]) */ public void modifyAttributes(Name name, ModificationItem[] mods) throws NamingException { this.assertOpen(); this.getDelegateDirContext().modifyAttributes(name, mods); } /** * @see javax.naming.directory.DirContext#modifyAttributes(java.lang.String, int, javax.naming.directory.Attributes) */ public void modifyAttributes(String name, int mod_op, Attributes attrs) throws NamingException { this.assertOpen(); this.getDelegateDirContext().modifyAttributes(name, mod_op, attrs); } /** * @see javax.naming.directory.DirContext#modifyAttributes(java.lang.String, javax.naming.directory.ModificationItem[]) */ public void modifyAttributes(String name, ModificationItem[] mods) throws NamingException { this.assertOpen(); this.getDelegateDirContext().modifyAttributes(name, mods); } /** * @see javax.naming.directory.DirContext#rebind(javax.naming.Name, java.lang.Object, javax.naming.directory.Attributes) */ public void rebind(Name name, Object obj, Attributes attrs) throws NamingException { this.assertOpen(); this.getDelegateDirContext().rebind(name, obj, attrs); } /** * @see javax.naming.directory.DirContext#rebind(java.lang.String, java.lang.Object, javax.naming.directory.Attributes) */ public void rebind(String name, Object obj, Attributes attrs) throws NamingException { this.assertOpen(); this.getDelegateDirContext().rebind(name, obj, attrs); } /** * @see javax.naming.directory.DirContext#search(javax.naming.Name, javax.naming.directory.Attributes, java.lang.String[]) */ public NamingEnumeration search(Name name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException { this.assertOpen(); return this.getDelegateDirContext().search(name, matchingAttributes, attributesToReturn); } /** * @see javax.naming.directory.DirContext#search(javax.naming.Name, javax.naming.directory.Attributes) */ public NamingEnumeration search(Name name, Attributes matchingAttributes) throws NamingException { this.assertOpen(); return this.getDelegateDirContext().search(name, matchingAttributes); } /** * @see javax.naming.directory.DirContext#search(javax.naming.Name, java.lang.String, java.lang.Object[], javax.naming.directory.SearchControls) */ public NamingEnumeration search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException { this.assertOpen(); return this.getDelegateDirContext().search(name, filterExpr, filterArgs, cons); } /** * @see javax.naming.directory.DirContext#search(javax.naming.Name, java.lang.String, javax.naming.directory.SearchControls) */ public NamingEnumeration search(Name name, String filter, SearchControls cons) throws NamingException { this.assertOpen(); return this.getDelegateDirContext().search(name, filter, cons); } /** * @see javax.naming.directory.DirContext#search(java.lang.String, javax.naming.directory.Attributes, java.lang.String[]) */ public NamingEnumeration search(String name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException { this.assertOpen(); return this.getDelegateDirContext().search(name, matchingAttributes, attributesToReturn); } /** * @see javax.naming.directory.DirContext#search(java.lang.String, javax.naming.directory.Attributes) */ public NamingEnumeration search(String name, Attributes matchingAttributes) throws NamingException { this.assertOpen(); return this.getDelegateDirContext().search(name, matchingAttributes); } /** * @see javax.naming.directory.DirContext#search(java.lang.String, java.lang.String, java.lang.Object[], javax.naming.directory.SearchControls) */ public NamingEnumeration search(String name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException { this.assertOpen(); return this.getDelegateDirContext().search(name, filterExpr, filterArgs, cons); } /** * @see javax.naming.directory.DirContext#search(java.lang.String, java.lang.String, javax.naming.directory.SearchControls) */ public NamingEnumeration search(String name, String filter, SearchControls cons) throws NamingException { this.assertOpen(); return this.getDelegateDirContext().search(name, filter, cons); } /** * @see DelegatingContext#close() */ public void close() throws NamingException { if (this.delegateDirContext == null) { return; } super.close(); this.delegateDirContext = null; } } ././@LongLink0000000000000000000000000000016700000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000011511475313376030206 0ustar Base classes for the pooling library. ././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/DelegatingContext.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000003030111475313376030206 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.pool; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.NameParser; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import org.apache.commons.lang.Validate; import org.apache.commons.pool.KeyedObjectPool; import org.springframework.ldap.pool.factory.PoolingContextSource; /** * Used by {@link PoolingContextSource} to wrap a {@link Context}, delegating most methods * to the underlying context, retains a reference to the pool the context was checked out * from and returns itself to the pool when {@link #close()} is called. * * @author Eric Dalquist */ public class DelegatingContext implements Context { private KeyedObjectPool keyedObjectPool; private Context delegateContext; private final DirContextType dirContextType; /** * Create a new delegating context for the specified pool, context and context type. * * @param keyedObjectPool The pool the delegate context was checked out from. * @param delegateContext The context to delegate operations to. * @param dirContextType The type of context, used as a key for the pool. * @throws IllegalArgumentException if any of the arguments are null */ public DelegatingContext(KeyedObjectPool keyedObjectPool, Context delegateContext, DirContextType dirContextType) { Validate.notNull(keyedObjectPool, "keyedObjectPool may not be null"); Validate.notNull(delegateContext, "delegateContext may not be null"); Validate.notNull(dirContextType, "dirContextType may not be null"); this.keyedObjectPool = keyedObjectPool; this.delegateContext = delegateContext; this.dirContextType = dirContextType; } //***** Helper Methods *****// /** * @return The direct delegate for this context proxy */ public Context getDelegateContext() { return this.delegateContext; } /** * Recursivley inspect delegates until a non-delegating context is found. * * @return The innermost (real) Context that is being delegated to. */ public Context getInnermostDelegateContext() { final Context delegateContext = this.getDelegateContext(); if (delegateContext instanceof DelegatingContext) { return ((DelegatingContext)delegateContext).getInnermostDelegateContext(); } return delegateContext; } /** * @throws NamingException If the delegate is null, {@link #close()} has been called. */ protected void assertOpen() throws NamingException { if (this.delegateContext == null) { throw new NamingException("Context is closed."); } } //***** Object methods *****// /** * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof Context)) { return false; } final Context thisContext = this.getInnermostDelegateContext(); Context otherContext = (Context)obj; if (otherContext instanceof DelegatingContext) { otherContext = ((DelegatingContext)otherContext).getInnermostDelegateContext(); } return thisContext == otherContext || (thisContext != null && thisContext.equals(otherContext)); } /** * @see java.lang.Object#hashCode() */ public int hashCode() { final Context context = this.getInnermostDelegateContext(); return (context != null ? context.hashCode() : 0); } /** * @see java.lang.Object#toString() */ public String toString() { final Context context = this.getInnermostDelegateContext(); return (context != null ? context.toString() : "Context is closed"); } //***** Context Interface Delegates *****// /** * @see javax.naming.Context#addToEnvironment(java.lang.String, java.lang.Object) */ public Object addToEnvironment(String propName, Object propVal) throws NamingException { throw new UnsupportedOperationException("Cannot call addToEnvironment on a pooled context"); } /** * @see javax.naming.Context#bind(javax.naming.Name, java.lang.Object) */ public void bind(Name name, Object obj) throws NamingException { this.assertOpen(); this.getDelegateContext().bind(name, obj); } /** * @see javax.naming.Context#bind(java.lang.String, java.lang.Object) */ public void bind(String name, Object obj) throws NamingException { this.assertOpen(); this.getDelegateContext().bind(name, obj); } /** * @see javax.naming.Context#close() */ public void close() throws NamingException { final Context context = this.getInnermostDelegateContext(); if (context == null) { return; } //Get a local reference so the member can be nulled earlier this.delegateContext = null; //Return the object to the Pool and then null the pool reference try { this.keyedObjectPool.returnObject(this.dirContextType, context); } catch (Exception e) { final NamingException namingException = new NamingException("Failed to return delegate Context to pool."); namingException.setRootCause(e); throw namingException; } finally { this.keyedObjectPool = null; } } /** * @see javax.naming.Context#composeName(javax.naming.Name, javax.naming.Name) */ public Name composeName(Name name, Name prefix) throws NamingException { this.assertOpen(); return this.getDelegateContext().composeName(name, prefix); } /** * @see javax.naming.Context#composeName(java.lang.String, java.lang.String) */ public String composeName(String name, String prefix) throws NamingException { this.assertOpen(); return this.getDelegateContext().composeName(name, prefix); } /** * @see javax.naming.Context#createSubcontext(javax.naming.Name) */ public Context createSubcontext(Name name) throws NamingException { throw new UnsupportedOperationException("Cannot call createSubcontext on a pooled context"); } /** * @see javax.naming.Context#createSubcontext(java.lang.String) */ public Context createSubcontext(String name) throws NamingException { throw new UnsupportedOperationException("Cannot call createSubcontext on a pooled context"); } /** * @see javax.naming.Context#destroySubcontext(javax.naming.Name) */ public void destroySubcontext(Name name) throws NamingException { throw new UnsupportedOperationException("Cannot call createSubcontext on a pooled context"); } /** * @see javax.naming.Context#destroySubcontext(java.lang.String) */ public void destroySubcontext(String name) throws NamingException { throw new UnsupportedOperationException("Cannot call createSubcontext on a pooled context"); } /** * @see javax.naming.Context#getEnvironment() */ public Hashtable getEnvironment() throws NamingException { this.assertOpen(); return this.getDelegateContext().getEnvironment(); } /** * @see javax.naming.Context#getNameInNamespace() */ public String getNameInNamespace() throws NamingException { this.assertOpen(); return this.getDelegateContext().getNameInNamespace(); } /** * @see javax.naming.Context#getNameParser(javax.naming.Name) */ public NameParser getNameParser(Name name) throws NamingException { this.assertOpen(); return this.getDelegateContext().getNameParser(name); } /** * @see javax.naming.Context#getNameParser(java.lang.String) */ public NameParser getNameParser(String name) throws NamingException { this.assertOpen(); return this.getDelegateContext().getNameParser(name); } /** * @see javax.naming.Context#list(javax.naming.Name) */ public NamingEnumeration list(Name name) throws NamingException { this.assertOpen(); return this.getDelegateContext().list(name); } /** * @see javax.naming.Context#list(java.lang.String) */ public NamingEnumeration list(String name) throws NamingException { this.assertOpen(); return this.getDelegateContext().list(name); } /** * @see javax.naming.Context#listBindings(javax.naming.Name) */ public NamingEnumeration listBindings(Name name) throws NamingException { this.assertOpen(); return this.getDelegateContext().listBindings(name); } /** * @see javax.naming.Context#listBindings(java.lang.String) */ public NamingEnumeration listBindings(String name) throws NamingException { this.assertOpen(); return this.getDelegateContext().listBindings(name); } /** * @see javax.naming.Context#lookup(javax.naming.Name) */ public Object lookup(Name name) throws NamingException { this.assertOpen(); return this.getDelegateContext().lookup(name); } /** * @see javax.naming.Context#lookup(java.lang.String) */ public Object lookup(String name) throws NamingException { this.assertOpen(); return this.getDelegateContext().lookup(name); } /** * @see javax.naming.Context#lookupLink(javax.naming.Name) */ public Object lookupLink(Name name) throws NamingException { this.assertOpen(); return this.getDelegateContext().lookupLink(name); } /** * @see javax.naming.Context#lookupLink(java.lang.String) */ public Object lookupLink(String name) throws NamingException { this.assertOpen(); return this.getDelegateContext().lookupLink(name); } /** * @see javax.naming.Context#rebind(javax.naming.Name, java.lang.Object) */ public void rebind(Name name, Object obj) throws NamingException { this.assertOpen(); this.getDelegateContext().rebind(name, obj); } /** * @see javax.naming.Context#rebind(java.lang.String, java.lang.Object) */ public void rebind(String name, Object obj) throws NamingException { this.assertOpen(); this.getDelegateContext().rebind(name, obj); } /** * @see javax.naming.Context#removeFromEnvironment(java.lang.String) */ public Object removeFromEnvironment(String propName) throws NamingException { throw new UnsupportedOperationException("Cannot call removeFromEnvironment on a pooled context"); } /** * @see javax.naming.Context#rename(javax.naming.Name, javax.naming.Name) */ public void rename(Name oldName, Name newName) throws NamingException { this.assertOpen(); this.getDelegateContext().rename(oldName, newName); } /** * @see javax.naming.Context#rename(java.lang.String, java.lang.String) */ public void rename(String oldName, String newName) throws NamingException { this.assertOpen(); this.getDelegateContext().rename(oldName, newName); } /** * @see javax.naming.Context#unbind(javax.naming.Name) */ public void unbind(Name name) throws NamingException { this.assertOpen(); this.getDelegateContext().unbind(name); } /** * @see javax.naming.Context#unbind(java.lang.String) */ public void unbind(String name) throws NamingException { this.assertOpen(); this.getDelegateContext().unbind(name); } } ././@LongLink0000000000000000000000000000016300000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/factory/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0002755000000000000000000000000011475313376030211 5ustar ././@LongLink0000000000000000000000000000021400000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/factory/PoolingContextSource.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000003161711475313376030221 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.pool.factory; import javax.naming.directory.DirContext; import javax.naming.ldap.LdapContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.pool.impl.GenericKeyedObjectPool; import org.springframework.beans.factory.DisposableBean; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.ldap.NamingException; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.pool.DelegatingDirContext; import org.springframework.ldap.pool.DelegatingLdapContext; import org.springframework.ldap.pool.DirContextType; import org.springframework.ldap.pool.validation.DirContextValidator; /** * A {@link ContextSource} implementation that wraps an object pool and another * {@link ContextSource}. {@link DirContext}s are retrieved from the pool which * maintains them. * * *
*
* Configuration: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Property Description Required Default
contextSource * The {@link ContextSource} to get {@link DirContext}s from for adding to the * pool.Yesnull
dirContextValidator * The {@link DirContextValidator} to use for validating {@link DirContext}s. * Required if any of the test/validate options are enabled.Nonull
minIdle{@link GenericKeyedObjectPool#setMinIdle(int)}No0
maxIdle{@link GenericKeyedObjectPool#setMaxIdle(int)}No8
maxActive{@link GenericKeyedObjectPool#setMaxActive(int)}No8
maxTotal{@link GenericKeyedObjectPool#setMaxTotal(int)}No-1
maxWait{@link GenericKeyedObjectPool#setMaxWait(long)}No-1L
whenExhaustedAction{@link GenericKeyedObjectPool#setWhenExhaustedAction(byte)}No{@link GenericKeyedObjectPool#WHEN_EXHAUSTED_BLOCK}
testOnBorrow{@link GenericKeyedObjectPool#setTestOnBorrow(boolean)}Nofalse
testOnReturn{@link GenericKeyedObjectPool#setTestOnReturn(boolean)}Nofalse
testWhileIdle{@link GenericKeyedObjectPool#setTestWhileIdle(boolean)}Nofalse
timeBetweenEvictionRunsMillis * {@link GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis(long)}No-1L
minEvictableIdleTimeMillis * {@link GenericKeyedObjectPool#setMinEvictableIdleTimeMillis(long)}No1000L * 60L * 30L
numTestsPerEvictionRun * {@link GenericKeyedObjectPool#setNumTestsPerEvictionRun(int)}No3
* * @author Eric Dalquist */ public class PoolingContextSource implements ContextSource, DisposableBean { /** * The logger for this class and sub-classes */ protected final Log logger = LogFactory.getLog(this.getClass()); protected final GenericKeyedObjectPool keyedObjectPool; private final DirContextPoolableObjectFactory dirContextPoolableObjectFactory; /** * Creates a new pooling context source, setting up the DirContext object * factory and generic keyed object pool. */ public PoolingContextSource() { this.dirContextPoolableObjectFactory = new DirContextPoolableObjectFactory(); this.keyedObjectPool = new GenericKeyedObjectPool(); this.keyedObjectPool.setFactory(this.dirContextPoolableObjectFactory); } // ***** Pool Property Configuration *****// /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxActive() */ public int getMaxActive() { return this.keyedObjectPool.getMaxActive(); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxIdle() */ public int getMaxIdle() { return this.keyedObjectPool.getMaxIdle(); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxTotal() */ public int getMaxTotal() { return this.keyedObjectPool.getMaxTotal(); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxWait() */ public long getMaxWait() { return this.keyedObjectPool.getMaxWait(); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMinEvictableIdleTimeMillis() */ public long getMinEvictableIdleTimeMillis() { return this.keyedObjectPool.getMinEvictableIdleTimeMillis(); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMinIdle() */ public int getMinIdle() { return this.keyedObjectPool.getMinIdle(); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumActive() */ public int getNumActive() { return this.keyedObjectPool.getNumActive(); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumIdle() */ public int getNumIdle() { return this.keyedObjectPool.getNumIdle(); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumTestsPerEvictionRun() */ public int getNumTestsPerEvictionRun() { return this.keyedObjectPool.getNumTestsPerEvictionRun(); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestOnBorrow() */ public boolean getTestOnBorrow() { return this.keyedObjectPool.getTestOnBorrow(); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestOnReturn() */ public boolean getTestOnReturn() { return this.keyedObjectPool.getTestOnReturn(); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestWhileIdle() */ public boolean getTestWhileIdle() { return this.keyedObjectPool.getTestWhileIdle(); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis() */ public long getTimeBetweenEvictionRunsMillis() { return this.keyedObjectPool.getTimeBetweenEvictionRunsMillis(); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getWhenExhaustedAction() */ public byte getWhenExhaustedAction() { return this.keyedObjectPool.getWhenExhaustedAction(); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxActive(int) */ public void setMaxActive(int maxActive) { this.keyedObjectPool.setMaxActive(maxActive); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxIdle(int) */ public void setMaxIdle(int maxIdle) { this.keyedObjectPool.setMaxIdle(maxIdle); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxTotal(int) */ public void setMaxTotal(int maxTotal) { this.keyedObjectPool.setMaxTotal(maxTotal); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxWait(long) */ public void setMaxWait(long maxWait) { this.keyedObjectPool.setMaxWait(maxWait); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMinEvictableIdleTimeMillis(long) */ public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { this.keyedObjectPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMinIdle(int) */ public void setMinIdle(int poolSize) { this.keyedObjectPool.setMinIdle(poolSize); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setNumTestsPerEvictionRun(int) */ public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { this.keyedObjectPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestOnBorrow(boolean) */ public void setTestOnBorrow(boolean testOnBorrow) { this.keyedObjectPool.setTestOnBorrow(testOnBorrow); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestOnReturn(boolean) */ public void setTestOnReturn(boolean testOnReturn) { this.keyedObjectPool.setTestOnReturn(testOnReturn); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestWhileIdle(boolean) */ public void setTestWhileIdle(boolean testWhileIdle) { this.keyedObjectPool.setTestWhileIdle(testWhileIdle); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis(long) */ public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) { this.keyedObjectPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); } /** * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setWhenExhaustedAction(byte) */ public void setWhenExhaustedAction(byte whenExhaustedAction) { this.keyedObjectPool.setWhenExhaustedAction(whenExhaustedAction); } // ***** Object Factory Property Configuration *****// /** * @return the contextSource */ public ContextSource getContextSource() { return this.dirContextPoolableObjectFactory.getContextSource(); } /** * @return the dirContextValidator */ public DirContextValidator getDirContextValidator() { return this.dirContextPoolableObjectFactory.getDirContextValidator(); } /** * @param contextSource the contextSource to set * Required */ public void setContextSource(ContextSource contextSource) { this.dirContextPoolableObjectFactory.setContextSource(contextSource); } /** * @param dirContextValidator the dirContextValidator to set * Required */ public void setDirContextValidator(DirContextValidator dirContextValidator) { this.dirContextPoolableObjectFactory.setDirContextValidator(dirContextValidator); } // ***** DisposableBean interface methods *****// /* * (non-Javadoc) * * @see org.springframework.beans.factory.DisposableBean#destroy() */ public void destroy() throws Exception { try { this.keyedObjectPool.close(); } catch (Exception e) { this.logger.warn("An exception occured while closing the underlying pool.", e); } } // ***** ContextSource interface methods *****// /* * @see ContextSource#getReadOnlyContext() */ public DirContext getReadOnlyContext() throws NamingException { return this.getContext(DirContextType.READ_ONLY); } /* * @see ContextSource#getReadWriteContext() */ public DirContext getReadWriteContext() throws NamingException { return this.getContext(DirContextType.READ_WRITE); } /** * Gets a DirContext of the specified type from the keyed object pool. * * @param dirContextType The type of context to return. * @return A wrapped DirContext of the specified type. * @throws DataAccessResourceFailureException If retrieving the object from * the pool throws an exception */ protected DirContext getContext(DirContextType dirContextType) { final DirContext dirContext; try { dirContext = (DirContext) this.keyedObjectPool.borrowObject(dirContextType); } catch (Exception e) { throw new DataAccessResourceFailureException("Failed to borrow DirContext from pool.", e); } if (dirContext instanceof LdapContext) { return new DelegatingLdapContext(this.keyedObjectPool, (LdapContext) dirContext, dirContextType); } return new DelegatingDirContext(this.keyedObjectPool, dirContext, dirContextType); } public DirContext getContext(String principal, String credentials) throws NamingException { throw new UnsupportedOperationException("Not supported for this implementation"); } } ././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/factory/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000011511475313376030206 0ustar Core classes for the pooling library. ././@LongLink0000000000000000000000000000022300000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/factory/MutablePoolingContextSource.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000352211475313376030213 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.pool.factory; import javax.naming.directory.DirContext; import javax.naming.ldap.LdapContext; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.ldap.pool.DelegatingDirContext; import org.springframework.ldap.pool.DirContextType; import org.springframework.ldap.pool.MutableDelegatingLdapContext; /** * A {@link PoolingContextSource} subclass that creates * {@link MutableDelegatingLdapContext} instances. This enables the Spring LDAP * pooling to be used in scenarios that require request controls to be set, such * as paged results. */ public class MutablePoolingContextSource extends PoolingContextSource { protected DirContext getContext(DirContextType dirContextType) { final DirContext dirContext; try { dirContext = (DirContext) this.keyedObjectPool.borrowObject(dirContextType); } catch (Exception e) { throw new DataAccessResourceFailureException("Failed to borrow DirContext from pool.", e); } if (dirContext instanceof LdapContext) { return new MutableDelegatingLdapContext(this.keyedObjectPool, (LdapContext) dirContext, dirContextType); } return new DelegatingDirContext(this.keyedObjectPool, dirContext, dirContextType); } } ././@LongLink0000000000000000000000000000022700000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/factory/DirContextPoolableObjectFactory.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001567311475313376030225 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.pool.factory; import javax.naming.directory.DirContext; import org.apache.commons.lang.Validate; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.pool.BaseKeyedPoolableObjectFactory; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.pool.DirContextType; import org.springframework.ldap.pool.validation.DirContextValidator; /** * Factory that creates {@link DirContext} instances for pooling via a * configured {@link ContextSource}. The {@link DirContext}s are keyed based * on if they are read only or read/write. The expected key type is the * {@link DirContextType} enum. * *
*
* Configuration: * * * * * * * * * * * * * * * * * * *
PropertyDescriptionRequiredDefault
contextSource The {@link ContextSource} to get {@link DirContext}s from * for adding to the pool. Yesnull
dirContextValidator The {@link DirContextValidator} to use to validate * {@link DirContext}s. This is only required if the pool has validation of any * kind turned on. Nonull
* * @author Eric Dalquist eric.dalquist@doit.wisc.edu */ class DirContextPoolableObjectFactory extends BaseKeyedPoolableObjectFactory { /** * Logger for this class and subclasses */ protected final Log logger = LogFactory.getLog(this.getClass()); private ContextSource contextSource; private DirContextValidator dirContextValidator; /** * @return the contextSource */ public ContextSource getContextSource() { return this.contextSource; } /** * @param contextSource * the contextSource to set */ public void setContextSource(ContextSource contextSource) { if (contextSource == null) { throw new IllegalArgumentException("contextSource may not be null"); } this.contextSource = contextSource; } /** * @return the dirContextValidator */ public DirContextValidator getDirContextValidator() { return this.dirContextValidator; } /** * @param dirContextValidator * the dirContextValidator to set */ public void setDirContextValidator(DirContextValidator dirContextValidator) { if (dirContextValidator == null) { throw new IllegalArgumentException( "dirContextValidator may not be null"); } this.dirContextValidator = dirContextValidator; } /** * @see org.apache.commons.pool.BaseKeyedPoolableObjectFactory#makeObject(java.lang.Object) */ public Object makeObject(Object key) throws Exception { Validate.notNull(this.contextSource, "ContextSource may not be null"); Validate.isTrue(key instanceof DirContextType, "key must be a DirContextType"); final DirContextType contextType = (DirContextType) key; if (this.logger.isDebugEnabled()) { this.logger.debug("Creating a new " + contextType + " DirContext"); } if (contextType == DirContextType.READ_WRITE) { final DirContext readWriteContext = this.contextSource .getReadWriteContext(); if (this.logger.isDebugEnabled()) { this.logger.debug("Created new " + DirContextType.READ_WRITE + " DirContext='" + readWriteContext + "'"); } return readWriteContext; } else if (contextType == DirContextType.READ_ONLY) { final DirContext readOnlyContext = this.contextSource .getReadOnlyContext(); if (this.logger.isDebugEnabled()) { this.logger.debug("Created new " + DirContextType.READ_ONLY + " DirContext='" + readOnlyContext + "'"); } return readOnlyContext; } else { throw new IllegalArgumentException("Unrecognized ContextType: " + contextType); } } /** * @see org.apache.commons.pool.BaseKeyedPoolableObjectFactory#validateObject(java.lang.Object, * java.lang.Object) */ public boolean validateObject(Object key, Object obj) { Validate.notNull(this.dirContextValidator, "DirContextValidator may not be null"); Validate.isTrue(key instanceof DirContextType, "key must be a DirContextType"); Validate.isTrue(obj instanceof DirContext, "The Object to validate must be of type '" + DirContext.class + "'"); try { final DirContextType contextType = (DirContextType) key; final DirContext dirContext = (DirContext) obj; return this.dirContextValidator.validateDirContext(contextType, dirContext); } catch (Exception e) { this.logger.warn("Failed to validate '" + obj + "' due to an unexpected exception.", e); return false; } } /** * @see org.apache.commons.pool.BaseKeyedPoolableObjectFactory#destroyObject(java.lang.Object, * java.lang.Object) */ public void destroyObject(Object key, Object obj) throws Exception { Validate.isTrue(obj instanceof DirContext, "The Object to validate must be of type '" + DirContext.class + "'"); try { final DirContext dirContext = (DirContext) obj; if (this.logger.isDebugEnabled()) { this.logger.debug("Closing " + key + " DirContext='" + dirContext + "'"); } dirContext.close(); if (this.logger.isDebugEnabled()) { this.logger.debug("Closed " + key + " DirContext='" + dirContext + "'"); } } catch (Exception e) { this.logger.warn( "An exception occured while closing '" + obj + "'", e); } } } ././@LongLink0000000000000000000000000000016600000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/validation/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0002755000000000000000000000000011475313376030211 5ustar ././@LongLink0000000000000000000000000000020200000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/validation/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000013611475313376030211 0ustar Connection validation support for the pooling library. ././@LongLink0000000000000000000000000000022500000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/validation/DefaultDirContextValidator.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001365411475313376030222 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.pool.validation; import javax.naming.NamingEnumeration; import javax.naming.directory.DirContext; import javax.naming.directory.SearchControls; import org.apache.commons.lang.Validate; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.pool.DirContextType; /** * Default {@link DirContext} validator that executes {@link DirContext#search(String, String, SearchControls)}. The * name, filter and {@link SearchControls} are all configurable. There is no special handling for read only versus * read write {@link DirContext}s. * *
*
* Configuration: * * * * * * * * * * * * * * * * * * * * * * * * * *
PropertyDescriptionRequiredDefault
base * The name parameter to the search method. * No""
filter * The filter parameter to the search method. * No"objectclass=*"
searchControls * The {@link SearchControls} parameter to the search method. * No * {@link SearchControls#setCountLimit(long)} = 1
* {@link SearchControls#setReturningAttributes(String[])} = new String[] { "objectclass" }
* {@link SearchControls#setTimeLimit(int)} = 500 *
* * @author Eric Dalquist */ public class DefaultDirContextValidator implements DirContextValidator { /** * Logger for this class and sub-classes */ protected final Log logger = LogFactory.getLog(this.getClass()); private String base; private String filter; private SearchControls searchControls; /** * Create the default validator, creates {@link SearchControls} with search scope OBJECT_SCOPE, * a countLimit of 1, returningAttributes of objectclass and timeLimit of 500. * The default base is an empty string and the default filter is objectclass=* */ public DefaultDirContextValidator() { this(SearchControls.OBJECT_SCOPE); } /** * Create a validator with all the defaults of the default constructor, but with the search scope set to the * referred value. * * @param searchScope The searchScope to be set in the default SearchControls */ public DefaultDirContextValidator(int searchScope) { this.searchControls = new SearchControls(); this.searchControls.setSearchScope(searchScope); this.searchControls.setCountLimit(1); this.searchControls.setReturningAttributes(new String[] { "objectclass" }); this.searchControls.setTimeLimit(500); this.base = ""; this.filter = "objectclass=*"; } /** * @return the baseName */ public String getBase() { return this.base; } /** * @param base the baseName to set */ public void setBase(String base) { this.base = base; } /** * @return the filter */ public String getFilter() { return this.filter; } /** * @param filter the filter to set */ public void setFilter(String filter) { if (filter == null) { throw new IllegalArgumentException("filter may not be null"); } this.filter = filter; } /** * @return the searchControls */ public SearchControls getSearchControls() { return this.searchControls; } /** * @param searchControls the searchControls to set */ public void setSearchControls(SearchControls searchControls) { if (searchControls == null) { throw new IllegalArgumentException("searchControls may not be null"); } this.searchControls = searchControls; } /** * @see DirContextValidator#validateDirContext(DirContextType, javax.naming.directory.DirContext) */ public boolean validateDirContext(DirContextType contextType, DirContext dirContext) { Validate.notNull(contextType, "contextType may not be null"); Validate.notNull(dirContext, "dirContext may not be null"); try { final NamingEnumeration searchResults = dirContext.search(this.base, this.filter, this.searchControls); if (searchResults.hasMore()) { if (this.logger.isDebugEnabled()) { this.logger.debug("DirContext '" + dirContext + "' passed validation."); } return true; } } catch (Exception e) { this.logger.warn("DirContext '" + dirContext + "' failed validation with an exception.", e); } if (this.logger.isInfoEnabled()) { this.logger.info("DirContext '" + dirContext + "' failed validation."); } return false; } } ././@LongLink0000000000000000000000000000021600000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/validation/DirContextValidator.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000303411475313376030211 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.pool.validation; import javax.naming.directory.DirContext; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.pool.DirContextType; /** * A validator for {@link DirContext}s. * * @author Eric Dalquist */ public interface DirContextValidator { /** * Validates the {@link DirContext}. A valid {@link DirContext} should be able * to answer queries and if applicable write to the directory. * * @param contextType The type of the {@link DirContext}, refers to if {@link ContextSource#getReadOnlyContext()} or {@link ContextSource#getReadWriteContext()} was called to create the {@link DirContext} * @param dirContext The {@link DirContext} to validate. * @return true if the {@link DirContext} operated correctly during validation. */ boolean validateDirContext(DirContextType contextType, DirContext dirContext); } ././@LongLink0000000000000000000000000000020500000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/DelegatingLdapContext.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001536111475313376030217 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.pool; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.ldap.Control; import javax.naming.ldap.ExtendedRequest; import javax.naming.ldap.ExtendedResponse; import javax.naming.ldap.LdapContext; import org.apache.commons.lang.Validate; import org.apache.commons.pool.KeyedObjectPool; import org.springframework.ldap.pool.factory.PoolingContextSource; /** * Used by {@link PoolingContextSource} to wrap a {@link LdapContext}, delegating most methods * to the underlying context. This class extends {@link DelegatingDirContext} which handles returning * the context to the pool on a call to {@link #close()} * * @author Eric Dalquist */ public class DelegatingLdapContext extends DelegatingDirContext implements LdapContext { private LdapContext delegateLdapContext; /** * Create a new delegating ldap context for the specified pool, context and context type. * * @param keyedObjectPool The pool the delegate context was checked out from. * @param delegateLdapContext The ldap context to delegate operations to. * @param dirContextType The type of context, used as a key for the pool. * @throws IllegalArgumentException if any of the arguments are null */ public DelegatingLdapContext(KeyedObjectPool keyedObjectPool, LdapContext delegateLdapContext, DirContextType dirContextType) { super(keyedObjectPool, delegateLdapContext, dirContextType); Validate.notNull(delegateLdapContext, "delegateLdapContext may not be null"); this.delegateLdapContext = delegateLdapContext; } //***** Helper Methods *****// /** * @return The direct delegate for this ldap context proxy */ public LdapContext getDelegateLdapContext() { return this.delegateLdapContext; } // cannot return subtype in overridden method unless Java5 public DirContext getDelegateDirContext() { return this.getDelegateLdapContext(); } /** * Recursivley inspect delegates until a non-delegating ldap context is found. * * @return The innermost (real) DirContext that is being delegated to. */ public LdapContext getInnermostDelegateLdapContext() { final LdapContext delegateLdapContext = this.getDelegateLdapContext(); if (delegateLdapContext instanceof DelegatingLdapContext) { return ((DelegatingLdapContext)delegateLdapContext).getInnermostDelegateLdapContext(); } return delegateLdapContext; } protected void assertOpen() throws NamingException { if (this.delegateLdapContext == null) { throw new NamingException("LdapContext is closed."); } super.assertOpen(); } //***** Object methods *****// /** * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof LdapContext)) { return false; } final LdapContext thisLdapContext = this.getInnermostDelegateLdapContext(); LdapContext otherLdapContext = (LdapContext)obj; if (otherLdapContext instanceof DelegatingLdapContext) { otherLdapContext = ((DelegatingLdapContext)otherLdapContext).getInnermostDelegateLdapContext(); } return thisLdapContext == otherLdapContext || (thisLdapContext != null && thisLdapContext.equals(otherLdapContext)); } /** * @see java.lang.Object#hashCode() */ public int hashCode() { final LdapContext context = this.getInnermostDelegateLdapContext(); return (context != null ? context.hashCode() : 0); } /** * @see java.lang.Object#toString() */ public String toString() { final LdapContext context = this.getInnermostDelegateLdapContext(); return (context != null ? context.toString() : "LdapContext is closed"); } //***** LdapContext Interface Delegates *****// /** * @see javax.naming.ldap.LdapContext#extendedOperation(javax.naming.ldap.ExtendedRequest) */ public ExtendedResponse extendedOperation(ExtendedRequest request) throws NamingException { this.assertOpen(); return this.getDelegateLdapContext().extendedOperation(request); } /** * @see javax.naming.ldap.LdapContext#getConnectControls() */ public Control[] getConnectControls() throws NamingException { this.assertOpen(); return this.getDelegateLdapContext().getConnectControls(); } /** * @see javax.naming.ldap.LdapContext#getRequestControls() */ public Control[] getRequestControls() throws NamingException { this.assertOpen(); return this.getDelegateLdapContext().getRequestControls(); } /** * @see javax.naming.ldap.LdapContext#getResponseControls() */ public Control[] getResponseControls() throws NamingException { this.assertOpen(); return this.getDelegateLdapContext().getResponseControls(); } /** * @see javax.naming.ldap.LdapContext#newInstance(javax.naming.ldap.Control[]) */ public LdapContext newInstance(Control[] requestControls) throws NamingException { throw new UnsupportedOperationException("Cannot call newInstance on a pooled context"); } /** * @see javax.naming.ldap.LdapContext#reconnect(javax.naming.ldap.Control[]) */ public void reconnect(Control[] connCtls) throws NamingException { throw new UnsupportedOperationException("Cannot call reconnect on a pooled context"); } /** * @see javax.naming.ldap.LdapContext#setRequestControls(javax.naming.ldap.Control[]) */ public void setRequestControls(Control[] requestControls) throws NamingException { throw new UnsupportedOperationException("Cannot call setRequestControls on a pooled context"); } /** * @see DelegatingDirContext#close() */ public void close() throws NamingException { if (this.delegateLdapContext == null) { return; } super.close(); this.delegateLdapContext = null; } } ././@LongLink0000000000000000000000000000017600000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/DirContextType.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000304611475313376030214 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.pool; import javax.naming.directory.DirContext; import org.springframework.ldap.core.ContextSource; /** * An enum representing the two types of {@link DirContext}s that can be returned by a * {@link ContextSource}. * * @author Eric Dalquist */ public final class DirContextType { private String name; private DirContextType(String name) { this.name = name; } /* (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { return name; } /** * The type of {@link DirContext} returned by {@link ContextSource#getReadOnlyContext()} */ public static final DirContextType READ_ONLY = new DirContextType("READ_ONLY"); /** * The type of {@link DirContext} returned by {@link ContextSource#getReadWriteContext()} */ public static final DirContextType READ_WRITE = new DirContextType("READ_WRITE"); } ././@LongLink0000000000000000000000000000021400000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/pool/MutableDelegatingLdapContext.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000434011475313376030212 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.pool; import javax.naming.NamingException; import javax.naming.ldap.Control; import javax.naming.ldap.LdapContext; import org.apache.commons.pool.KeyedObjectPool; import org.springframework.ldap.pool.factory.MutablePoolingContextSource; /** * Used by {@link MutablePoolingContextSource} to wrap a {@link LdapContext}, * delegating most methods to the underlying context. This class extends * {@link DelegatingLdapContext}, allowing request controls to be set on the * wrapped ldap context. This enables the Spring LDAP pooling to be used for * scenarios such as paged results. * * @author Ulrik Sandberg */ public class MutableDelegatingLdapContext extends DelegatingLdapContext { /** * Create a new mutable delegating ldap context for the specified pool, * context and context type. * * @param keyedObjectPool The pool the delegate context was checked out * from. * @param delegateLdapContext The ldap context to delegate operations to. * @param dirContextType The type of context, used as a key for the pool. * @throws IllegalArgumentException if any of the arguments are null */ public MutableDelegatingLdapContext(KeyedObjectPool keyedObjectPool, LdapContext delegateLdapContext, DirContextType dirContextType) { super(keyedObjectPool, delegateLdapContext, dirContextType); } /* * @see * org.springframework.ldap.pool.DelegatingLdapContext#setRequestControls * (javax.naming.ldap.Control[]) */ public void setRequestControls(Control[] requestControls) throws NamingException { assertOpen(); getDelegateLdapContext().setRequestControls(requestControls); } } ././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/CommunicationException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000177411475313376030222 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI CommunicationException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.CommunicationException */ public class CommunicationException extends NamingException { public CommunicationException(javax.naming.CommunicationException cause) { super(cause); } } ././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0002755000000000000000000000000011475313376030211 5ustar ././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0002755000000000000000000000000011475313376030211 5ustar ././@LongLink0000000000000000000000000000023500000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/TempEntryRenamingStrategy.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000241511475313376030213 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import javax.naming.Name; /** * Interface for different strategies to rename temporary entries for unbind and * rebind operations. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public interface TempEntryRenamingStrategy { /** * Get a temporary name for the current entry to be renamed to. * * @param originalName * The original name of the entry. * @return The name to which the entry should be temporarily renamed * according to this strategy. */ Name getTemporaryName(Name originalName); } ././@LongLink0000000000000000000000000000023300000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/RenameOperationExecutor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000645611475313376030224 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import javax.naming.Name; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.core.LdapOperations; import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor; /** * A {@link CompensatingTransactionOperationExecutor} to manage a rename * operation. Performs a rename operation in {@link #performOperation()}, a * negating rename in {@link #rollback()}, and nothing in {@link #commit()}. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class RenameOperationExecutor implements CompensatingTransactionOperationExecutor { private static Log log = LogFactory.getLog(RenameOperationExecutor.class); private LdapOperations ldapOperations; private Name newDn; private Name originalDn; /** * Constructor. * * @param ldapOperations * The {@link LdapOperations} to use for performing the rollback * operation. * @param originalDn * DN that the entry was moved from in the recorded operation. * @param newDn * DN that the entry has been moved to in the recorded operation. */ public RenameOperationExecutor(LdapOperations ldapOperations, Name originalDn, Name newDn) { this.ldapOperations = ldapOperations; this.originalDn = originalDn; this.newDn = newDn; } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#rollback() */ public void rollback() { log.debug("Rolling back rename operation"); try { ldapOperations.rename(newDn, originalDn); } catch (Exception e) { log.warn("Unable to rollback rename operation. " + "originalDn: " + newDn + "; newDn: " + originalDn); } } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#commit() */ public void commit() { log.debug("Nothing to do in commit for rename operation"); } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#performOperation() */ public void performOperation() { log.debug("Performing rename operation"); ldapOperations.rename(originalDn, newDn); } Name getNewDn() { return newDn; } LdapOperations getLdapOperations() { return ldapOperations; } Name getOriginalDn() { return originalDn; } } ././@LongLink0000000000000000000000000000023300000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/RebindOperationRecorder.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000655411475313376030223 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import javax.naming.Name; import javax.naming.directory.Attributes; import org.springframework.ldap.core.LdapOperations; import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor; import org.springframework.transaction.compensating.CompensatingTransactionOperationRecorder; /** * A {@link CompensatingTransactionOperationRecorder} keeping track of a rebind * operation. Creates {@link RebindOperationExecutor} objects in * {@link #recordOperation(Object[])}. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class RebindOperationRecorder implements CompensatingTransactionOperationRecorder { private LdapOperations ldapOperations; private TempEntryRenamingStrategy renamingStrategy; /** * Constructor. * * @param ldapOperations * {@link LdapOperations} to use for getting the rollback * information and supply to the {@link RebindOperationExecutor}. * @param renamingStrategy * {@link TempEntryRenamingStrategy} to use for generating temp * DNs. */ public RebindOperationRecorder(LdapOperations ldapOperations, TempEntryRenamingStrategy renamingStrategy) { this.ldapOperations = ldapOperations; this.renamingStrategy = renamingStrategy; } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationRecorder#recordOperation(java.lang.Object[]) */ public CompensatingTransactionOperationExecutor recordOperation( Object[] args) { if (args == null || args.length != 3) { throw new IllegalArgumentException( "Invalid arguments for bind operation"); } Name dn = LdapTransactionUtils.getFirstArgumentAsName(args); Object object = args[1]; Attributes attributes = null; if (args[2] != null && !(args[2] instanceof Attributes)) { throw new IllegalArgumentException( "Invalid third argument to bind operation"); } else if (args[2] != null) { attributes = (Attributes) args[2]; } Name temporaryName = renamingStrategy.getTemporaryName(dn); return new RebindOperationExecutor(ldapOperations, dn, temporaryName, object, attributes); } /** * Get the LdapOperations. For testing purposes. * * @return the LdapOperations. */ LdapOperations getLdapOperations() { return ldapOperations; } public TempEntryRenamingStrategy getRenamingStrategy() { return renamingStrategy; } } ././@LongLink0000000000000000000000000000023100000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/BindOperationRecorder.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000550211475313376030213 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import javax.naming.Name; import javax.naming.directory.Attributes; import org.springframework.ldap.core.LdapOperations; import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor; import org.springframework.transaction.compensating.CompensatingTransactionOperationRecorder; /** * A {@link CompensatingTransactionOperationRecorder} keeping track of bind * operations. Creates {@link BindOperationExecutor} objects in * {@link #recordOperation(Object[])}. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class BindOperationRecorder implements CompensatingTransactionOperationRecorder { private LdapOperations ldapOperations; /** * Constructor. * * @param ldapOperations * {@link LdapOperations} to use for supplying to the * corresponding rollback operation. */ public BindOperationRecorder(LdapOperations ldapOperations) { this.ldapOperations = ldapOperations; } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationRecorder#recordOperation(java.lang.Object[]) */ public CompensatingTransactionOperationExecutor recordOperation( Object[] args) { if (args == null || args.length != 3) { throw new IllegalArgumentException( "Invalid arguments for bind operation"); } Name dn = LdapTransactionUtils.getFirstArgumentAsName(args); Object object = args[1]; Attributes attributes = null; if (args[2] != null && !(args[2] instanceof Attributes)) { throw new IllegalArgumentException( "Invalid third argument to bind operation"); } else if (args[2] != null) { attributes = (Attributes) args[2]; } return new BindOperationExecutor(ldapOperations, dn, object, attributes); } /** * Get the LdapOperations. For testing purposes.s * * @return the LdapOperations. */ LdapOperations getLdapOperations() { return ldapOperations; } } ././@LongLink0000000000000000000000000000020700000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/support/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0002755000000000000000000000000011475313376030211 5ustar ././@LongLink0000000000000000000000000000022300000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/support/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000016511475313376030213 0ustar Useful helper implementations for client side Compensating LDAP Transactions. ././@LongLink0000000000000000000000000000026500000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/support/DifferentSubtreeTempEntryRenamingStrategy.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000633511475313376030220 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating.support; import java.util.List; import javax.naming.Name; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.LdapRdn; import org.springframework.ldap.core.LdapRdnComponent; import org.springframework.ldap.transaction.compensating.TempEntryRenamingStrategy; /** * A {@link TempEntryRenamingStrategy} that moves the entry to a different * subtree than the original entry. The specified subtree needs to be present in * the LDAP tree; it will not be created and operations using this strategy will * fail if the destination is not in place. However, this strategy is preferable * to {@link DefaultTempEntryRenamingStrategy}, as it makes searches have the * expected result even though the temporary entry still exists during the * transaction. *

* Example: If the specified subtreeNode is * ou=tempEntries and the originalName is * cn=john doe, ou=company1, c=SE, the result of * {@link #getTemporaryName(Name)} will be * cn=john doe1, ou=tempEntries. The "1" suffix is a * sequence number needed to prevent potential collisions in the temporary * storage. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class DifferentSubtreeTempEntryRenamingStrategy implements TempEntryRenamingStrategy { private Name subtreeNode; private static int nextSequenceNo = 1; public DifferentSubtreeTempEntryRenamingStrategy(Name subtreeNode) { this.subtreeNode = subtreeNode; } public Name getSubtreeNode() { return subtreeNode; } public void setSubtreeNode(Name subtreeNode) { this.subtreeNode = subtreeNode; } int getNextSequenceNo() { return nextSequenceNo; } /* * @see org.springframework.ldap.support.transaction.TempEntryRenamingStrategy#getTemporaryName(javax.naming.Name) */ public Name getTemporaryName(Name originalName) { DistinguishedName tempName = new DistinguishedName(originalName); List names = tempName.getNames(); LdapRdn rdn = (LdapRdn) names.get(names.size() - 1); LdapRdnComponent component = rdn.getComponent(); LdapRdn newRdn; synchronized (this) { newRdn = new LdapRdn(component.getKey(), component.getValue() + nextSequenceNo++); } DistinguishedName newName = new DistinguishedName(subtreeNode); newName.add(newRdn); return newName; } } ././@LongLink0000000000000000000000000000025400000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/support/DefaultTempEntryRenamingStrategy.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000603211475313376030212 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating.support; import java.util.List; import javax.naming.Name; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.LdapRdn; import org.springframework.ldap.core.LdapRdnComponent; import org.springframework.ldap.transaction.compensating.TempEntryRenamingStrategy; /** * Default implementation of {@link TempEntryRenamingStrategy}. This * implementation simply adds "_temp" to the leftmost (least significant part) * of the name. For example: * *

 * cn=john doe, ou=company1, c=SE
 * 
* * becomes: * *
 * cn=john doe_temp, ou=company1, c=SE
 * 
*

* Note that using this strategy means that the entry remains in virtually the * same location as where it originally resided. This means that searches later * in the same transaction might return references to the temporary entry even * though it should have been removed or rebound. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class DefaultTempEntryRenamingStrategy implements TempEntryRenamingStrategy { /** * The default temp entry suffix, "_temp". */ public static final String DEFAULT_TEMP_SUFFIX = "_temp"; private String tempSuffix = DEFAULT_TEMP_SUFFIX; /* * @see org.springframework.ldap.support.transaction.TempEntryRenamingStrategy#getTemporaryName(javax.naming.Name) */ public Name getTemporaryName(Name originalName) { DistinguishedName temporaryName = new DistinguishedName(originalName); List names = temporaryName.getNames(); LdapRdn rdn = (LdapRdn) names.get(names.size() - 1); LdapRdnComponent rdnComponent = rdn.getComponent(); String value = rdnComponent.getValue(); rdnComponent.setValue(value + DEFAULT_TEMP_SUFFIX); return temporaryName; } /** * Get the suffix that will be used for renaming temporary entries. * * @return the suffix. */ public String getTempSuffix() { return tempSuffix; } /** * Set the suffix to use for renaming temporary entries. Default value is * {@link #DEFAULT_TEMP_SUFFIX}. * * @param tempSuffix * the suffix. */ public void setTempSuffix(String tempSuffix) { this.tempSuffix = tempSuffix; } } ././@LongLink0000000000000000000000000000021300000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000016111475313376030207 0ustar LDAP specific implementations of the Compensating Transaction interfaces. ././@LongLink0000000000000000000000000000023100000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/NullOperationExecutor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000311511475313376030211 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor; /** * A {@link CompensatingTransactionOperationExecutor} that performs nothing. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class NullOperationExecutor implements CompensatingTransactionOperationExecutor { private static Log log = LogFactory.getLog(NullOperationExecutor.class); /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#rollback() */ public void rollback() { log.info("Rolling back null operation"); } public void commit() { log.info("Committing back null operation"); } public void performOperation() { log.info("Performing null operation"); } } ././@LongLink0000000000000000000000000000023300000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/UnbindOperationExecutor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000724311475313376030217 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import javax.naming.Name; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.core.LdapOperations; import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor; /** * A {@link CompensatingTransactionOperationExecutor} to manage an unbind * operation. The methods in this class do not behave as expected, since it * might be impossible to retrieve all the original attributes from the entry. * Instead this class performs a rename in {@link #performOperation()}, * a negating rename in {@link #rollback()}, and {@link #commit()} unbinds the * entry from its temporary location. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class UnbindOperationExecutor implements CompensatingTransactionOperationExecutor { private static Log log = LogFactory.getLog(UnbindOperationExecutor.class); private LdapOperations ldapOperations; private Name originalDn; private Name temporaryDn; /** * Constructor. * * @param ldapOperations * The {@link LdapOperations} to use for performing the rollback * operation. * @param originalDn * The original DN of the entry to be removed. * @param temporaryDn * Temporary DN of the entry to be removed; this is where the * entry is temporarily stored during the transaction. */ public UnbindOperationExecutor(LdapOperations ldapOperations, Name originalDn, Name temporaryDn) { this.ldapOperations = ldapOperations; this.originalDn = originalDn; this.temporaryDn = temporaryDn; } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#rollback() */ public void rollback() { try { ldapOperations.rename(temporaryDn, originalDn); } catch (Exception e) { log.warn("Filed to rollback unbind operation, temporaryDn: " + temporaryDn + "; originalDn: " + originalDn); } } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#commit() */ public void commit() { log.debug("Committing unbind operation - unbinding temporary entry"); ldapOperations.unbind(temporaryDn); } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#performOperation() */ public void performOperation() { log.debug("Performing operation for unbind -" + " renaming to temporary entry."); ldapOperations.rename(originalDn, temporaryDn); } LdapOperations getLdapOperations() { return ldapOperations; } Name getOriginalDn() { return originalDn; } Name getTemporaryDn() { return temporaryDn; } } ././@LongLink0000000000000000000000000000023300000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/RenameOperationRecorder.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000526211475313376030216 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import javax.naming.Name; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.core.LdapOperations; import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor; import org.springframework.transaction.compensating.CompensatingTransactionOperationRecorder; import org.springframework.util.Assert; /** * A {@link CompensatingTransactionOperationRecorder} for keeping track of * rename operations. Creates {@link RenameOperationExecutor} objects for * rolling back. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class RenameOperationRecorder implements CompensatingTransactionOperationRecorder { private static Log log = LogFactory.getLog(RenameOperationRecorder.class); private LdapOperations ldapOperations; /** * Constructor. * * @param ldapOperations * The {@link LdapOperations} to supply to the created * {@link RebindOperationExecutor} objects. */ public RenameOperationRecorder(LdapOperations ldapOperations) { this.ldapOperations = ldapOperations; } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationRecorder#recordOperation(java.lang.Object[]) */ public CompensatingTransactionOperationExecutor recordOperation( Object[] args) { log.debug("Storing rollback information for rename operation"); Assert.notEmpty(args); if (args.length != 2) { // This really shouldn't happen. throw new IllegalArgumentException("Illegal argument length"); } Name oldDn = LdapTransactionUtils.getArgumentAsName(args[0]); Name newDn = LdapTransactionUtils.getArgumentAsName(args[1]); return new RenameOperationExecutor(ldapOperations, oldDn, newDn); } LdapOperations getLdapOperations() { return ldapOperations; } } ././@LongLink0000000000000000000000000000023300000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/UnbindOperationRecorder.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000531111475313376030211 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import javax.naming.Name; import org.springframework.ldap.core.LdapOperations; import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor; import org.springframework.transaction.compensating.CompensatingTransactionOperationRecorder; /** * {@link CompensatingTransactionOperationRecorder} to keep track of unbind * operations. This class creates {@link UnbindOperationExecutor} objects for * rollback. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class UnbindOperationRecorder implements CompensatingTransactionOperationRecorder { private LdapOperations ldapOperations; private TempEntryRenamingStrategy renamingStrategy; /** * Constructor. * * @param ldapOperations * {@link LdapOperations} to use for getting the data prior to * unbinding the entry and to supply to the * {@link UnbindOperationExecutor} for rollback. * @param renamingStrategy * the {@link TempEntryRenamingStrategy} to use when generating * DNs for temporary entries. */ public UnbindOperationRecorder(LdapOperations ldapOperations, TempEntryRenamingStrategy renamingStrategy) { this.ldapOperations = ldapOperations; this.renamingStrategy = renamingStrategy; } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationRecorder#recordOperation(java.lang.Object[]) */ public CompensatingTransactionOperationExecutor recordOperation( Object[] args) { Name dn = LdapTransactionUtils.getFirstArgumentAsName(args); Name temporaryDn = renamingStrategy.getTemporaryName(dn); return new UnbindOperationExecutor(ldapOperations, dn, temporaryDn); } LdapOperations getLdapOperations() { return ldapOperations; } public TempEntryRenamingStrategy getRenamingStrategy() { return renamingStrategy; } } ././@LongLink0000000000000000000000000000025700000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/LdapCompensatingTransactionOperationFactory.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000712711475313376030220 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import javax.naming.directory.DirContext; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.core.LdapOperations; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.support.SingleContextSource; import org.springframework.transaction.compensating.CompensatingTransactionOperationFactory; import org.springframework.transaction.compensating.CompensatingTransactionOperationRecorder; /** * {@link CompensatingTransactionOperationRecorder} implementation for LDAP * operations. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class LdapCompensatingTransactionOperationFactory implements CompensatingTransactionOperationFactory { private static Log log = LogFactory.getLog(LdapCompensatingTransactionOperationFactory.class); private TempEntryRenamingStrategy renamingStrategy; /** * Constructor. * * @param renamingStrategy the {@link TempEntryRenamingStrategy} to supply * to relevant operations. */ public LdapCompensatingTransactionOperationFactory(TempEntryRenamingStrategy renamingStrategy) { this.renamingStrategy = renamingStrategy; } /* * @see org.springframework.transaction.compensating. * CompensatingTransactionOperationFactory * #createRecordingOperation(java.lang.Object, java.lang.String) */ public CompensatingTransactionOperationRecorder createRecordingOperation(Object resource, String operation) { if (StringUtils.equals(operation, LdapTransactionUtils.BIND_METHOD_NAME)) { log.debug("Bind operation recorded"); return new BindOperationRecorder(createLdapOperationsInstance((DirContext) resource)); } else if (StringUtils.equals(operation, LdapTransactionUtils.REBIND_METHOD_NAME)) { log.debug("Rebind operation recorded"); return new RebindOperationRecorder(createLdapOperationsInstance((DirContext) resource), renamingStrategy); } else if (StringUtils.equals(operation, LdapTransactionUtils.RENAME_METHOD_NAME)) { log.debug("Rename operation recorded"); return new RenameOperationRecorder(createLdapOperationsInstance((DirContext) resource)); } else if (StringUtils.equals(operation, LdapTransactionUtils.MODIFY_ATTRIBUTES_METHOD_NAME)) { return new ModifyAttributesOperationRecorder(createLdapOperationsInstance((DirContext) resource)); } else if (StringUtils.equals(operation, LdapTransactionUtils.UNBIND_METHOD_NAME)) { return new UnbindOperationRecorder(createLdapOperationsInstance((DirContext) resource), renamingStrategy); } log.warn("No suitable CompensatingTransactionOperationRecorder found for method " + operation + ". Operation will not be transacted."); return new NullOperationRecorder(); } LdapOperations createLdapOperationsInstance(DirContext ctx) { return new LdapTemplate(new SingleContextSource(ctx)); } } ././@LongLink0000000000000000000000000000023100000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/NullOperationRecorder.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000344411475313376030216 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor; import org.springframework.transaction.compensating.CompensatingTransactionOperationManager; import org.springframework.transaction.compensating.CompensatingTransactionOperationRecorder; /** * A {@link CompensatingTransactionOperationRecorder} performing nothing, * returning a {@link NullOperationExecutor} regardless of the input. Instances * of this class will be created if the * {@link CompensatingTransactionOperationManager} cannot determine any * appropriate {@link CompensatingTransactionOperationRecorder} for the current * operation. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class NullOperationRecorder implements CompensatingTransactionOperationRecorder { /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationRecorder#recordOperation(java.lang.Object[]) */ public CompensatingTransactionOperationExecutor recordOperation( Object[] args) { return new NullOperationExecutor(); } } ././@LongLink0000000000000000000000000000023000000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/LdapTransactionUtils.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000663711475313376030225 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import javax.naming.Name; import org.apache.commons.lang.StringUtils; import org.springframework.ldap.core.DistinguishedName; import org.springframework.util.Assert; /** * Utility methods for working with LDAP transactions. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public final class LdapTransactionUtils { public static final String REBIND_METHOD_NAME = "rebind"; public static final String BIND_METHOD_NAME = "bind"; public static final String RENAME_METHOD_NAME = "rename"; public static final String UNBIND_METHOD_NAME = "unbind"; public static final String MODIFY_ATTRIBUTES_METHOD_NAME = "modifyAttributes"; /** * Not to be instantiated. */ private LdapTransactionUtils() { } /** * Get the first parameter in the argument list as a Name. * * @param args * arguments supplied to a ldap operation. * @return a Name representation of the first argument, or the Name itself * if it is a name. */ public static Name getFirstArgumentAsName(Object[] args) { Assert.notEmpty(args); Object firstArg = args[0]; return getArgumentAsName(firstArg); } /** * Get the argument as a Name. * * @param arg * an argument supplied to an Ldap operation. * @return a Name representation of the argument, or the Name itself if it * is a Name. */ public static Name getArgumentAsName(Object arg) { if (arg instanceof String) { return new DistinguishedName((String) arg); } else if (arg instanceof Name) { return (Name) arg; } else { throw new IllegalArgumentException( "First argument needs to be a Name or a String representation thereof"); } } /** * Check whether the supplied method is a method for which transactions is * supported (and which should be recorded for possible rollback later). * * @param methodName * name of the method to check. * @return true if this is a supported transaction operation, * false otherwise. */ public static boolean isSupportedWriteTransactionOperation(String methodName) { return (StringUtils.equals(methodName, BIND_METHOD_NAME) || StringUtils.equals(methodName, REBIND_METHOD_NAME) || StringUtils.equals(methodName, RENAME_METHOD_NAME) || StringUtils .equals(methodName, MODIFY_ATTRIBUTES_METHOD_NAME) || StringUtils .equals(methodName, UNBIND_METHOD_NAME)); } } ././@LongLink0000000000000000000000000000020700000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/manager/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0002755000000000000000000000000011475313376030211 5ustar ././@LongLink0000000000000000000000000000026300000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/manager/ContextSourceTransactionManagerDelegate.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001224411475313376030214 0ustar /* * Copyright 2002-2007 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating.manager; import javax.naming.NamingException; import javax.naming.directory.DirContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.transaction.compensating.LdapCompensatingTransactionOperationFactory; import org.springframework.ldap.transaction.compensating.TempEntryRenamingStrategy; import org.springframework.ldap.transaction.compensating.support.DefaultTempEntryRenamingStrategy; import org.springframework.transaction.compensating.support.AbstractCompensatingTransactionManagerDelegate; import org.springframework.transaction.compensating.support.CompensatingTransactionHolderSupport; import org.springframework.transaction.compensating.support.DefaultCompensatingTransactionOperationManager; /** * This delegate performs all the work for the * {@link ContextSourceTransactionManager}. The work is delegated in order to * be able to perform the exact same work for the LDAP part in * {@link ContextSourceAndDataSourceTransactionManager}. * * @author Mattias Hellborg Arthursson * @see ContextSourceTransactionManager * @see ContextSourceAndDataSourceTransactionManager * @since 1.2 */ public class ContextSourceTransactionManagerDelegate extends AbstractCompensatingTransactionManagerDelegate { private static final Log log = LogFactory .getLog(ContextSourceTransactionManagerDelegate.class); private ContextSource contextSource; private TempEntryRenamingStrategy renamingStrategy = new DefaultTempEntryRenamingStrategy(); /** * Set the ContextSource to work on. Even though the actual ContextSource * sent to the LdapTemplate instance should be a * {@link TransactionAwareContextSourceProxy}, the one sent to this method * should be the target of that proxy. If it is not, the target will be * extracted and used instead. * * @param contextSource * the ContextSource to work on. */ public void setContextSource(ContextSource contextSource) { if (contextSource instanceof TransactionAwareContextSourceProxy) { TransactionAwareContextSourceProxy proxy = (TransactionAwareContextSourceProxy) contextSource; this.contextSource = proxy.getTarget(); } else { this.contextSource = contextSource; } } public ContextSource getContextSource() { return contextSource; } /* * @see org.springframework.transaction.compensating.support.AbstractCompensatingTransactionManagerDelegate#getTransactionSynchronizationKey() */ protected Object getTransactionSynchronizationKey() { return getContextSource(); } /* * @see org.springframework.transaction.compensating.support.AbstractCompensatingTransactionManagerDelegate#getNewHolder() */ protected CompensatingTransactionHolderSupport getNewHolder() { DirContext newCtx = getContextSource().getReadWriteContext(); DirContextHolder contextHolder = new DirContextHolder( new DefaultCompensatingTransactionOperationManager( new LdapCompensatingTransactionOperationFactory( renamingStrategy)), newCtx); return contextHolder; } /* * @see org.springframework.transaction.compensating.support.AbstractCompensatingTransactionManagerDelegate#closeTargetResource(org.springframework.transaction.compensating.support.CompensatingTransactionHolderSupport) */ protected void closeTargetResource( CompensatingTransactionHolderSupport transactionHolderSupport) { DirContextHolder contextHolder = (DirContextHolder) transactionHolderSupport; DirContext ctx = contextHolder.getCtx(); try { log.debug("Closing target context"); ctx.close(); } catch (NamingException e) { log.warn("Failed to close target context", e); } } /** * Set the {@link TempEntryRenamingStrategy} to be used when renaming * temporary entries in unbind and rebind operations. Default value is a * {@link DefaultTempEntryRenamingStrategy}. * * @param renamingStrategy * the {@link TempEntryRenamingStrategy} to use. */ public void setRenamingStrategy(TempEntryRenamingStrategy renamingStrategy) { this.renamingStrategy = renamingStrategy; } } ././@LongLink0000000000000000000000000000023400000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/manager/DirContextHolder.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000467711475313376030227 0ustar /* * Copyright 2002-2007 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating.manager; import javax.naming.directory.DirContext; import org.springframework.transaction.compensating.CompensatingTransactionOperationManager; import org.springframework.transaction.compensating.support.CompensatingTransactionHolderSupport; /** * Keeps track of the transaction DirContext. The same DirContext instance will * be reused throughout a transaction. Also keeps a * {@link CompensatingTransactionOperationManager}, responsible for performing * operations and keeping track of all changes and storing information necessary * for commit or rollback. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class DirContextHolder extends CompensatingTransactionHolderSupport { private DirContext ctx; /** * Constructor. * * @param manager * The {@link CompensatingTransactionOperationManager}. * @param ctx * The DirContext associated with the current transaction. */ public DirContextHolder(CompensatingTransactionOperationManager manager, DirContext ctx) { super(manager); this.ctx = ctx; } /** * Set the DirContext associated with the current transaction. * * @param ctx * The DirContext associated with the current transaction. */ public void setCtx(DirContext ctx) { this.ctx = ctx; } /** * Return the DirContext associated with the current transaction. */ public DirContext getCtx() { return ctx; } /* * @see org.springframework.transaction.compensating.support.CompensatingTransactionHolderSupport#getTransactedResource() */ protected Object getTransactedResource() { return ctx; } } ././@LongLink0000000000000000000000000000022300000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/manager/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000015211475313376030207 0ustar The core implementation classes for client-side LDAP transactions. ././@LongLink0000000000000000000000000000026700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/manager/ContextSourceAndHibernateTransactionManager.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000002200411475313376030207 0ustar /* * Copyright 2002-2008 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating.manager; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.transaction.compensating.TempEntryRenamingStrategy; import org.springframework.ldap.transaction.compensating.manager.ContextSourceTransactionManagerDelegate; import org.springframework.orm.hibernate3.HibernateTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionSuspensionNotSupportedException; import org.springframework.transaction.support.DefaultTransactionStatus; /** * A Transaction Manager to manage LDAP and Hibernate 3 operations within the same * transaction. Note that even though the same logical transaction is used, this * is not a JTA XA transaction; no two-phase commit will be performed, * and thus commit and rollback may yield unexpected results.
* This Transaction Manager is as good as it gets when you are using in LDAP in * combination with a Hibernate 3 and unable to use XA transactions because LDAP * is not transactional by design to begin with.
* * Furthermore, this manager does not support nested transactions * @author Hans Westerbeek * @since 1.2.2 */ public class ContextSourceAndHibernateTransactionManager extends HibernateTransactionManager { /** * */ private static final long serialVersionUID = 1L; private ContextSourceTransactionManagerDelegate ldapManagerDelegate = new ContextSourceTransactionManagerDelegate(); /* * @see org.springframework.orm.hibernate3.HibernateTransactionManager#isExistingTransaction(java.lang.Object) */ protected boolean isExistingTransaction(Object transaction) { ContextSourceAndHibernateTransactionObject actualTransactionObject = (ContextSourceAndHibernateTransactionObject) transaction; return super.isExistingTransaction(actualTransactionObject .getHibernateTransactionObject()); } /* * @see org.springframework.orm.hibernate3.HibernateTransactionManager#doGetTransaction() */ protected Object doGetTransaction() throws TransactionException { Object dataSourceTransactionObject = super.doGetTransaction(); Object contextSourceTransactionObject = ldapManagerDelegate .doGetTransaction(); return new ContextSourceAndHibernateTransactionObject( contextSourceTransactionObject, dataSourceTransactionObject); } /* * @see org.springframework.orm.hibernate3.HibernateTransactionManager#doBegin(java.lang.Object, * org.springframework.transaction.TransactionDefinition) */ protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException { ContextSourceAndHibernateTransactionObject actualTransactionObject = (ContextSourceAndHibernateTransactionObject) transaction; super.doBegin(actualTransactionObject.getHibernateTransactionObject(), definition); ldapManagerDelegate.doBegin(actualTransactionObject .getLdapTransactionObject(), definition); } /* * @see org.springframework.orm.hibernate3.HibernateTransactionManager#doCleanupAfterCompletion(java.lang.Object) */ protected void doCleanupAfterCompletion(Object transaction) { ContextSourceAndHibernateTransactionObject actualTransactionObject = (ContextSourceAndHibernateTransactionObject) transaction; super.doCleanupAfterCompletion(actualTransactionObject .getHibernateTransactionObject()); ldapManagerDelegate.doCleanupAfterCompletion(actualTransactionObject .getLdapTransactionObject()); } /* * @see org.springframework.orm.hibernate3.HibernateTransactionManager#doCommit(org.springframework.transaction.support.DefaultTransactionStatus) */ protected void doCommit(DefaultTransactionStatus status) throws TransactionException { ContextSourceAndHibernateTransactionObject actualTransactionObject = (ContextSourceAndHibernateTransactionObject) status .getTransaction(); try { super.doCommit(new DefaultTransactionStatus(actualTransactionObject .getHibernateTransactionObject(), status .isNewTransaction(), status.isNewSynchronization(), status .isReadOnly(), status.isDebug(), status .getSuspendedResources())); } catch (TransactionException ex) { if (isRollbackOnCommitFailure()) { logger.debug("Failed to commit db resource, rethrowing", ex); // If we are to rollback on commit failure, just rethrow the // exception - this will cause a rollback to be performed on // both resources. throw ex; } else { logger .warn("Failed to commit and resource is rollbackOnCommit not set -" + " proceeding to commit ldap resource."); } } ldapManagerDelegate.doCommit(new DefaultTransactionStatus( actualTransactionObject.getLdapTransactionObject(), status .isNewTransaction(), status.isNewSynchronization(), status.isReadOnly(), status.isDebug(), status .getSuspendedResources())); } /* * @see org.springframework.orm.hibernate3.HibernateTransactionManager#doRollback(org.springframework.transaction.support.DefaultTransactionStatus) */ protected void doRollback(DefaultTransactionStatus status) throws TransactionException { ContextSourceAndHibernateTransactionObject actualTransactionObject = (ContextSourceAndHibernateTransactionObject) status .getTransaction(); super.doRollback(new DefaultTransactionStatus(actualTransactionObject .getHibernateTransactionObject(), status.isNewTransaction(), status.isNewSynchronization(), status.isReadOnly(), status .isDebug(), status.getSuspendedResources())); ldapManagerDelegate.doRollback(new DefaultTransactionStatus( actualTransactionObject.getLdapTransactionObject(), status .isNewTransaction(), status.isNewSynchronization(), status.isReadOnly(), status.isDebug(), status .getSuspendedResources())); } public ContextSource getContextSource() { return ldapManagerDelegate.getContextSource(); } public void setContextSource(ContextSource contextSource) { ldapManagerDelegate.setContextSource(contextSource); } protected void setRenamingStrategy( TempEntryRenamingStrategy renamingStrategy) { ldapManagerDelegate.setRenamingStrategy(renamingStrategy); } private final static class ContextSourceAndHibernateTransactionObject { private Object ldapTransactionObject; private Object hibernateTransactionObject; public ContextSourceAndHibernateTransactionObject( Object ldapTransactionObject, Object hibernateTransactionObject) { this.ldapTransactionObject = ldapTransactionObject; this.hibernateTransactionObject = hibernateTransactionObject; } public Object getHibernateTransactionObject() { return hibernateTransactionObject; } public Object getLdapTransactionObject() { return ldapTransactionObject; } } /* * @see org.springframework.orm.hibernate3.HibernateTransactionManager#doSuspend(java.lang.Object) */ protected Object doSuspend(Object transaction) throws TransactionException { throw new TransactionSuspensionNotSupportedException( "Transaction manager [" + getClass().getName() + "] does not support transaction suspension"); } /* * @see org.springframework.orm.hibernate3.HibernateTransactionManager#doResume(java.lang.Object, * java.lang.Object) */ protected void doResume(Object transaction, Object suspendedResources) throws TransactionException { throw new TransactionSuspensionNotSupportedException( "Transaction manager [" + getClass().getName() + "] does not support transaction suspension"); } } ././@LongLink0000000000000000000000000000025300000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/manager/ContextSourceTransactionManager.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000002141511475313376030214 0ustar /* * Copyright 2002-2007 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating.manager; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.transaction.compensating.TempEntryRenamingStrategy; import org.springframework.ldap.transaction.compensating.UnbindOperationExecutor; import org.springframework.ldap.transaction.compensating.support.DefaultTempEntryRenamingStrategy; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor; import org.springframework.transaction.compensating.CompensatingTransactionOperationRecorder; import org.springframework.transaction.compensating.support.DefaultCompensatingTransactionOperationManager; import org.springframework.transaction.support.AbstractPlatformTransactionManager; import org.springframework.transaction.support.DefaultTransactionStatus; /** * TransactionManager for managing LDAP transactions. Since transactions are not * supported in the LDAP protocol, this class and its collaborators aim to * provide compensating transactions instead. Should a transaction * need to be rolled back, this TransactionManager will try to restore the * original state using information recorded prior to each operation. The * operation where the original state is restored is called a compensating * operation. *

* NOTE: The transactions provided by this TransactionManager are all * client side and are by no means 'real' transactions, in the sense * that we know them in the ordinary database world, e.g.: *

    *
  • Should the transaction failure be caused by a network failure, there is * no way whatsoever that this TransactionManager can restore the database * state. In this case, all possibilities for rollback will be utterly lost.
  • *
  • Transaction isolation is not provided, i.e. entries participating in a * transaction for one client may very well participate in another transaction * for another client at the same time. Should one of these transactions be * rolled back, the outcome of this is undetermined, and may in the worst case * result in total failure.
  • *
*

*

* While the points above should be noted and considered, the compensating * transaction approach will be perfectly sufficient for all but the most * unfortunate of circumstances. Considering that there currently is a total * absence of server-side transaction support in the LDAP world, being able to * mark operations as transactional in the same way as for relational database * operations is surely a step forward. *

*

* An LDAP transaction is tied to a {@link ContextSource}, to be supplied to * the {@link #setContextSource(ContextSource)} method. While the actual * ContextSource used by the target LdapTemplate instance needs to be of the * type {@link TransactionAwareContextSourceProxy}, the ContextSource supplied * to this class should be the actual target ContextSource. *

*

* Using this TransactionManager along with * {@link TransactionAwareContextSourceProxy}, all modifying operations (bind, * unbind, rebind, rename, modifyAttributes) in a transaction will be * intercepted. Each modification has its corresponding * {@link CompensatingTransactionOperationRecorder}, which collects the * information necessary to perform a rollback and produces a * {@link CompensatingTransactionOperationExecutor} which is then used to * execute the actual operation and is later called for performing the commit or * rollback. *

*

* For several of the operations, performing a rollback is pretty * straightforward. For example, in order to roll back a rename operation, it * will only be required to rename the entry back to its original position. For * other operations, however, it's a bit more complicated. An unbind operation * is not possible to roll back by simply binding the entry back with the * attributes retrieved from the original entry. It might not be possible to get * all the information from the original entry. Consequently, the * {@link UnbindOperationExecutor} will move the original entry to a temporary * location in its performOperation() method. The commit() method will know that * everything went well, so it will be OK to unbind the entry. The rollback * operation will be to rename the entry back to its original location. The same * behaviour is used for rebind() operations. The operation of calculating a * temporary location for an entry is delegated to a * {@link TempEntryRenamingStrategy} (default * {@link DefaultTempEntryRenamingStrategy}), specified in * {@link #setRenamingStrategy(TempEntryRenamingStrategy)}. *

*

* The actual work of this Transaction Manager is delegated to a * {@link ContextSourceTransactionManagerDelegate}. This is because the exact * same logic needs to be used if we want to wrap a JDBC and LDAP transaction in * the same logical transaction. *

* * @author Mattias Hellborg Arthursson * * @see ContextSourceAndDataSourceTransactionManager * @see ContextSourceTransactionManagerDelegate * @see DefaultCompensatingTransactionOperationManager * @see TempEntryRenamingStrategy * @see TransactionAwareContextSourceProxy * @since 1.2 */ public class ContextSourceTransactionManager extends AbstractPlatformTransactionManager { private static final long serialVersionUID = 7138208218687237856L; private ContextSourceTransactionManagerDelegate delegate = new ContextSourceTransactionManagerDelegate(); /* * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doBegin(java.lang.Object, * org.springframework.transaction.TransactionDefinition) */ protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException { delegate.doBegin(transaction, definition); } /* * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doCleanupAfterCompletion(java.lang.Object) */ protected void doCleanupAfterCompletion(Object transaction) { delegate.doCleanupAfterCompletion(transaction); } /* * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doCommit(org.springframework.transaction.support.DefaultTransactionStatus) */ protected void doCommit(DefaultTransactionStatus status) throws TransactionException { delegate.doCommit(status); } /* * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doGetTransaction() */ protected Object doGetTransaction() throws TransactionException { return delegate.doGetTransaction(); } /* * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doRollback(org.springframework.transaction.support.DefaultTransactionStatus) */ protected void doRollback(DefaultTransactionStatus status) throws TransactionException { delegate.doRollback(status); } /** * Get the ContextSource. * * @return the contextSource. * @see ContextSourceTransactionManagerDelegate#getContextSource() */ public ContextSource getContextSource() { return delegate.getContextSource(); } /** * Set the ContextSource. * * @param contextSource * the ContextSource. * @see ContextSourceTransactionManagerDelegate#setContextSource(ContextSource) */ public void setContextSource(ContextSource contextSource) { delegate.setContextSource(contextSource); } /** * Set the {@link TempEntryRenamingStrategy}. * * @param renamingStrategy * the Renaming Strategy. * @see ContextSourceTransactionManagerDelegate#setRenamingStrategy(TempEntryRenamingStrategy) */ public void setRenamingStrategy(TempEntryRenamingStrategy renamingStrategy) { delegate.setRenamingStrategy(renamingStrategy); } } ././@LongLink0000000000000000000000000000026700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/manager/TransactionAwareDirContextInvocationHandler.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001132411475313376030212 0ustar /* * Copyright 2002-2007 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating.manager; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import javax.naming.directory.DirContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.NamingException; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.transaction.compensating.LdapTransactionUtils; import org.springframework.transaction.compensating.support.CompensatingTransactionUtils; import org.springframework.transaction.support.TransactionSynchronizationManager; /** * Proxy implementation for DirContext, making sure that the instance is not * closed during a transaction, and that all modifying operations are recorded, * storing compensating rollback operations for them. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class TransactionAwareDirContextInvocationHandler implements InvocationHandler { private static Log log = LogFactory .getLog(TransactionAwareDirContextInvocationHandler.class); private DirContext target; private ContextSource contextSource; /** * Constructor. * * @param target * The target DirContext. * @param contextSource * The transactional ContextSource, needed to get hold of the * current transaction's {@link DirContextHolder}. */ public TransactionAwareDirContextInvocationHandler(DirContext target, ContextSource contextSource) { this.target = target; this.contextSource = contextSource; } /* * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, * java.lang.reflect.Method, java.lang.Object[]) */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if (methodName.equals("getTargetContext")) { return target; } else if (methodName.equals("equals")) { // Only consider equal when proxies are identical. return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE); } else if (methodName.equals("hashCode")) { // Use hashCode of Connection proxy. return new Integer(hashCode()); } else if (methodName.equals("close")) { doCloseConnection(target, contextSource); return null; } else if (LdapTransactionUtils .isSupportedWriteTransactionOperation(methodName)) { // Store transaction data and allow operation to proceed. CompensatingTransactionUtils.performOperation(contextSource, target, method, args); return null; } else { try { return method.invoke(target, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } } } /** * Close the supplied context, but only if it is not associated with the * current transaction. * * @param context * the DirContext to close. * @param contextSource * the ContextSource bound to the transaction. * @throws NamingException */ void doCloseConnection(DirContext context, ContextSource contextSource) throws javax.naming.NamingException { DirContextHolder transactionContextHolder = (DirContextHolder) TransactionSynchronizationManager .getResource(contextSource); if (transactionContextHolder == null || transactionContextHolder.getCtx() != context) { log.debug("Closing context"); // This is not the transactional context or the transaction is // no longer active - we should close it. context.close(); } else { log.debug("Leaving transactional context open"); } } }././@LongLink0000000000000000000000000000027000000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/manager/ContextSourceAndDataSourceTransactionManager.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000002164011475313376030214 0ustar /* * Copyright 2002-2007 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating.manager; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.transaction.compensating.TempEntryRenamingStrategy; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionSuspensionNotSupportedException; import org.springframework.transaction.support.DefaultTransactionStatus; /** * A Transaction Manager to manage LDAP and JDBC operations within the same * transaction. Note that even though the same logical transaction is used, this * is not a JTA XA transaction; no two-phase commit will be performed, * and thus commit and rollback may yield unexpected results. * * Note that nested transactions are not supported. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class ContextSourceAndDataSourceTransactionManager extends DataSourceTransactionManager { private static final long serialVersionUID = 6832868697460384648L; private ContextSourceTransactionManagerDelegate ldapManagerDelegate = new ContextSourceTransactionManagerDelegate(); public ContextSourceAndDataSourceTransactionManager() { super(); // Override the default behaviour. setNestedTransactionAllowed(false); } /* * @see org.springframework.jdbc.datasource.DataSourceTransactionManager#isExistingTransaction(java.lang.Object) */ protected boolean isExistingTransaction(Object transaction) { // We don't support nested transactions here return false; } /* * @see org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction() */ protected Object doGetTransaction() throws TransactionException { Object dataSourceTransactionObject = super.doGetTransaction(); Object contextSourceTransactionObject = ldapManagerDelegate .doGetTransaction(); return new ContextSourceAndDataSourceTransactionObject( contextSourceTransactionObject, dataSourceTransactionObject); } /* * @see org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin(java.lang.Object, * org.springframework.transaction.TransactionDefinition) */ protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException { ContextSourceAndDataSourceTransactionObject actualTransactionObject = (ContextSourceAndDataSourceTransactionObject) transaction; super.doBegin(actualTransactionObject.getDataSourceTransactionObject(), definition); ldapManagerDelegate.doBegin(actualTransactionObject .getLdapTransactionObject(), definition); } /* * @see org.springframework.jdbc.datasource.DataSourceTransactionManager#doCleanupAfterCompletion(java.lang.Object) */ protected void doCleanupAfterCompletion(Object transaction) { ContextSourceAndDataSourceTransactionObject actualTransactionObject = (ContextSourceAndDataSourceTransactionObject) transaction; super.doCleanupAfterCompletion(actualTransactionObject .getDataSourceTransactionObject()); ldapManagerDelegate.doCleanupAfterCompletion(actualTransactionObject .getLdapTransactionObject()); } /* * @see org.springframework.jdbc.datasource.DataSourceTransactionManager#doCommit(org.springframework.transaction.support.DefaultTransactionStatus) */ protected void doCommit(DefaultTransactionStatus status) throws TransactionException { ContextSourceAndDataSourceTransactionObject actualTransactionObject = (ContextSourceAndDataSourceTransactionObject) status .getTransaction(); try { super.doCommit(new DefaultTransactionStatus(actualTransactionObject .getDataSourceTransactionObject(), status .isNewTransaction(), status.isNewSynchronization(), status .isReadOnly(), status.isDebug(), status .getSuspendedResources())); } catch (TransactionException ex) { if (isRollbackOnCommitFailure()) { logger.debug("Failed to commit db resource, rethrowing", ex); // If we are to rollback on commit failure, just rethrow the // exception - this will cause a rollback to be performed on // both resources. throw ex; } else { logger .warn("Failed to commit and resource is rollbackOnCommit not set -" + " proceeding to commit ldap resource."); } } ldapManagerDelegate.doCommit(new DefaultTransactionStatus( actualTransactionObject.getLdapTransactionObject(), status .isNewTransaction(), status.isNewSynchronization(), status.isReadOnly(), status.isDebug(), status .getSuspendedResources())); } /* * @see org.springframework.jdbc.datasource.DataSourceTransactionManager#doRollback(org.springframework.transaction.support.DefaultTransactionStatus) */ protected void doRollback(DefaultTransactionStatus status) throws TransactionException { ContextSourceAndDataSourceTransactionObject actualTransactionObject = (ContextSourceAndDataSourceTransactionObject) status .getTransaction(); super.doRollback(new DefaultTransactionStatus(actualTransactionObject .getDataSourceTransactionObject(), status.isNewTransaction(), status.isNewSynchronization(), status.isReadOnly(), status .isDebug(), status.getSuspendedResources())); ldapManagerDelegate.doRollback(new DefaultTransactionStatus( actualTransactionObject.getLdapTransactionObject(), status .isNewTransaction(), status.isNewSynchronization(), status.isReadOnly(), status.isDebug(), status .getSuspendedResources())); } public ContextSource getContextSource() { return ldapManagerDelegate.getContextSource(); } public void setContextSource(ContextSource contextSource) { ldapManagerDelegate.setContextSource(contextSource); } protected void setRenamingStrategy( TempEntryRenamingStrategy renamingStrategy) { ldapManagerDelegate.setRenamingStrategy(renamingStrategy); } private final static class ContextSourceAndDataSourceTransactionObject { private Object ldapTransactionObject; private Object dataSourceTransactionObject; public ContextSourceAndDataSourceTransactionObject( Object ldapTransactionObject, Object dataSourceTransactionObject) { this.ldapTransactionObject = ldapTransactionObject; this.dataSourceTransactionObject = dataSourceTransactionObject; } public Object getDataSourceTransactionObject() { return dataSourceTransactionObject; } public Object getLdapTransactionObject() { return ldapTransactionObject; } } /* * @see org.springframework.jdbc.datasource.DataSourceTransactionManager#doSuspend(java.lang.Object) */ protected Object doSuspend(Object transaction) throws TransactionException { throw new TransactionSuspensionNotSupportedException( "Transaction manager [" + getClass().getName() + "] does not support transaction suspension"); } /* * @see org.springframework.jdbc.datasource.DataSourceTransactionManager#doResume(java.lang.Object, * java.lang.Object) */ protected void doResume(Object transaction, Object suspendedResources) throws TransactionException { throw new TransactionSuspensionNotSupportedException( "Transaction manager [" + getClass().getName() + "] does not support transaction suspension"); } }././@LongLink0000000000000000000000000000025600000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/manager/TransactionAwareContextSourceProxy.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000727011475313376030217 0ustar /* * Copyright 2002-2007 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating.manager; import java.lang.reflect.Proxy; import javax.naming.directory.DirContext; import org.springframework.ldap.NamingException; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DirContextProxy; import org.springframework.ldap.support.LdapUtils; import org.springframework.transaction.support.TransactionSynchronizationManager; /** * A proxy for ContextSource to make sure that the returned DirContext objects * are aware of the surrounding transactions. This makes sure that the * DirContext is not closed during the transaction and that all modifying * operations are recorded, keeping track of the corresponding rollback * operations. All returned DirContext instances will be of the type * {@link TransactionAwareDirContextInvocationHandler}. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class TransactionAwareContextSourceProxy implements ContextSource { private ContextSource target; /** * Constructor. * * @param target * the target ContextSource. */ public TransactionAwareContextSourceProxy(ContextSource target) { this.target = target; } /** * Get the target ContextSource. * * @return the target ContextSource. */ public ContextSource getTarget() { return target; } /* * @see org.springframework.ldap.core.ContextSource#getReadOnlyContext() */ public DirContext getReadOnlyContext() throws NamingException { return getReadWriteContext(); } private DirContext getTransactionAwareDirContextProxy(DirContext context, ContextSource target) { return (DirContext) Proxy .newProxyInstance(DirContextProxy.class.getClassLoader(), new Class[] { LdapUtils .getActualTargetClass(context), DirContextProxy.class }, new TransactionAwareDirContextInvocationHandler( context, target)); } /* * @see org.springframework.ldap.core.ContextSource#getReadWriteContext() */ public DirContext getReadWriteContext() throws NamingException { DirContextHolder contextHolder = (DirContextHolder) TransactionSynchronizationManager .getResource(target); DirContext ctx = null; if (contextHolder != null) { ctx = contextHolder.getCtx(); } if (ctx == null) { ctx = target.getReadWriteContext(); if (contextHolder != null) { contextHolder.setCtx(ctx); } } return getTransactionAwareDirContextProxy(ctx, target); } public DirContext getContext(String principal, String credentials) throws NamingException { throw new UnsupportedOperationException("Not supported on a transacted ContextSource"); } } ././@LongLink0000000000000000000000000000023100000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/BindOperationExecutor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000763011475313376030217 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import javax.naming.Name; import javax.naming.directory.Attributes; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.core.LdapOperations; import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor; /** * A {@link CompensatingTransactionOperationExecutor} to manage a bind * operation. Performs a bind in {@link #performOperation()}, a corresponding * unbind in {@link #rollback()}, and nothing in {@link #commit()}. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class BindOperationExecutor implements CompensatingTransactionOperationExecutor { private static Log log = LogFactory.getLog(BindOperationExecutor.class); private LdapOperations ldapOperations; private Name dn; private Object originalObject; private Attributes originalAttributes; /** * Constructor. * * @param ldapOperations * {@link LdapOperations} to use for performing the rollback * operation. * @param dn * DN of the entry to be unbound. * @param originalObject * original value sent to the 'object' parameter of the bind * operation. * @param originalAttributes * original value sent to the 'attributes' parameter of the bind * operation. */ public BindOperationExecutor(LdapOperations ldapOperations, Name dn, Object originalObject, Attributes originalAttributes) { this.ldapOperations = ldapOperations; this.dn = dn; this.originalObject = originalObject; this.originalAttributes = originalAttributes; } /* * (non-Javadoc) * * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#rollback() */ public void rollback() { try { ldapOperations.unbind(dn); } catch (Exception e) { log.warn("Failed to rollback, dn:" + dn.toString(), e); } } /* * (non-Javadoc) * * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#commit() */ public void commit() { log.debug("Nothing to do in commit for bind operation"); } /* * (non-Javadoc) * * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#performOperation() */ public void performOperation() { log.debug("Performing bind operation"); ldapOperations.bind(dn, originalObject, originalAttributes); } /** * Get the DN. Package private for testing purposes. * * @return the target DN. */ Name getDn() { return dn; } /** * Get the LdapOperations. Package private for testing purposes. * * @return the LdapOperations. */ LdapOperations getLdapOperations() { return ldapOperations; } Attributes getOriginalAttributes() { return originalAttributes; } Object getOriginalObject() { return originalObject; } } ././@LongLink0000000000000000000000000000024500000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/ModifyAttributesOperationRecorder.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001605111475313376030214 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import java.util.HashSet; import java.util.Set; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.DirContext; import javax.naming.directory.ModificationItem; import org.springframework.ldap.core.AttributesMapper; import org.springframework.ldap.core.LdapOperations; import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor; import org.springframework.transaction.compensating.CompensatingTransactionOperationRecorder; import org.springframework.util.Assert; /** * A {@link CompensatingTransactionOperationRecorder} keeping track of * modifyAttributes operations, creating corresponding * {@link ModifyAttributesOperationExecutor} instances for rollback. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class ModifyAttributesOperationRecorder implements CompensatingTransactionOperationRecorder { private LdapOperations ldapOperations; public ModifyAttributesOperationRecorder(LdapOperations ldapOperations) { this.ldapOperations = ldapOperations; } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationRecorder#recordOperation(java.lang.Object[]) */ public CompensatingTransactionOperationExecutor recordOperation( Object[] args) { Assert.notNull(args); Name dn = LdapTransactionUtils.getFirstArgumentAsName(args); if (args.length != 2 || !(args[1] instanceof ModificationItem[])) { throw new IllegalArgumentException( "Unexpected arguments to ModifyAttributes operation"); } ModificationItem[] incomingModifications = (ModificationItem[]) args[1]; Set set = new HashSet(); for (int i = 0; i < incomingModifications.length; i++) { set.add(incomingModifications[i].getAttribute().getID()); } // Get the current values of all referred Attributes. String[] attributeNameArray = (String[]) set.toArray(new String[set .size()]); Attributes currentAttributes = (Attributes) ldapOperations.lookup(dn, attributeNameArray, getAttributesMapper()); // Get a compensating ModificationItem for each of the incoming // modification. ModificationItem[] rollbackItems = new ModificationItem[incomingModifications.length]; for (int i = 0; i < incomingModifications.length; i++) { rollbackItems[i] = getCompensatingModificationItem( currentAttributes, incomingModifications[i]); } return new ModifyAttributesOperationExecutor(ldapOperations, dn, incomingModifications, rollbackItems); } /** * Get an {@link AttributesMapper} that just returns the supplied * Attributes. * * @return the {@link AttributesMapper} to use for getting the current * Attributes of the target DN. */ AttributesMapper getAttributesMapper() { return new AttributesMapper() { public Object mapFromAttributes(Attributes attributes) throws NamingException { return attributes; } }; } /** * Get a ModificationItem to use for rollback of the supplied modification. * * @param originalAttributes * All Attributes of the target DN that are affected of any of * the ModificationItems. * @param modificationItem * the ModificationItem to create a rollback item for. * @return A ModificationItem to use for rollback of the supplied * ModificationItem. */ protected ModificationItem getCompensatingModificationItem( Attributes originalAttributes, ModificationItem modificationItem) { Attribute modificationAttribute = modificationItem.getAttribute(); Attribute originalAttribute = originalAttributes .get(modificationAttribute.getID()); if (modificationItem.getModificationOp() == DirContext.REMOVE_ATTRIBUTE) { if (modificationAttribute.size() == 0) { // If the modification attribute size it means that the // Attribute should be removed entirely - we should store a // ModificationItem to restore all present values for rollback. return new ModificationItem(DirContext.ADD_ATTRIBUTE, (Attribute) originalAttribute.clone()); } else { // The rollback modification will be to re-add the removed // attribute values. return new ModificationItem(DirContext.ADD_ATTRIBUTE, (Attribute) modificationAttribute.clone()); } } else if (modificationItem.getModificationOp() == DirContext.REPLACE_ATTRIBUTE) { if (originalAttribute != null) { return new ModificationItem(DirContext.REPLACE_ATTRIBUTE, (Attribute) originalAttribute.clone()); } else { // The attribute doesn't previously exist - the rollback // operation will be to remove the attribute. return new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute(modificationAttribute.getID())); } } else { // An ADD_ATTRIBUTE operation if (originalAttribute == null) { // The attribute doesn't previously exist - the rollback // operation will be to remove the attribute. return new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute(modificationAttribute.getID())); } else { // The attribute does exist before - we should store the // previous value and it should be used for replacing in // rollback. return new ModificationItem(DirContext.REPLACE_ATTRIBUTE, (Attribute) originalAttribute.clone()); } } } LdapOperations getLdapOperations() { return ldapOperations; } } ././@LongLink0000000000000000000000000000023300000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/RebindOperationExecutor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001121611475313376030212 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import javax.naming.Name; import javax.naming.directory.Attributes; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.core.LdapOperations; import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor; /** * A {@link CompensatingTransactionOperationExecutor} to manage a rebind * operation. The methods in this class do not behave as expected, since it * might be impossible to retrieve all the original attributes from the entry. * Instead this class performs a rename in {@link #performOperation()}, * a negating rename in {@link #rollback()}, and the {@link #commit()} * operation unbinds the original entry from its temporary location and binds a * new entry to the original location using the attributes supplied to the * original rebind opertaion. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class RebindOperationExecutor implements CompensatingTransactionOperationExecutor { private static Log log = LogFactory.getLog(RebindOperationExecutor.class); private LdapOperations ldapOperations; private Name originalDn; private Name temporaryDn; private Object originalObject; private Attributes originalAttributes; /** * Constructor. * * @param ldapOperations * the {@link LdapOperations} to use to perform the rollback. * @param originalDn * The original DN of the entry to bind. * @param temporaryDn * The temporary DN of the entry. * @param originalObject * Original 'object' parameter sent to the rebind operation. * @param originalAttributes * Original 'attributes' parameter sent to the rebind operation */ public RebindOperationExecutor(LdapOperations ldapOperations, Name originalDn, Name temporaryDn, Object originalObject, Attributes originalAttributes) { this.ldapOperations = ldapOperations; this.originalDn = originalDn; this.temporaryDn = temporaryDn; this.originalObject = originalObject; this.originalAttributes = originalAttributes; } /** * Get the LdapOperations. Package private for testing purposes. * * @return the LdapOperations. */ LdapOperations getLdapOperations() { return ldapOperations; } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#rollback() */ public void rollback() { log.debug("Rolling back rebind operation"); try { ldapOperations.unbind(originalDn); ldapOperations.rename(temporaryDn, originalDn); } catch (Exception e) { log.warn("Failed to rollback operation, dn: " + originalDn + "; temporary DN: " + temporaryDn, e); } } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#commit() */ public void commit() { log.debug("Committing rebind operation"); ldapOperations.unbind(temporaryDn); } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#performOperation() */ public void performOperation() { log.debug("Performing rebind operation - " + "renaming original entry and " + "binding new contents to entry."); ldapOperations.rename(originalDn, temporaryDn); ldapOperations.bind(originalDn, originalObject, originalAttributes); } Attributes getOriginalAttributes() { return originalAttributes; } Name getOriginalDn() { return originalDn; } Object getOriginalObject() { return originalObject; } Name getTemporaryDn() { return temporaryDn; } } ././@LongLink0000000000000000000000000000024500000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/transaction/compensating/ModifyAttributesOperationExecutor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001004111475313376030205 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.transaction.compensating; import javax.naming.Name; import javax.naming.directory.ModificationItem; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.core.LdapOperations; import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor; /** * A {@link CompensatingTransactionOperationExecutor} to manage a * modifyAttributes operation. Performs a * modifyAttributes in {@link #performOperation()}, a negating * modifyAttributes in {@link #rollback()}, and nothing in {@link #commit()}. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class ModifyAttributesOperationExecutor implements CompensatingTransactionOperationExecutor { private static Log log = LogFactory .getLog(ModifyAttributesOperationExecutor.class); private LdapOperations ldapOperations; private Name dn; private ModificationItem[] compensatingModifications; private ModificationItem[] actualModifications; /** * Constructor. * * @param ldapOperations * The {@link LdapOperations} to use to perform the rollback * operation. * @param dn * the DN of the target entry. * @param actualModifications * the actual modificationItems that were sent to the * modifyAttributes operation. * @param compensatingModifications * the ModificationItems to undo the recorded operation. */ public ModifyAttributesOperationExecutor(LdapOperations ldapOperations, Name dn, ModificationItem[] actualModifications, ModificationItem[] compensatingModifications) { this.ldapOperations = ldapOperations; this.dn = dn; this.actualModifications = (ModificationItem[]) actualModifications.clone(); this.compensatingModifications = (ModificationItem[]) compensatingModifications.clone(); } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#rollback() */ public void rollback() { try { log.debug("Rolling back modifyAttributes operation"); ldapOperations.modifyAttributes(dn, compensatingModifications); } catch (Exception e) { log .warn("Failed to rollback ModifyAttributes operation, dn: " + dn); } } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#commit() */ public void commit() { log.debug("Nothing to do in commit for modifyAttributes"); } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#performOperation() */ public void performOperation() { log.debug("Performing modifyAttributes operation"); ldapOperations.modifyAttributes(dn, actualModifications); } Name getDn() { return dn; } LdapOperations getLdapOperations() { return ldapOperations; } ModificationItem[] getActualModifications() { return actualModifications; } ModificationItem[] getCompensatingModifications() { return compensatingModifications; } } ././@LongLink0000000000000000000000000000020300000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/NoSuchAttributeException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000213311475313376030210 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI NoSuchAttributeException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.directory.NoSuchAttributeException */ public class NoSuchAttributeException extends NamingException { public NoSuchAttributeException(String message) { super(message); } public NoSuchAttributeException(javax.naming.directory.NoSuchAttributeException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020700000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/InvalidSearchFilterException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000207411475313376030214 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI InvalidSearchFilterException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.directory.InvalidSearchFilterException */ public class InvalidSearchFilterException extends NamingException { public InvalidSearchFilterException( javax.naming.directory.InvalidSearchFilterException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020500000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/TimeLimitExceededException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000204511475313376030212 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI TimeLimitExceededException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.TimeLimitExceededException */ public class TimeLimitExceededException extends LimitExceededException { public TimeLimitExceededException( javax.naming.TimeLimitExceededException cause) { super(cause); } } ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0002755000000000000000000000000011475313376030211 5ustar ././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/DistinguishedName.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000005641311475313376030222 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import javax.naming.CompositeName; import javax.naming.InvalidNameException; import javax.naming.Name; import javax.naming.ldap.Rdn; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.BadLdapGrammarException; import org.springframework.ldap.support.LdapUtils; import org.springframework.ldap.support.ListComparator; import org.springframework.util.Assert; /** * Default implementation of a {@link Name} corresponding to an LDAP path. A * Distinguished Name manipulation implementation is included in JDK1.5 * (LdapName), but not in prior releases. * * A DistinguishedName is particularly useful when building or * modifying an LDAP path dynamically, as escaping will be taken care of. * * A path is split into several names. The {@link Name} interface specifies that * the most significant part be in position 0. *

* Example: * *

*
The path
*
uid=adam.skogman, ou=People, ou=EU
*
Name[0]
*
ou=EU
*
Name[1]
*
ou=People
*
Name[2]
*
uid=adam.skogman
*
*

*

* Name instances, and consequently DistinguishedName * instances are naturally mutable, which is useful when constructing * DistinguishedNames. Example: * *

 * DistinguishedName path = new DistinguishedName("dc=jayway,dc=se");
 * path.add("ou", "People");
 * path.add("uid", "adam.skogman");
 * String dn = path.toString();
 * 
* * will render uid=adam.skogman,ou=People,dc=jayway,dc=se. *

*

* NOTE: The fact that DistinguishedName instances are mutable needs to * be taken into careful account, as this means that they may be modified * involuntarily. This means that whenever a DistinguishedName * instance is kept for reference (e.g. for identification of a domain entry) or * as a constant, you should consider getting an immutable copy of the instance * using {@link #immutableDistinguishedName()} or * {@link #immutableDistinguishedName(String)}. *

*

* NB:As of version 1.3 the default toString representation of * DistinguishedName now defaults to a compact one, without spaces between the * respective RDNs. For backward compatibility, set the * {@link #SPACED_DN_FORMAT_PROPERTY} ({@value #SPACED_DN_FORMAT_PROPERTY}) to * true. * @author Adam Skogman * @author Mattias Hellborg Arthursson */ public class DistinguishedName implements Name { /** * System property that will be inspected to determine whether * {@link #toString()} will format the DN with spaces after each comma or * use a more compact representation, i.e.: * uid=adam.skogman, ou=People, dc=jayway, dc=se rather than * uid=adam.skogman,ou=People,dc=jayway,dc=se. A value other * than null or blank will trigger the spaced format. Default is the compact * representation. *

* Valid values are: *

    *
  • blank or null (property not set)
  • *
  • any non-blank value
  • *
* @since 1.3 * @see #toCompactString() */ public static final String SPACED_DN_FORMAT_PROPERTY = "org.springframework.ldap.core.spacedDnFormat"; /** * System property that will be inspected to determine whether creating a * DistinguishedName will convert the keys to lowercase, convert * the keys to uppercase, or leave the keys as they were in the * original String, ie none. Default is to convert the keys to * lowercase. *

* Valid values are: *

    *
  • "lower" or blank or null (property not set)
  • *
  • "upper"
  • *
  • "none"
  • *
* @since 1.3.1 * @see #KEY_CASE_FOLD_LOWER * @see #KEY_CASE_FOLD_UPPER * @see #KEY_CASE_FOLD_NONE */ public static final String KEY_CASE_FOLD_PROPERTY = "org.springframework.ldap.core.keyCaseFold"; public static final String KEY_CASE_FOLD_LOWER = "lower"; public static final String KEY_CASE_FOLD_UPPER = "upper"; public static final String KEY_CASE_FOLD_NONE = "none"; private static final Log log = LogFactory.getLog(DistinguishedName.class); private static final boolean COMPACT = true; private static final boolean NON_COMPACT = false; private static final long serialVersionUID = 3514344371999042586L; /** * An empty, unmodifiable DistinguishedName. */ public static final DistinguishedName EMPTY_PATH = new DistinguishedName(Collections.EMPTY_LIST); private List names; /** * Construct a new DistinguishedName with no components. */ public DistinguishedName() { names = new LinkedList(); } /** * Construct a new DistinguishedName from a String. * * @param path a String corresponding to a (syntactically) valid LDAP path. */ public DistinguishedName(String path) { if (StringUtils.isBlank(path)) { names = new LinkedList(); } else { parse(path); } } /** * Construct a new DistinguishedName from the supplied * List of {@link LdapRdn} objects. * * @param list the components that this instance will consist of. */ public DistinguishedName(List list) { this.names = list; } /** * Construct a new DistinguishedName from the supplied * {@link Name}. The parts of the supplied {@link Name} must be * syntactically correct {@link LdapRdn}s. * * @param name the {@link Name} to construct a new * DistinguishedName from. */ public DistinguishedName(Name name) { Assert.notNull(name, "name cannot be null"); if (name instanceof CompositeName) { parse(LdapUtils.convertCompositeNameToString((CompositeName) name)); return; } names = new LinkedList(); for (int i = 0; i < name.size(); i++) { names.add(new LdapRdn(name.get(i))); } } /** * Parse the supplied String and make this instance represent the * corresponding distinguished name. * * @param path the LDAP path to parse. */ protected void parse(String path) { DnParser parser = DefaultDnParserFactory.createDnParser(unmangleCompositeName(path)); DistinguishedName dn; try { dn = parser.dn(); } catch (ParseException e) { throw new BadLdapGrammarException("Failed to parse DN", e); } catch (TokenMgrError e) { throw new BadLdapGrammarException("Failed to parse DN", e); } this.names = dn.names; } /** * If path is surrounded by quotes, strip them. JNDI considers forward slash * ('/') special, but LDAP doesn't. {@link CompositeName#toString()} tends * to mangle a {@link Name} with a slash by surrounding it with quotes * ('"'). * * @param path Path to check and possibly strip. * @return A String with the possibly stripped path. */ private String unmangleCompositeName(String path) { String tempPath; // Check if CompositeName has mangled the name with quotes if (path.startsWith("\"") && path.endsWith("\"")) { tempPath = path.substring(1, path.length() - 1); } else { tempPath = path; } return tempPath; } /** * Get the {@link LdapRdn} at a specified position. * * @param index the {@link LdapRdn} to retrieve. * @return the {@link LdapRdn} at the requested position. */ public LdapRdn getLdapRdn(int index) { return (LdapRdn) names.get(index); } /** * Get the {@link LdapRdn} with the specified key. If there are several * {@link Rdn}s with the same key, the first one found (in order of * significance) will be returned. * * @param key Attribute name of the {@link LdapRdn} to retrieve. * @return the {@link LdapRdn} with the requested key. * @throws IllegalArgumentException if no Rdn matches the given key. */ public LdapRdn getLdapRdn(String key) { for (Iterator iter = names.iterator(); iter.hasNext();) { LdapRdn rdn = (LdapRdn) iter.next(); if (StringUtils.equals(rdn.getKey(), key)) { return rdn; } } throw new IllegalArgumentException("No Rdn with the requested key: '" + key + "'"); } /** * Get the value of the {@link LdapRdnComponent} with the specified key * (Attribute value). If there are several Rdns with the same key, the value * of the first one found (in order of significance) will be returned. * * @param key Attribute name of the {@link LdapRdn} to retrieve. * @return the value. * @throws IllegalArgumentException if no Rdn matches the given key. */ public String getValue(String key) { return getLdapRdn(key).getValue(); } /** * Get the name List. * * @return the list of {@link LdapRdn}s that this * DistinguishedName consists of. */ public List getNames() { return names; } /** * Get the String representation of this DistinguishedName. * Depending on the setting of property * org.springframework.ldap.core.spacedDnFormat a space will be * added after each comma, to make the result more readable. Default is * compact representation, i.e. without any spaces. * * @return a syntactically correct, properly escaped String representation * of the DistinguishedName. * @see #SPACED_DN_FORMAT_PROPERTY */ public String toString() { String spacedFormatting = System.getProperty(SPACED_DN_FORMAT_PROPERTY); if (StringUtils.isBlank(spacedFormatting)) { return format(COMPACT); } else { return format(NON_COMPACT); } } /** * Get the compact String representation of this * DistinguishedName. Add no space after each comma, to make it * compact. * * @return a syntactically correct, properly escaped String representation * of the DistinguishedName. */ public String toCompactString() { return format(COMPACT); } /** * Builds a complete LDAP path, ldap encoded, useful as a DN. * * Always uses lowercase, always separates with ", " i.e. comma and a space. * * @return the LDAP path. */ public String encode() { return format(NON_COMPACT); } private String format(boolean compact) { // empty path if (names.size() == 0) return ""; StringBuffer buffer = new StringBuffer(256); ListIterator i = names.listIterator(names.size()); while (i.hasPrevious()) { LdapRdn rdn = (LdapRdn) i.previous(); buffer.append(rdn.getLdapEncoded()); // add comma, except in last iteration if (i.hasPrevious()) { if (compact) { buffer.append(","); } else { buffer.append(", "); } } } return buffer.toString(); } /** * Builds a complete LDAP path, ldap and url encoded. Separates only with * ",". * * @return the LDAP path, for use in an url. */ public String toUrl() { StringBuffer buffer = new StringBuffer(256); for (int i = names.size() - 1; i >= 0; i--) { LdapRdn n = (LdapRdn) names.get(i); buffer.append(n.encodeUrl()); if (i > 0) { buffer.append(","); } } return buffer.toString(); } /** * Determines if this DistinguishedName path contains another * path. * * @param path the path to check. * @return true if the supplied path is conained in this * instance, false otherwise. */ public boolean contains(DistinguishedName path) { List shortlist = path.getNames(); // this path must be at least as long if (getNames().size() < shortlist.size()) return false; // must have names if (shortlist.size() == 0) return false; Iterator longiter = getNames().iterator(); Iterator shortiter = shortlist.iterator(); LdapRdn longname = (LdapRdn) longiter.next(); LdapRdn shortname = (LdapRdn) shortiter.next(); // find first match while (!longname.equals(shortname) && longiter.hasNext()) { longname = (LdapRdn) longiter.next(); } // Done? if (!shortiter.hasNext() && longname.equals(shortname)) return true; if (!longiter.hasNext()) return false; // compare while (longname.equals(shortname) && longiter.hasNext() && shortiter.hasNext()) { longname = (LdapRdn) longiter.next(); shortname = (LdapRdn) shortiter.next(); } // Done if (!shortiter.hasNext() && longname.equals(shortname)) return true; else return false; } /** * Add an LDAP path last in this DistinguishedName. E.g.: * *
	 * DistinguishedName name1 = new DistinguishedName("c=SE, dc=jayway, dc=se");
	 * DistinguishedName name2 = new DistinguishedName("ou=people");
	 * name1.append(name2);
	 * 
* * will result in ou=people, c=SE, dc=jayway, dc=se * * @param path the path to append. * @return this instance. */ public DistinguishedName append(DistinguishedName path) { getNames().addAll(path.getNames()); return this; } /** * Append a new {@link LdapRdn} using the supplied key and value. * * @param key the key of the {@link LdapRdn}. * @param value the value of the {@link LdapRdn}. * @return this instance. */ public DistinguishedName append(String key, String value) { add(key, value); return this; } /** * Add an LDAP path first in this DistinguishedName. E.g.: * *
	 * DistinguishedName name1 = new DistinguishedName("ou=people");
	 * DistinguishedName name2 = new DistinguishedName("c=SE, dc=jayway, dc=se");
	 * name1.prepend(name2);
	 * 
* * will result in ou=people, c=SE, dc=jayway, dc=se * * @param path the path to prepend. */ public void prepend(DistinguishedName path) { ListIterator i = path.getNames().listIterator(path.getNames().size()); while (i.hasPrevious()) { names.add(0, i.previous()); } } /** * Remove the first part of this DistinguishedName. * * @return the removed entry. */ public LdapRdn removeFirst() { return (LdapRdn) names.remove(0); } /** * Remove the supplied path from the beginning of this * DistinguishedName if this instance starts with * path. Useful for stripping base path suffix from a * DistinguishedName. * * @param path the path to remove from the beginning of this instance. */ public void removeFirst(Name path) { if (path != null && this.startsWith(path)) { for (int i = 0; i < path.size(); i++) this.removeFirst(); } } /** * @see java.lang.Object#clone() */ public Object clone() { try { DistinguishedName result = (DistinguishedName) super.clone(); result.names = new LinkedList(names); return result; } catch (CloneNotSupportedException e) { log.fatal("CloneNotSupported thrown from superclass - this should not happen"); throw new RuntimeException("Fatal error in clone", e); } } /** * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { // A subclass with identical values should NOT be considered equal. // EqualsBuilder in commons-lang cannot handle subclasses correctly. if (obj == null || obj.getClass() != this.getClass()) { return false; } DistinguishedName name = (DistinguishedName) obj; // compare the lists return getNames().equals(name.getNames()); } /** * @see java.lang.Object#hashCode() */ public int hashCode() { return this.getClass().hashCode() ^ getNames().hashCode(); } /** * Compare this instance to another object. Note that the comparison is done * in order of significance, so the most significant Rdn is compared first, * then the second and so on. * * @see javax.naming.Name#compareTo(java.lang.Object) */ public int compareTo(Object obj) { DistinguishedName that = (DistinguishedName) obj; ListComparator comparator = new ListComparator(); return comparator.compare(this.names, that.names); } public int size() { return names.size(); } public boolean isEmpty() { return names.size() == 0; } /* * (non-Javadoc) * * @see javax.naming.Name#getAll() */ public Enumeration getAll() { LinkedList strings = new LinkedList(); for (Iterator iter = names.iterator(); iter.hasNext();) { LdapRdn rdn = (LdapRdn) iter.next(); strings.add(rdn.getLdapEncoded()); } return Collections.enumeration(strings); } /* * (non-Javadoc) * * @see javax.naming.Name#get(int) */ public String get(int index) { LdapRdn rdn = (LdapRdn) names.get(index); return rdn.getLdapEncoded(); } /* * (non-Javadoc) * * @see javax.naming.Name#getPrefix(int) */ public Name getPrefix(int index) { LinkedList newNames = new LinkedList(); for (int i = 0; i < index; i++) { newNames.add(names.get(i)); } return new DistinguishedName(newNames); } /* * (non-Javadoc) * * @see javax.naming.Name#getSuffix(int) */ public Name getSuffix(int index) { if (index > names.size()) { throw new ArrayIndexOutOfBoundsException(); } LinkedList newNames = new LinkedList(); for (int i = index; i < names.size(); i++) { newNames.add(names.get(i)); } return new DistinguishedName(newNames); } /* * (non-Javadoc) * * @see javax.naming.Name#startsWith(javax.naming.Name) */ public boolean startsWith(Name name) { if (name.size() == 0) { return false; } DistinguishedName start = null; if (name instanceof DistinguishedName) { start = (DistinguishedName) name; } else { return false; } if (start.size() > this.size()) { return false; } Iterator longiter = names.iterator(); Iterator shortiter = start.getNames().iterator(); while (shortiter.hasNext()) { Object longname = longiter.next(); Object shortname = shortiter.next(); if (!longname.equals(shortname)) { return false; } } // All names in shortiter matched. return true; } /** * Determines if this DistinguishedName ends with a certian * path. * * If the argument path is empty (no names in path) this method will return * false. * * @param name The suffix to check for. * */ public boolean endsWith(Name name) { DistinguishedName path = null; if (name instanceof DistinguishedName) { path = (DistinguishedName) name; } else { return false; } List shortlist = path.getNames(); // this path must be at least as long if (getNames().size() < shortlist.size()) return false; // must have names if (shortlist.size() == 0) return false; ListIterator longiter = getNames().listIterator(getNames().size()); ListIterator shortiter = shortlist.listIterator(shortlist.size()); while (shortiter.hasPrevious()) { LdapRdn longname = (LdapRdn) longiter.previous(); LdapRdn shortname = (LdapRdn) shortiter.previous(); if (!longname.equals(shortname)) return false; } // if short list ended, all were equal return true; } /* * (non-Javadoc) * * @see javax.naming.Name#addAll(javax.naming.Name) */ public Name addAll(Name name) throws InvalidNameException { return addAll(names.size(), name); } /* * (non-Javadoc) * * @see javax.naming.Name#addAll(int, javax.naming.Name) */ public Name addAll(int arg0, Name name) throws InvalidNameException { DistinguishedName distinguishedName = null; try { distinguishedName = (DistinguishedName) name; } catch (ClassCastException e) { throw new InvalidNameException("Invalid name type"); } names.addAll(arg0, distinguishedName.getNames()); return this; } /* * (non-Javadoc) * * @see javax.naming.Name#add(java.lang.String) */ public Name add(String string) throws InvalidNameException { return add(names.size(), string); } /* * (non-Javadoc) * * @see javax.naming.Name#add(int, java.lang.String) */ public Name add(int index, String string) throws InvalidNameException { try { names.add(index, new LdapRdn(string)); } catch (BadLdapGrammarException e) { throw new InvalidNameException("Failed to parse rdn '" + string + "'"); } return this; } /* * (non-Javadoc) * * @see javax.naming.Name#remove(int) */ public Object remove(int arg0) throws InvalidNameException { LdapRdn rdn = (LdapRdn) names.remove(arg0); return rdn.getLdapEncoded(); } /** * Remove the last part of this DistinguishedName. * * @return the removed {@link LdapRdn}. */ public LdapRdn removeLast() { return (LdapRdn) names.remove(names.size() - 1); } /** * Add a new {@link LdapRdn} using the supplied key and value. * * @param key the key of the {@link LdapRdn}. * @param value the value of the {@link LdapRdn}. */ public void add(String key, String value) { names.add(new LdapRdn(key, value)); } /** * Add the supplied {@link LdapRdn} last in the list of Rdns. * * @param rdn the {@link LdapRdn} to add. */ public void add(LdapRdn rdn) { names.add(rdn); } /** * Add the supplied {@link LdapRdn} att the specified index. * * @param idx the index at which to add the LdapRdn. * @param rdn the LdapRdn to add. */ public void add(int idx, LdapRdn rdn) { names.add(idx, rdn); } /** * Return an immutable copy of this instance. It will not be possible to add * or remove any Rdns to or from the returned instance, and the respective * Rdns will also be immutable in turn. * * @return a copy of this instance backed by an immutable list. * @since 1.2 */ public DistinguishedName immutableDistinguishedName() { List listWithImmutableRdns = new ArrayList(names.size()); for (Iterator iterator = names.iterator(); iterator.hasNext();) { LdapRdn rdn = (LdapRdn) iterator.next(); listWithImmutableRdns.add(rdn.immutableLdapRdn()); } return new DistinguishedName(Collections.unmodifiableList(listWithImmutableRdns)); } /** * Create an immutable DistinguishedName instance, suitable as a constant. * * @param dnString the DN string to parse. * @return an immutable DistinguishedName corresponding to the supplied DN * string. * @since 1.3 */ public static final DistinguishedName immutableDistinguishedName(String dnString) { return new DistinguishedName(dnString).immutableDistinguishedName(); } } ././@LongLink0000000000000000000000000000020300000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/DirContextProcessor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000341311475313376030212 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.NamingException; import javax.naming.directory.DirContext; /** * Interface to be called in search by {@link LdapTemplate} before and after the * actual search and enumeration traversal. Implementations may be used to apply * search controls on the Context and retrieve the results of * such controls afterwards. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public interface DirContextProcessor { /** * Perform pre-processing on the supplied DirContext. * * @param ctx * the DirContext instance. * @throws NamingException * if thrown by the underlying operation. */ void preProcess(DirContext ctx) throws NamingException; /** * Perform post-processing on the supplied DirContext. * * @param ctx * the DirContext instance. * @throws NamingException * if thrown by the underlying operation. */ void postProcess(DirContext ctx) throws NamingException; } ././@LongLink0000000000000000000000000000020400000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/DirContextOperations.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000002016011475313376030210 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import java.util.SortedSet; import javax.naming.Name; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; /** * Interface for DirContextAdapter. * * @author Mattias Hellborg Arthursson * @see DirContextAdapter */ public interface DirContextOperations extends DirContext, AttributeModificationsAware { /** * Gets the update mode. An entry in update mode will keep track of its * modifications so that they can be retrieved using * {@link AttributeModificationsAware#getModificationItems()}. The update * mode should be true for a new entry and true * for an existing entry that is being updated. * * @return update mode. */ boolean isUpdateMode(); /** * Creates a String array of the names of the attributes which have been * changed. * * If this is a new entry, all set entries will be in the list. If this is * an updated entry, only changed and removed entries will be in the array. * * @return Array of String */ String[] getNamesOfModifiedAttributes(); /** * Get the value of a String attribute. If more than one attribute value * exists for the specified attribute, only the first one will be returned. * If an attribute has no value, null will be returned. * * @param name name of the attribute. * @return the value of the attribute if it exists, or null if * the attribute doesn't exist or if it exists but with no value. * @throws ClassCastException if the value of the entry is not a String. */ String getStringAttribute(String name); /** * Get the value of an Object attribute. If more than one attribute value * exists for the specified attribute, only the first one will be returned. * If an attribute has no value, null will be returned. * * @param name name of the attribute. * @return the attribute value as an object if it exists, or * null if the attribute doesn't exist or if it exists but with * no value. */ Object getObjectAttribute(String name); /** * Check if an Object attribute exists, regardless of whether it has a value * or not. * * @param name name of the attribute * @return true if the attribute exists, false * otherwise */ boolean attributeExists(String name); /** * Set the with the name name to the value. * * @param name name of the attribute. * @param value value to set the attribute to. */ public void setAttributeValue(String name, Object value); /** * Sets a multivalue attribute, disregarding the order of the values. * * If value is null or value.length == 0 then the attribute will be removed. * * If update mode, changes will be made only if the array has more or less * objects or if one or more object has changed. Reordering the objects will * not cause an update. * * @param name The id of the attribute. * @param values Attribute values. */ void setAttributeValues(String name, Object[] values); /** * Sets a multivalue attribute. * * If value is null or value.length == 0 then the attribute will be removed. * * If update mode, changes will be made if the array has more or less * objects or if one or more string has changed. * * Reordering the objects will only cause an update if orderMatters is set * to true. * * @param name The id of the attribute. * @param values Attribute values. * @param orderMatters If true, it will be changed even if data * was just reordered. */ void setAttributeValues(String name, Object[] values, boolean orderMatters); /** * Add a value to the Attribute with the specified name. If the Attribute * doesn't exist it will be created. This method makes sure that the there * will be no duplicates of an added value - it the value exists it will not * be added again. * * @param name the name of the Attribute to which the specified value should * be added. * @param value the Attribute value to add. */ void addAttributeValue(String name, Object value); /** * Add a value to the Attribute with the specified name. If the Attribute * doesn't exist it will be created. The addIfDuplicateExists * parameter controls the handling of duplicates. It false, * this method makes sure that the there will be no duplicates of an added * value - it the value exists it will not be added again. * * @param name the name of the Attribute to which the specified value should * be added. * @param value the Attribute value to add. * @param addIfDuplicateExists true will add the value * regardless of whether there is an identical value already, allowing for * duplicate attribute values; false will not add the value if * it already exists. */ void addAttributeValue(String name, Object value, boolean addIfDuplicateExists); /** * Remove a value from the Attribute with the specified name. If the * Attribute doesn't exist, do nothing. * * @param name the name of the Attribute from which the specified value * should be removed. * @param value the value to remove. */ void removeAttributeValue(String name, Object value); /** * Update the attributes.This will mean that the getters ( * getStringAttribute methods) will return the updated values, * and the modifications will be forgotten (i.e. * {@link AttributeModificationsAware#getModificationItems()} will return an * empty array. */ void update(); /** * Get all values of a String attribute. * * @param name name of the attribute. * @return a (possibly empty) array containing all registered values of the * attribute as Strings if the attribute is defined or null * otherwise. * @throws ArrayStoreException if any of the attribute values is not a * String. */ String[] getStringAttributes(String name); /** * Get all values of an Object attribute. * * @param name name of the attribute. * @return a (possibly empty) array containing all registered values of the * attribute if the attribute is defined or null otherwise. * @since 1.3 */ Object[] getObjectAttributes(String name); /** * Get all String values of the attribute as a SortedSet. * * @param name name of the attribute. * @return a SortedSet containing all values of the attribute, * or null if the attribute does not exist. */ SortedSet getAttributeSortedStringSet(String name); /** * Returns the DN relative to the base path. * * @return The distinguished name of the current context. * * @see DirContextAdapter#getNameInNamespace() */ Name getDn(); /** * Set the dn of this entry. * * @param dn the dn. */ void setDn(Name dn); /* * (non-Javadoc) * * @see javax.naming.Context#getNameInNamespace() */ String getNameInNamespace(); /** * If this instance results from a referral, this method returns the url of * the referred server. * * @return The url of the referred server, e.g. * ldap://localhost:389, or the empty string if this is not a * referral. * @since 1.3 */ String getReferralUrl(); /** * Checks whether this instance results from a referral. * * @return true if this instance results from a referral, * false otherwise. * @since 1.3 */ boolean isReferral(); /** * Get all the Attributes. * * @return all the Attributes. * @since 1.3 */ Attributes getAttributes(); } ././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/AttributesMapper.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000407211475313376030214 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.directory.Attributes; /** * An interface used by LdapTemplate for mapping LDAP Attributes to beans. * Implementions of this interface perform the actual work of extracting * results, but need not worry about exception handling. NamingExceptions will * be caught and handled correctly by the {@link LdapTemplate} class. *

* Typically used in search methods of {@link LdapTemplate}. * AttributeMapper objects are normally stateless and thus * reusable; they are ideal for implementing attribute-mapping logic in one * place. *

* Alternatively, consider using a {@link ContextMapper} in stead. * * @see LdapTemplate#search(Name, String, AttributesMapper) * @see LdapTemplate#lookup(Name, AttributesMapper) * @see ContextMapper * * @author Mattias Hellborg Arthursson */ public interface AttributesMapper { /** * Map Attributes to an object. The supplied attributes are the attributes * from a single SearchResult. * * @param attributes * attributes from a SearchResult. * @return an object built from the attributes. * @throws NamingException * if any error occurs mapping the attributes */ Object mapFromAttributes(Attributes attributes) throws NamingException; } ././@LongLink0000000000000000000000000000021400000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/NameClassPairCallbackHandler.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000306511475313376030215 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.NameClassPair; /** * Callback interface used by {@link LdapTemplate} search, list and listBindings * methods. Implementations of this interface perform the actual work of * extracting results from a single NameClassPair (a * NameClassPair, Binding or * SearchResult depending on the search operation) returned by an * LDAP seach operation, such as search(), list(), and listBindings(). * * @author Mattias Hellborg Arthursson */ public interface NameClassPairCallbackHandler { /** * Handle one entry. This method will be called once for each entry returned * by a search or list. * * @param nameClassPair * the NameClassPair returned from the * NamingEnumeration. */ void handleNameClassPair(NameClassPair nameClassPair); } ././@LongLink0000000000000000000000000000022500000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/AuthenticatedLdapEntryContextCallback.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000267311475313376030221 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.directory.DirContext; /** * Callback interface to be used in the authentication methods in * {@link LdapOperations} for performing operations on individually * authenticated contexts. * * @author Mattias Hellborg Arthursson * @since 1.3 */ public interface AuthenticatedLdapEntryContextCallback { /** * Perform some LDAP operation on the supplied authenticated * DirContext instance. The target context will be * automatically closed. * * @param ctx the DirContext instance to perform an operation * on. * @param ldapEntryIdentification the identification of the LDAP entry used * to authenticate the supplied DirContext. */ void executeWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification); } ././@LongLink0000000000000000000000000000020700000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/LdapEntryIdentification.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000625611475313376030222 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.directory.DirContext; import org.springframework.util.Assert; /** * Wrapper class to handle the full identification of an LDAP entry. An LDAP * entry is identified by its Distinguished Name, in Spring LDAP represented by * the {@link DistinguishedName} class. A Distinguished Name can be absolute - * i.e. complete including the very root (base) of the LDAP tree - or relative - * i.e relative to the base LDAP path of the current LDAP connection (specified * as base to the {@link ContextSource}). *

* The different representations are needed on different occasions, e.g. the * relative DN is typically what is needed to perform lookups and searches in * the LDAP tree, whereas the absolute DN is needed when authenticating and when * an LDAP entry is referred to in e.g. a group. This wrapper class contains * both of these representations. * * @author Mattias Hellborg Arthursson */ public class LdapEntryIdentification { private final DistinguishedName relativeDn; private final DistinguishedName absoluteDn; /** * Construct an LdapEntryIdentification instance. * @param absoluteDn the absolute DN of the identified entry, e.g. as * returned by {@link DirContext#getNameInNamespace()}. * @param relativeDn the DN of the identified entry relative to the base * LDAP path, e.g. as returned by {@link DirContextOperations#getDn()}. */ public LdapEntryIdentification(DistinguishedName absoluteDn, DistinguishedName relativeDn) { Assert.notNull(absoluteDn, "Absolute DN must not be null"); Assert.notNull(relativeDn, "Relative DN must not be null"); this.absoluteDn = absoluteDn.immutableDistinguishedName(); this.relativeDn = relativeDn.immutableDistinguishedName(); } /** * Get the DN of the identified entry relative to the base LDAP path, e.g. * as returned by {@link DirContextOperations#getDn()}. * @return the relative DN. */ public DistinguishedName getRelativeDn() { return relativeDn; } /** * Get the absolute DN of the identified entry, e.g. as returned by * {@link DirContext#getNameInNamespace()}. * @return the absolute DN. */ public DistinguishedName getAbsoluteDn() { return absoluteDn; } public boolean equals(Object obj) { if (obj != null && obj.getClass().equals(this.getClass())) { LdapEntryIdentification that = (LdapEntryIdentification) obj; return this.absoluteDn.equals(that.absoluteDn) && this.relativeDn.equals(that.relativeDn); } return false; } public int hashCode() { return absoluteDn.hashCode() ^ relativeDn.hashCode(); } } ././@LongLink0000000000000000000000000000016300000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0002755000000000000000000000000011475313376030211 5ustar ././@LongLink0000000000000000000000000000023000000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/DirContextAuthenticationStrategy.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001004311475313376030207 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import java.util.Hashtable; import javax.naming.NamingException; import javax.naming.directory.DirContext; import org.springframework.ldap.core.AuthenticationSource; import org.springframework.ldap.core.ContextSource; /** * A strategy to use when authenticating LDAP connections on creation. When * authenticating LDAP connections different strategies are needed depending on * the authentication mechanism used. Furthermore, depending on the mechanism * the work to be done needs to be applied at different stages of the * DirContext creation process. A * DirContextAuthenticationStrategy contains the logic to perform a particular * type of authentication mechanism and will be called by its * {@link ContextSource} at appropriate stages of the process. * * @author Mattias Hellborg Arthursson */ public interface DirContextAuthenticationStrategy { /** * This method is responsible for preparing the environment to be used when * creating the DirContext instance. The base environment * (including URL, ContextFactory etc. will already be set, * and this method is called just before the actual Context is to be * created. * * @param env The Hashtable to be sent to the * DirContext instance on initialization. Pre-configured with * the basic settings; the implementation of this method is responsible for * manipulating the environment as appropriate for the particular * authentication mechanism. * @param userDn the user DN to authenticate, as received from the * {@link AuthenticationSource} of the {@link ContextSource}. * @param password the password to authenticate with, as received from the * {@link AuthenticationSource} of the {@link ContextSource}. * @throws NamingException if anything goes wrong. This will cause the * DirContext creation to be aborted and the exception to be * translated and rethrown. */ public void setupEnvironment(Hashtable env, String userDn, String password) throws NamingException; /** * This method is responsible for post-processing the * DirContext instance after it has been created. It will be * called immediately after the instance has been created. Some * authentication mechanisms, e.g. TLS, require particular stuff to happen * before the actual target Context is closed. This method provides the * possibility to replace or wrap the actual DirContext with a proxy so that * any calls on it may be intercepted. * * @param ctx the freshly created DirContext instance. The * actual implementation class (e.g. InitialLdapContext) * depends on the {@link ContextSource} implementation. * @param userDn the user DN to authenticate, as received from the * {@link AuthenticationSource} of the {@link ContextSource}. * @param password the password to authenticate with, as received from the * {@link AuthenticationSource} of the {@link ContextSource}. * @return the DirContext, possibly modified, replaced or wrapped. * @throws NamingException if anything goes wrong. This will cause the * DirContext creation to be aborted and the exception to be * translated and rethrown. */ public DirContext processContextAfterCreation(DirContext ctx, String userDn, String password) throws NamingException; } ././@LongLink0000000000000000000000000000023500000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/CollectingAuthenticationErrorCallback.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000303211475313376030207 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import org.springframework.ldap.core.AuthenticationErrorCallback; /** * Convenience implementation of AuthenticationErrorCallback that stores the * given exception and provides a method for retrieving it. The caller of the * authenticate method can provide an instance of this class as an error * callback. If the authentication fails, the caller can ask the callback * instance for the actual authentication exception. * * @author Ulrik Sandberg * @since 1.3.1 */ public final class CollectingAuthenticationErrorCallback implements AuthenticationErrorCallback { private Exception error; /* * (non-Javadoc) * * @see * org.springframework.ldap.core.AuthenticationErrorCallback#execute(java * .lang.Exception) */ public void execute(Exception e) { this.error = e; } /** * @return the collected exception */ public Exception getError() { return error; } }././@LongLink0000000000000000000000000000024300000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/AbstractTlsDirContextAuthenticationStrategy.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000002044011475313376030211 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Hashtable; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.ldap.LdapContext; import javax.naming.ldap.StartTlsRequest; import javax.naming.ldap.StartTlsResponse; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSocketFactory; import org.springframework.ldap.UncategorizedLdapException; import org.springframework.ldap.core.DirContextProxy; import org.springframework.ldap.support.LdapUtils; /** * Abstract superclass for {@link DirContextAuthenticationStrategy} * implementations that apply TLS security to the connections. The supported TLS * behavior differs between servers. E.g., some servers expect the TLS * connection be shut down gracefully before the actual target context is * closed, whereas other servers do not support that. The * shutdownTlsGracefully property controls this behavior; the * property defaults to false. *

* The SSLSocketFactory used for TLS negotiation can be customized * using the sslSocketFactory property. This allows for example a * socket factory that can load the keystore/truststore using the Spring * Resource abstraction. This provides a much more Spring-like strategy for * configuring PKI credentials for authentication, in addition to allowing * application-specific keystores and truststores running in the same JVM. *

* In some rare occasions there is a need to supply a * HostnameVerifier to the TLS processing instructions in order to * have the returned certificate properly validated. If a * HostnameVerifier is supplied to * {@link #setHostnameVerifier(HostnameVerifier)}, that will be applied to the * processing. *

*

* For further information regarding TLS, refer to this * page. *

* NB: TLS negotiation is an expensive process, which is why you will * most likely want to use connection pooling, to make sure new connections are * not created for each individual request. It is imperative however, that the * built-in LDAP connection pooling is not used in combination with the TLS * AuthenticationStrategy implementations - this will not work. You should use * the Spring LDAP PoolingContextSource instead. * * @author Mattias Hellborg Arthursson */ public abstract class AbstractTlsDirContextAuthenticationStrategy implements DirContextAuthenticationStrategy { /** Hostname verifier to use for cert subject validation */ private HostnameVerifier hostnameVerifier; /** Flag to cause graceful shutdown required by some LDAP DSAs */ private boolean shutdownTlsGracefully = false; /** SSL socket factory to use for startTLS negotiation */ private SSLSocketFactory sslSocketFactory; /** * Specify whether the TLS should be shut down gracefully before the target * context is closed. Defaults to false. * * @param shutdownTlsGracefully true to shut down the TLS * connection explicitly, false closes the target context * immediately. */ public void setShutdownTlsGracefully(boolean shutdownTlsGracefully) { this.shutdownTlsGracefully = shutdownTlsGracefully; } /** * Set the optional * HostnameVerifier to use for verifying incoming certificates. Defaults to null * , meaning that the default hostname verification will take place. * * @param hostnameVerifier The HostnameVerifier to use, if any. */ public void setHostnameVerifier(HostnameVerifier hostnameVerifier) { this.hostnameVerifier = hostnameVerifier; } /** * Sets the optional SSL socket factory used for startTLS negotiation. * Defaults to null to indicate that the default socket factory * provided by the underlying JSSE provider should be used. * @param sslSocketFactory SSL socket factory to use, if any. */ public void setSslSocketFactory(final SSLSocketFactory sslSocketFactory) { this.sslSocketFactory = sslSocketFactory; } /* (non-Javadoc) * @see org.springframework.ldap.core.support.DirContextAuthenticationStrategy#setupEnvironment(java.util.Hashtable, java.lang.String, java.lang.String) */ public final void setupEnvironment(Hashtable env, String userDn, String password) { // Nothing to do in this implementation - authentication should take // place after TLS has been negotiated. } /* (non-Javadoc) * @see org.springframework.ldap.core.support.DirContextAuthenticationStrategy#processContextAfterCreation(javax.naming.directory.DirContext, java.lang.String, java.lang.String) */ public final DirContext processContextAfterCreation(DirContext ctx, String userDn, String password) throws NamingException { if (ctx instanceof LdapContext) { final LdapContext ldapCtx = (LdapContext) ctx; final StartTlsResponse tlsResponse = (StartTlsResponse) ldapCtx.extendedOperation(new StartTlsRequest()); try { if (hostnameVerifier != null) { tlsResponse.setHostnameVerifier(hostnameVerifier); } tlsResponse.negotiate(sslSocketFactory); // If null, the default SSL socket factory is used applyAuthentication(ldapCtx, userDn, password); if (shutdownTlsGracefully) { // Wrap the target context in a proxy to intercept any calls // to 'close', so that we can shut down the TLS connection // gracefully first. return (DirContext) Proxy.newProxyInstance(DirContextProxy.class.getClassLoader(), new Class[] { LdapContext.class, DirContextProxy.class }, new TlsAwareDirContextProxy(ldapCtx, tlsResponse)); } else { return ctx; } } catch (IOException e) { LdapUtils.closeContext(ctx); throw new UncategorizedLdapException("Failed to negotiate TLS session", e); } } else { throw new IllegalArgumentException( "Processed Context must be an LDAPv3 context, i.e. an LdapContext implementation"); } } /** * Apply the actual authentication to the specified LdapContext * . Typically, this will involve adding stuff to the environment. * * @param ctx the LdapContext instance. * @param userDn the user dn of the user to authenticate. * @param password the password of the user to authenticate. * @throws NamingException if any error occurs. */ protected abstract void applyAuthentication(LdapContext ctx, String userDn, String password) throws NamingException; private static final class TlsAwareDirContextProxy implements DirContextProxy, InvocationHandler { private static final String GET_TARGET_CONTEXT_METHOD_NAME = "getTargetContext"; private static final String CLOSE_METHOD_NAME = "close"; private final LdapContext target; private final StartTlsResponse tlsResponse; public TlsAwareDirContextProxy(LdapContext target, StartTlsResponse tlsResponse) { this.target = target; this.tlsResponse = tlsResponse; } public DirContext getTargetContext() { return target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals(CLOSE_METHOD_NAME)) { tlsResponse.close(); return method.invoke(target, args); } else if (method.getName().equals(GET_TARGET_CONTEXT_METHOD_NAME)) { return target; } else { return method.invoke(target, args); } } } } ././@LongLink0000000000000000000000000000021100000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/BaseLdapPathAware.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000361411475313376030215 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import org.springframework.ldap.core.DistinguishedName; /** * Interface to be implemented by classes that want to have access to the base * context used in the active ContextSource. There are several * cases in which services may want to have access to the base context, e.g. * when working with groups (groupOfNames objectclass), in which * case the full DN of each group member needs to be specified in the attribute * value. *

* If a class implements this interface and a * {@link BaseLdapPathBeanPostProcessor} is defined in the * ApplicationContext, the default base path will automatically * passed to the {@link #setBaseLdapPath(DistinguishedName)} method on * initialization. *

* NB:The ContextSource needs to be a subclass of * {@link AbstractContextSource} for this mechanism to work. * * * @author Mattias Hellborg Arthursson * @since 1.2 */ public interface BaseLdapPathAware { /** * Set the base LDAP path specified in the current * ApplicationContext. * @param baseLdapPath the base path used in the ContextSource */ void setBaseLdapPath(DistinguishedName baseLdapPath); } ././@LongLink0000000000000000000000000000024100000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/DigestMd5DirContextAuthenticationStrategy.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000360711475313376030217 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import java.util.Hashtable; import javax.naming.Context; import javax.naming.directory.DirContext; /** * Authentication strategy for LDAP DIGEST-MD5 SASL mechanism. * * @author Marvin S. Addison * @since 1.3.1 */ public class DigestMd5DirContextAuthenticationStrategy implements DirContextAuthenticationStrategy { /** Authentication type for DIGEST-MD5 auth */ private static final String DIGEST_MD5_AUTHENTICATION = "DIGEST-MD5"; /* * (non-Javadoc) * @see org.springframework.ldap.core.support.DirContextAuthenticationStrategy#processContextAfterCreation(javax.naming.directory.DirContext, * java.lang.String, java.lang.String) */ public DirContext processContextAfterCreation(DirContext ctx, String userDn, String password) { return ctx; } /* * (non-Javadoc) * @see org.springframework.ldap.core.support.DirContextAuthenticationStrategy#setupEnvironment(java.util.Hashtable, * java.lang.String, java.lang.String) */ public void setupEnvironment(Hashtable env, String userDn, String password) { env.put(Context.SECURITY_AUTHENTICATION, DIGEST_MD5_AUTHENTICATION); // userDn should be a bare username for DIGEST-MD5 env.put(Context.SECURITY_PRINCIPAL, userDn); env.put(Context.SECURITY_CREDENTIALS, password); } } ././@LongLink0000000000000000000000000000021500000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/AbstractContextMapper.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000412111475313376030207 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import org.springframework.ldap.core.ContextMapper; import org.springframework.ldap.core.DirContextOperations; /** * Abstract superclass that may be used instead of implementing * {@link ContextMapper} directly. Subclassing from this superclass, the * supplied context will be automatically cast to * DirContextOperations. Note that if you use your own * DirObjectFactory, this implementation will fail with a * ClassCastException. * * @author Mattias Hellborg Arthursson * */ public abstract class AbstractContextMapper implements ContextMapper { /** * {@inheritDoc} * * @throws ClassCastException * if a custom DirObjectFactory implementation is * used, causing the objects passed in be anything else than * {@link DirContextOperations} instances. */ public final Object mapFromContext(Object ctx) { return doMapFromContext((DirContextOperations) ctx); } /** * Map a single DirContextOperation to an object. The * supplied instance is the object supplied to * {@link #mapFromContext(Object)} cast to a * DirContextOperations. * * @param ctx * the context to map to an object. * @return an object built from the data in the context. */ protected abstract Object doMapFromContext(DirContextOperations ctx); } ././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000012511475313376030207 0ustar Support classes the core Spring LDAP package. ././@LongLink0000000000000000000000000000021000000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/DirContextSource.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000322311475313376030211 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import java.util.Hashtable; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; /** * ContextSource implementation which creates InitialDirContext instances, for * LDAPv2 compatibility. For configuration information, see * {@link org.springframework.ldap.core.support.AbstractContextSource AbstractContextSource}. * * @see org.springframework.ldap.core.support.AbstractContextSource * * @author Mattias Hellborg Arthursson */ public class DirContextSource extends AbstractContextSource { /** * Create a new InitialDirContext instance. * * @param environment * the environment to use when creating the context. * @return a new InitialDirContext implementation. */ protected DirContext getDirContextInstance(Hashtable environment) throws NamingException { return new InitialDirContext(environment); } } ././@LongLink0000000000000000000000000000021700000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/DefaultDirObjectFactory.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001534711475313376030223 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import java.net.URI; import java.net.URISyntaxException; import java.util.Hashtable; import javax.naming.CompositeName; import javax.naming.Context; import javax.naming.Name; import javax.naming.directory.Attributes; import javax.naming.spi.DirObjectFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.core.JdkVersion; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.support.LdapUtils; import org.springframework.util.StringUtils; /** * Default implementation of the DirObjectFactory interface. Creates a * {@link DirContextAdapter} from the supplied arguments. * * @author Mattias Hellborg Arthursson */ public class DefaultDirObjectFactory implements DirObjectFactory { private static final Log log = LogFactory.getLog(DefaultDirObjectFactory.class); /** * Key to use in the ContextSource implementation to store the value of the * base path suffix, if any, in the Ldap Environment. * * @deprecated Use {@link BaseLdapPathAware} and * {@link BaseLdapPathBeanPostProcessor} instead. */ public static final String JNDI_ENV_BASE_PATH_KEY = "org.springframework.ldap.base.path"; private static final String LDAP_PROTOCOL_PREFIX = "ldap://"; private static final String LDAPS_PROTOCOL_PREFIX = "ldaps://"; /* * (non-Javadoc) * * @see * javax.naming.spi.DirObjectFactory#getObjectInstance(java.lang.Object, * javax.naming.Name, javax.naming.Context, java.util.Hashtable, * javax.naming.directory.Attributes) */ public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment, Attributes attrs) throws Exception { try { String nameInNamespace = null; if (nameCtx != null) { nameInNamespace = nameCtx.getNameInNamespace(); } else { nameInNamespace = ""; } return constructAdapterFromName(attrs, name, nameInNamespace); } finally { // It seems that the object supplied to the obj parameter is a // DirContext instance with reference to the same Ldap connection as // the original context. Since it is not the same instance (that's // the nameCtx parameter) this one really needs to be closed in // order to correctly clean up and return the connection to the pool // when we're finished with the surrounding operation. if (obj instanceof Context) { Context ctx = (Context) obj; try { ctx.close(); } catch (Exception e) { // Never mind this } } } } /** * Construct a DirContextAdapter given the supplied paramters. The * name is normally a JNDI CompositeName, which * needs to be handled with particuclar care. Specifically the escaping of a * CompositeName destroys proper escaping of Distinguished * Names. Also, the name might contain referral information, in which case * we need to separate the server information from the actual Distinguished * Name so that we can create a representing DirContextAdapter. * * @param attrs the attributes * @param name the Name, typically a CompositeName, possibly * including referral information. * @param nameInNamespace the Name in namespace. * @return a {@link DirContextAdapter} representing the specified * information. */ DirContextAdapter constructAdapterFromName(Attributes attrs, Name name, String nameInNamespace) { String nameString = ""; String referralUrl = ""; if (name instanceof CompositeName) { // Which it most certainly will be, and therein lies the // problem. CompositeName.toString() completely screws up the // formatting // in some cases, particularly when backslashes are involved. nameString = LdapUtils .convertCompositeNameToString((CompositeName) name); } else { log .warn("Expecting a CompositeName as input to getObjectInstance but received a '" + name.getClass().toString() + "' - using toString and proceeding with undefined results"); nameString = name.toString(); } if (nameString.startsWith(LDAP_PROTOCOL_PREFIX) || nameString.startsWith(LDAPS_PROTOCOL_PREFIX)) { if (log.isDebugEnabled()) { log.debug("Received name '" + nameString + "' contains protocol delimiter; indicating a referral." + "Stripping protocol and address info to enable construction of a proper DistinguishedName"); } try { URI url = new URI(nameString); String pathString = url.getPath(); referralUrl = nameString.substring(0, nameString.length() - pathString.length()); if (StringUtils.hasLength(pathString) && pathString.startsWith("/")) { // We don't want any slash in the beginning of the // Distinguished Name. pathString = pathString.substring(1); } nameString = pathString; } catch (URISyntaxException e) { if (JdkVersion.isAtLeastJava15()) { throw new IllegalArgumentException( "Supplied name starts with protocol prefix indicating a referral," + " but is not possible to parse to an URI", e); } else { throw new IllegalArgumentException( "Supplied name starts with protocol prefix indicating a referral," + " but is not possible to parse to an URI: " + e.getMessage()); } } if (log.isDebugEnabled()) { log.debug("Resulting name after removal of referral information: '" + nameString + "'"); } } DirContextAdapter dirContextAdapter = new DirContextAdapter(attrs, new DistinguishedName(nameString), new DistinguishedName(nameInNamespace), referralUrl); dirContextAdapter.setUpdateMode(true); return dirContextAdapter; } /* * (non-Javadoc) * * @see javax.naming.spi.ObjectFactory#getObjectInstance(java.lang.Object, * javax.naming.Name, javax.naming.Context, java.util.Hashtable) */ public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { return null; } } ././@LongLink0000000000000000000000000000024200000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/DefaultTlsDirContextAuthenticationStrategy.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000320511475313376030211 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import javax.naming.Context; import javax.naming.NamingException; import javax.naming.ldap.LdapContext; /** * Default implementation of TLS authentication. Applies SIMPLE * authentication on top of the negotiated TLS session. Refer to * {@link AbstractTlsDirContextAuthenticationStrategy} for configuration * options. * * @author Mattias Hellborg Arthursson * @see AbstractTlsDirContextAuthenticationStrategy * @see AbstractContextSource */ public class DefaultTlsDirContextAuthenticationStrategy extends AbstractTlsDirContextAuthenticationStrategy { private static final String SIMPLE_AUTHENTICATION = "simple"; protected void applyAuthentication(LdapContext ctx, String userDn, String password) throws NamingException { ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, SIMPLE_AUTHENTICATION); ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDn); ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password); } } ././@LongLink0000000000000000000000000000022100000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/BaseLdapPathContextSource.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000172211475313376030213 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import org.springframework.ldap.core.ContextSource; /** * Interface to be implemented by ContextSources that are capable * of providing the base LDAP path. * * @author Mattias Hellborg Arthursson */ public interface BaseLdapPathContextSource extends ContextSource, BaseLdapPathSource { } ././@LongLink0000000000000000000000000000021300000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/SingleContextSource.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001157111475313376030216 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import javax.naming.directory.DirContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.NamingException; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DirContextProxy; import org.springframework.ldap.support.LdapUtils; import org.springframework.beans.factory.DisposableBean; /** * A {@link ContextSource} to be used as a decorator around a target ContextSource * to make sure the target is never actually closed. Useful when working with e.g. paged results, * as these require the same target to be used. * * @author Mattias Hellborg Arthursson */ public class SingleContextSource implements ContextSource, DisposableBean { private static final Log log = LogFactory.getLog(SingleContextSource.class); private final DirContext ctx; /** * Constructor. * * @param ctx the target DirContext. */ public SingleContextSource(DirContext ctx) { this.ctx = ctx; } /* * @see org.springframework.ldap.ContextSource#getReadOnlyContext() */ public DirContext getReadOnlyContext() throws NamingException { return getNonClosingDirContextProxy(ctx); } /* * @see org.springframework.ldap.ContextSource#getReadWriteContext() */ public DirContext getReadWriteContext() throws NamingException { return getNonClosingDirContextProxy(ctx); } private DirContext getNonClosingDirContextProxy(DirContext context) { return (DirContext) Proxy.newProxyInstance(DirContextProxy.class .getClassLoader(), new Class[]{ LdapUtils.getActualTargetClass(context), DirContextProxy.class}, new SingleContextSource.NonClosingDirContextInvocationHandler( context)); } public DirContext getContext(String principal, String credentials) throws NamingException { throw new UnsupportedOperationException( "Not a valid operation for this type of ContextSource"); } /** * Destroy method that allows the target DirContext to be cleaned up when * the SingleContextSource is not going to be used any more. */ public void destroy() { try { ctx.close(); } catch (javax.naming.NamingException e) { log.warn(e); } } /** * A proxy for DirContext forwarding all operation to the target DirContext, * but making sure that no close operations will be performed. * * @author Mattias Hellborg Arthursson */ public static class NonClosingDirContextInvocationHandler implements InvocationHandler { private DirContext target; public NonClosingDirContextInvocationHandler(DirContext target) { this.target = target; } /* * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, * java.lang.reflect.Method, java.lang.Object[]) */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if (methodName.equals("getTargetContext")) { return target; } else if (methodName.equals("equals")) { // Only consider equal when proxies are identical. return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE); } else if (methodName.equals("hashCode")) { // Use hashCode of Connection proxy. return new Integer(proxy.hashCode()); } else if (methodName.equals("close")) { // Never close the target context, as this class will only be // used for operations concerning the compensating transactions. return null; } try { return method.invoke(target, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } } } }././@LongLink0000000000000000000000000000022400000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/AggregateDirContextProcessor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000603111475313376030211 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.naming.NamingException; import javax.naming.directory.DirContext; import org.springframework.ldap.core.DirContextProcessor; /** * Manages a sequence of {@link DirContextProcessor} instances. Applies * {@link #preProcess(DirContext)} and {@link #postProcess(DirContext)} * respectively in sequence on the managed objects. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class AggregateDirContextProcessor implements DirContextProcessor { private List dirContextProcessors = new LinkedList(); /** * Add the supplied DirContextProcessor to the list of managed objects. * * @param processor * the DirContextpProcessor to add. */ public void addDirContextProcessor(DirContextProcessor processor) { dirContextProcessors.add(processor); } /** * Get the list of managed {@link DirContextProcessor} instances. * * @return the managed list of {@link DirContextProcessor} instances. */ public List getDirContextProcessors() { return dirContextProcessors; } /** * Set the list of managed {@link DirContextProcessor} instances. * * @param dirContextProcessors * the list of {@link DirContextProcessor} instances to set. */ public void setDirContextProcessors(List dirContextProcessors) { this.dirContextProcessors = dirContextProcessors; } /* * @see org.springframework.ldap.core.DirContextProcessor#preProcess(javax.naming.directory.DirContext) */ public void preProcess(DirContext ctx) throws NamingException { for (Iterator iter = dirContextProcessors.iterator(); iter.hasNext();) { DirContextProcessor processor = (DirContextProcessor) iter.next(); processor.preProcess(ctx); } } /* * @see org.springframework.ldap.core.DirContextProcessor#postProcess(javax.naming.directory.DirContext) */ public void postProcess(DirContext ctx) throws NamingException { for (Iterator iter = dirContextProcessors.iterator(); iter.hasNext();) { DirContextProcessor processor = (DirContextProcessor) iter.next(); processor.postProcess(ctx); } } } ././@LongLink0000000000000000000000000000021100000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/LdapContextSource.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000313311475313376030211 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import java.util.Hashtable; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.ldap.InitialLdapContext; /** * ContextSource implementation which creates an InitialLdapContext * instance. For configuration information, see * {@link org.springframework.ldap.core.support.AbstractContextSource AbstractContextSource}. * * @see org.springframework.ldap.core.support.AbstractContextSource * * @author Mattias Hellborg Arthursson * @author Adam Skogman * @author Ulrik Sandberg */ public class LdapContextSource extends AbstractContextSource { /* * @see org.springframework.ldap.support.AbstractContextSource#getDirContextInstance(java.util.Hashtable) */ protected DirContext getDirContextInstance(Hashtable environment) throws NamingException { return new InitialLdapContext(environment, null); } } ././@LongLink0000000000000000000000000000022500000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/BaseLdapPathBeanPostProcessor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001226211475313376030214 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.ldap.core.DistinguishedName; import org.springframework.util.StringUtils; /** * This BeanPostProcessor checks each bean if it implements * {@link BaseLdapPathAware}. If it does, the default context base LDAP path * will be determined, and that value will be injected to the * {@link BaseLdapPathAware#setBaseLdapPath(DistinguishedName)} method of the * processed bean. *

* If the baseLdapPath property of this * BeanPostProcessor is set, that value will be used. Otherwise, in * order to determine which base LDAP path to supply to the instance the * ApplicationContext is searched for any beans that are * implementations of {@link BaseLdapPathSource}. If one single occurrence is * found, that instance is queried for its base path, and that is what will be * injected. If more than one {@link BaseLdapPathSource} instance is configured * in the ApplicationContext, the name of the one to use will need * to be specified to the baseLdapPathSourceName property; * otherwise the post processing will fail. If no {@link BaseLdapPathSource} * implementing bean is found in the context and the basePath * property is not set, post processing will also fail. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class BaseLdapPathBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware { private ApplicationContext applicationContext; private DistinguishedName basePath; private String baseLdapPathSourceName; public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof BaseLdapPathAware) { BaseLdapPathAware baseLdapPathAware = (BaseLdapPathAware) bean; if (basePath != null) { baseLdapPathAware.setBaseLdapPath(basePath); } else { BaseLdapPathSource ldapPathSource = getBaseLdapPathSourceFromApplicationContext(); baseLdapPathAware.setBaseLdapPath(ldapPathSource.getBaseLdapPath().immutableDistinguishedName()); } } return bean; } BaseLdapPathSource getBaseLdapPathSourceFromApplicationContext() { if (StringUtils.hasLength(baseLdapPathSourceName)) { return (BaseLdapPathSource) applicationContext.getBean(baseLdapPathSourceName); } String[] definedContextSources = applicationContext.getBeanNamesForType(BaseLdapPathSource.class); if (definedContextSources.length < 1) { throw new NoSuchBeanDefinitionException("No BaseLdapPathSource implementation definition found"); } else if (definedContextSources.length > 1) { throw new NoSuchBeanDefinitionException( "More than BaseLdapPathSource implementation definition found in current ApplicationContext"); } return (BaseLdapPathSource) applicationContext.getBean(definedContextSources[0]); } /* * (non-Javadoc) * * @seeorg.springframework.beans.factory.config.BeanPostProcessor# * postProcessAfterInitialization(java.lang.Object, java.lang.String) */ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // Do nothing for this implementation return bean; } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } /** * Set the base path to be injected in all {@link BaseLdapPathAware} beans. * If this property is not set, the default base path will be determined * from any defined {@link BaseLdapPathSource} instances available in the * ApplicationContext. * * @param basePath the base path. */ public void setBasePath(DistinguishedName basePath) { this.basePath = basePath.immutableDistinguishedName(); } /** * Set the name of the ContextSource bean to use for getting * the base path. This method is typically useful if several ContextSource * instances have been configured. * * @param contextSourceName the name of the ContextSource bean * to use for determining the base path. */ public void setBaseLdapPathSourceName(String contextSourceName) { this.baseLdapPathSourceName = contextSourceName; } } ././@LongLink0000000000000000000000000000024300000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/ExternalTlsDirContextAuthenticationStrategy.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000207611475313376030216 0ustar package org.springframework.ldap.core.support; import javax.naming.Context; import javax.naming.NamingException; import javax.naming.ldap.LdapContext; /** * {@link DirContextAuthenticationStrategy} for using TLS and external (SASL) * authentication. This implementation requires a client certificate to be * pointed out using system variables, as described here. Refer to {@link AbstractTlsDirContextAuthenticationStrategy} for * other configuration options. * * @author Mattias Hellborg Arthursson * @see AbstractTlsDirContextAuthenticationStrategy * @see AbstractContextSource */ public class ExternalTlsDirContextAuthenticationStrategy extends AbstractTlsDirContextAuthenticationStrategy { private static final String EXTERNAL_AUTHENTICATION = "EXTERNAL"; protected void applyAuthentication(LdapContext ctx, String userDn, String password) throws NamingException { ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, EXTERNAL_AUTHENTICATION); } } ././@LongLink0000000000000000000000000000023600000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/SimpleDirContextAuthenticationStrategy.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000412011475313376030206 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import java.util.Hashtable; import javax.naming.Context; import javax.naming.directory.DirContext; /** * The default {@link DirContextAuthenticationStrategy} implementation, setting * the DirContext environment up for 'SIMPLE' authentication, and * specifying the user DN and password as SECURITY_PRINCIPAL and * SECURITY_CREDENTIALS respectively in the authenticated environment before the * context is created. * * @author Mattias Hellborg Arthursson */ public class SimpleDirContextAuthenticationStrategy implements DirContextAuthenticationStrategy { private static final String SIMPLE_AUTHENTICATION = "simple"; /* * (non-Javadoc) * @see org.springframework.ldap.core.support.DirContextAuthenticationStrategy#setupEnvironment(java.util.Hashtable, * java.lang.String, java.lang.String) */ public void setupEnvironment(Hashtable env, String userDn, String password) { env.put(Context.SECURITY_AUTHENTICATION, SIMPLE_AUTHENTICATION); env.put(Context.SECURITY_PRINCIPAL, userDn); env.put(Context.SECURITY_CREDENTIALS, password); } /* * (non-Javadoc) * @see org.springframework.ldap.core.support.DirContextAuthenticationStrategy#processContextAfterCreation(javax.naming.directory.DirContext, * java.lang.String, java.lang.String) */ public DirContext processContextAfterCreation(DirContext ctx, String userDn, String password) { return ctx; } } ././@LongLink0000000000000000000000000000021500000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/AbstractContextSource.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000004475411475313376030227 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import java.util.Hashtable; import java.util.Map; import javax.naming.Context; import javax.naming.NamingException; import javax.naming.directory.DirContext; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.JdkVersion; import org.springframework.ldap.core.AuthenticationSource; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.support.LdapUtils; /** * Abstract implementation of the {@link ContextSource} interface. By default, * returns an authenticated * DirContext implementation for both read-only and * read-write operations. To have an anonymous environment created for read-only * operations, set the anonymousReadOnly property to * true. *

* Implementing classes need to implement * {@link #getDirContextInstance(Hashtable)} to create a DirContext * instance of the desired type. *

* If an {@link AuthenticationSource} is set, this will be used for getting user * principal and password for each new connection, otherwise a default one will * be created using the specified userDn and password. *

* Note: When using implementations of this class outside of a Spring * Context it is necessary to call {@link #afterPropertiesSet()} when all * properties are set, in order to finish up initialization. * * @see org.springframework.ldap.core.LdapTemplate * @see org.springframework.ldap.core.support.DefaultDirObjectFactory * @see org.springframework.ldap.core.support.LdapContextSource * @see org.springframework.ldap.core.support.DirContextSource * * @author Mattias Hellborg Arthursson * @author Adam Skogman * @author Ulrik Sandberg */ public abstract class AbstractContextSource implements BaseLdapPathContextSource, InitializingBean { private static final Class DEFAULT_CONTEXT_FACTORY = com.sun.jndi.ldap.LdapCtxFactory.class; private static final Class DEFAULT_DIR_OBJECT_FACTORY = DefaultDirObjectFactory.class; private Class dirObjectFactory = DEFAULT_DIR_OBJECT_FACTORY; private Class contextFactory = DEFAULT_CONTEXT_FACTORY; private DistinguishedName base = DistinguishedName.EMPTY_PATH; protected String userDn = ""; protected String password = ""; private String[] urls; private boolean pooled = false; private Hashtable baseEnv = new Hashtable(); private Hashtable anonymousEnv; private AuthenticationSource authenticationSource; private boolean cacheEnvironmentProperties = true; private boolean anonymousReadOnly = false; private String referral = null; private static final Log log = LogFactory.getLog(AbstractContextSource.class); public static final String SUN_LDAP_POOLING_FLAG = "com.sun.jndi.ldap.connect.pool"; private static final String JDK_142 = "1.4.2"; private DirContextAuthenticationStrategy authenticationStrategy = new SimpleDirContextAuthenticationStrategy(); public DirContext getContext(String principal, String credentials) { DirContext ctx = createContext(getAuthenticatedEnv(principal, credentials)); try { authenticationStrategy.processContextAfterCreation(ctx, principal, credentials); return ctx; } catch (NamingException e) { closeContext(ctx); throw LdapUtils.convertLdapException(e); } } /* * (non-Javadoc) * * @see org.springframework.ldap.core.ContextSource#getReadOnlyContext() */ public DirContext getReadOnlyContext() { if (!anonymousReadOnly) { return getContext(authenticationSource.getPrincipal(), authenticationSource.getCredentials()); } else { return createContext(getAnonymousEnv()); } } /* * (non-Javadoc) * * @see org.springframework.ldap.core.ContextSource#getReadWriteContext() */ public DirContext getReadWriteContext() { return getContext(authenticationSource.getPrincipal(), authenticationSource.getCredentials()); } /** * Default implementation of setting the environment up to be authenticated. * This method should typically NOT be overridden; any customization to the * authentication mechanism should be managed by setting a different * {@link DirContextAuthenticationStrategy} on this instance. * * @param env the environment to modify. * @param principal the principal to authenticate with. * @param credentials the credentials to authenticate with. * @see DirContextAuthenticationStrategy * @see #setAuthenticationStrategy(DirContextAuthenticationStrategy) */ protected void setupAuthenticatedEnvironment(Hashtable env, String principal, String credentials) { try { authenticationStrategy.setupEnvironment(env, principal, credentials); } catch (NamingException e) { throw LdapUtils.convertLdapException(e); } } /** * Close the context and swallow any exceptions. * * @param ctx the DirContext to close. */ private void closeContext(DirContext ctx) { if (ctx != null) { try { ctx.close(); } catch (Exception e) { } } } /** * Assemble a valid url String from all registered urls to add as * PROVIDER_URL to the environment. * * @param ldapUrls all individual url Strings. * @return the full url String */ protected String assembleProviderUrlString(String[] ldapUrls) { StringBuffer providerUrlBuffer = new StringBuffer(1024); for (int i = 0; i < ldapUrls.length; i++) { providerUrlBuffer.append(ldapUrls[i]); if (!DistinguishedName.EMPTY_PATH.equals(base)) { if (!ldapUrls[i].endsWith("/")) { providerUrlBuffer.append("/"); } } providerUrlBuffer.append(base.toUrl()); providerUrlBuffer.append(' '); } return providerUrlBuffer.toString().trim(); } /** * Set the base suffix from which all operations should origin. If a base * suffix is set, you will not have to (and, indeed, must not) specify the * full distinguished names in any operations performed. * * @param base the base suffix. */ public void setBase(String base) { this.base = new DistinguishedName(base); } /** * Get the base suffix from which all operations should originate. If a base * suffix is set, you will not have to (and, indeed, must not) specify the * full distinguished names in any operations performed. * * @return the base suffix */ protected DistinguishedName getBase() { return new DistinguishedName(base); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.support.BaseLdapPathSource#getBaseLdapPath * () */ public DistinguishedName getBaseLdapPath() { return getBase().immutableDistinguishedName(); } /* * (non-Javadoc) * * @seeorg.springframework.ldap.core.support.BaseLdapPathSource# * getBaseLdapPathAsString() */ public String getBaseLdapPathAsString() { return getBaseLdapPath().toString(); } /** * Create a DirContext using the supplied environment. * * @param environment the LDAP environment to use when creating the * DirContext. * @return a new DirContext implementation initialized with the supplied * environment. */ protected DirContext createContext(Hashtable environment) { DirContext ctx = null; try { ctx = getDirContextInstance(environment); if (log.isInfoEnabled()) { Hashtable ctxEnv = ctx.getEnvironment(); String ldapUrl = (String) ctxEnv.get(Context.PROVIDER_URL); log.debug("Got Ldap context on server '" + ldapUrl + "'"); } return ctx; } catch (NamingException e) { closeContext(ctx); throw LdapUtils.convertLdapException(e); } } /** * Set the context factory. Default is com.sun.jndi.ldap.LdapCtxFactory. * * @param contextFactory the context factory used when creating Contexts. */ public void setContextFactory(Class contextFactory) { this.contextFactory = contextFactory; } /** * Get the context factory. * * @return the context factory used when creating Contexts. */ public Class getContextFactory() { return contextFactory; } /** * Set the DirObjectFactory to use. Default is * {@link DefaultDirObjectFactory}. The specified class needs to be an * implementation of javax.naming.spi.DirObjectFactory. Note: Setting * this value to null may have cause connection leaks when using * ContextMapper methods in LdapTemplate. * * @param dirObjectFactory the DirObjectFactory to be used. Null means that * no DirObjectFactory will be used. */ public void setDirObjectFactory(Class dirObjectFactory) { this.dirObjectFactory = dirObjectFactory; } /** * Get the DirObjectFactory to use. * * @return the DirObjectFactory to be used. null means that no * DirObjectFactory will be used. */ public Class getDirObjectFactory() { return dirObjectFactory; } /** * Checks that all necessary data is set and that there is no compatibility * issues, after which the instance is initialized. Note that you need to * call this method explicitly after setting all desired properties if using * the class outside of a Spring Context. */ public void afterPropertiesSet() throws Exception { if (ArrayUtils.isEmpty(urls)) { throw new IllegalArgumentException("At least one server url must be set"); } if (!DistinguishedName.EMPTY_PATH.equals(base) && getJdkVersion().compareTo(JDK_142) < 0) { throw new IllegalArgumentException("Base path is not supported for JDK versions < 1.4.2"); } if (authenticationSource == null) { log.debug("AuthenticationSource not set - " + "using default implementation"); if (StringUtils.isBlank(userDn)) { log.info("Property 'userDn' not set - " + "anonymous context will be used for read-write operations"); } else if (StringUtils.isBlank(password)) { log.info("Property 'password' not set - " + "blank password will be used"); } authenticationSource = new SimpleAuthenticationSource(); } if (cacheEnvironmentProperties) { anonymousEnv = setupAnonymousEnv(); } } private Hashtable setupAnonymousEnv() { if (pooled) { baseEnv.put(SUN_LDAP_POOLING_FLAG, "true"); log.debug("Using LDAP pooling."); } else { baseEnv.remove(SUN_LDAP_POOLING_FLAG); log.debug("Not using LDAP pooling"); } Hashtable env = new Hashtable(baseEnv); env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory.getName()); env.put(Context.PROVIDER_URL, assembleProviderUrlString(urls)); if (dirObjectFactory != null) { env.put(Context.OBJECT_FACTORIES, dirObjectFactory.getName()); } if (!StringUtils.isBlank(referral)) { env.put(Context.REFERRAL, referral); } if (!DistinguishedName.EMPTY_PATH.equals(base)) { // Save the base path for use in the DefaultDirObjectFactory. env.put(DefaultDirObjectFactory.JNDI_ENV_BASE_PATH_KEY, base); } log.debug("Trying provider Urls: " + assembleProviderUrlString(urls)); return env; } /** * Set the password (credentials) to use for getting authenticated contexts. * * @param password the password. */ public void setPassword(String password) { this.password = password; } /** * Set the user distinguished name (principal) to use for getting * authenticated contexts. * * @param userDn the user distinguished name. */ public void setUserDn(String userDn) { this.userDn = userDn; } /** * Set the urls of the LDAP servers. Use this method if several servers are * required. * * @param urls the urls of all servers. */ public void setUrls(String[] urls) { this.urls = (String[]) urls.clone(); } /** * Get the urls of the LDAP servers. * * @return the urls of all servers. */ public String[] getUrls() { return (String[]) urls.clone(); } /** * Set the url of the LDAP server. Utility method if only one server is * used. * * @param url the url of the LDAP server. */ public void setUrl(String url) { this.urls = new String[] { url }; } /** * Set whether the pooling flag should be set, enabling the built-in LDAP * connection pooling. Default is false. The built-in LDAP * connection pooling suffers from a number of deficiencies, e.g. no * connection validation. Also, enabling this flag when using TLS * connections will explicitly not work. Consider using the Spring LDAP * PoolingContextSource as an alternative instead of enabling * this flag. *

* Note that since LDAP pooling is system wide, full configuration of this * needs be done using system parameters as specified in the LDAP/JNDI * documentation. Also note, that pooling is done on user dn basis, i.e. * each individually authenticated connection will be pooled separately. * This means that LDAP pooling will be most efficient using anonymous * connections or connections authenticated using one single system user. * * @param pooled whether Contexts should be pooled. */ public void setPooled(boolean pooled) { this.pooled = pooled; } /** * Get whether the pooling flag should be set. * * @return whether Contexts should be pooled. */ public boolean isPooled() { return pooled; } /** * If any custom environment properties are needed, these can be set using * this method. * * @param baseEnvironmentProperties */ public void setBaseEnvironmentProperties(Map baseEnvironmentProperties) { this.baseEnv = new Hashtable(baseEnvironmentProperties); } String getJdkVersion() { return JdkVersion.getJavaVersion(); } protected Hashtable getAnonymousEnv() { if (cacheEnvironmentProperties) { return anonymousEnv; } else { return setupAnonymousEnv(); } } protected Hashtable getAuthenticatedEnv(String principal, String credentials) { // The authenticated environment should always be rebuilt. Hashtable env = new Hashtable(getAnonymousEnv()); setupAuthenticatedEnvironment(env, principal, credentials); return env; } /** * Set the authentication source to use when retrieving user principal and * credentials. * * @param authenticationSource the {@link AuthenticationSource} that will * provide user info. */ public void setAuthenticationSource(AuthenticationSource authenticationSource) { this.authenticationSource = authenticationSource; } /** * Get the authentication source. * * @return the {@link AuthenticationSource} that will provide user info. */ public AuthenticationSource getAuthenticationSource() { return authenticationSource; } /** * Set whether environment properties should be cached between requsts for * anonymous environment. Default is true; setting this * property to false causes the environment Hashmap to be * rebuilt from the current property settings of this instance between each * request for an anonymous environment. * * @param cacheEnvironmentProperties true causes that the * anonymous environment properties should be cached, false * causes the Hashmap to be rebuilt for each request. */ public void setCacheEnvironmentProperties(boolean cacheEnvironmentProperties) { this.cacheEnvironmentProperties = cacheEnvironmentProperties; } /** * Set whether an anonymous environment should be used for read-only * operations. Default is false. * * @param anonymousReadOnly true if an anonymous environment * should be used for read-only operations, false otherwise. */ public void setAnonymousReadOnly(boolean anonymousReadOnly) { this.anonymousReadOnly = anonymousReadOnly; } /** * Get whether an anonymous environment should be used for read-only * operations. * * @return true if an anonymous environment should be used for * read-only operations, false otherwise. */ public boolean isAnonymousReadOnly() { return anonymousReadOnly; } /** * Set the {@link DirContextAuthenticationStrategy} to use for preparing the * environment and processing the created DirContext instances. * * @param authenticationStrategy the * {@link DirContextAuthenticationStrategy} to use; default is * {@link SimpleDirContextAuthenticationStrategy}. */ public void setAuthenticationStrategy(DirContextAuthenticationStrategy authenticationStrategy) { this.authenticationStrategy = authenticationStrategy; } /** * Set the method to handle referrals. Default is 'ignore'; setting this * flag to 'follow' will enable referrals to be automatically followed. Note * that this might require particular name server setup in order to work * (the referred URLs will need to be automatically found using standard DNS * resolution). * @param referral the value to set the system property * Context.REFERRAL to, customizing the way that referrals are * handled. */ public void setReferral(String referral) { this.referral = referral; } /** * Implement in subclass to create a DirContext of the desired type (e.g. * InitialDirContext or InitialLdapContext). * * @param environment the environment to use when creating the instance. * @return a new DirContext instance. * @throws NamingException if one is encountered when creating the instance. */ protected abstract DirContext getDirContextInstance(Hashtable environment) throws NamingException; class SimpleAuthenticationSource implements AuthenticationSource { public String getPrincipal() { return userDn; } public String getCredentials() { return password; } } } ././@LongLink0000000000000000000000000000022000000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/LookupAttemptingCallback.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000200411475313376030205 0ustar package org.springframework.ldap.core.support; import javax.naming.NamingException; import javax.naming.directory.DirContext; import org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback; import org.springframework.ldap.core.LdapEntryIdentification; import org.springframework.ldap.support.LdapUtils; /** * Attempts to perform an LDAP operation in the authenticated context, because * Active Directory might allow bind with incorrect password (specifically empty * password), and later refuse operations. We want to fail fast when * authenticating. * * @author Hugo Josefson * @since 1.3.1 */ public class LookupAttemptingCallback implements AuthenticatedLdapEntryContextCallback { public void executeWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) { try { ctx.lookup(ldapEntryIdentification.getRelativeDn()); } catch (NamingException e) { // rethrow, because we aren't allowed to throw checked exceptions. throw LdapUtils.convertLdapException(e); } } } ././@LongLink0000000000000000000000000000023100000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/CountNameClassPairCallbackHandler.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000302511475313376030211 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import javax.naming.NameClassPair; import org.springframework.ldap.core.NameClassPairCallbackHandler; /** * A {@link NameClassPairCallbackHandler} for counting all returned entries. * * @author Mattias Hellborg Arthursson * */ public class CountNameClassPairCallbackHandler implements NameClassPairCallbackHandler { private int noOfRows = 0; /** * Get the number of rows that was returned by the search. * * @return the number of entries that have been handled. */ public int getNoOfRows() { return noOfRows; } /* * (non-Javadoc) * * @see org.springframework.ldap.SearchResultCallbackHandler#handleSearchResult(javax.naming.directory.SearchResult) */ public void handleNameClassPair(NameClassPair nameClassPair) { noOfRows++; } } ././@LongLink0000000000000000000000000000021200000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/support/BaseLdapPathSource.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000276011475313376030216 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.support; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DistinguishedName; /** * Implementations of this interface are capable of providing a base LDAP path. * The base LDAP path is the root path to which all LDAP operations performed on * a particular context are relative. * * @see ContextSource * * @author Mattias Hellborg Arthursson */ public interface BaseLdapPathSource { /** * Get the base LDAP path as a {@link DistinguishedName}. * * @return the base LDAP path as a {@link DistinguishedName}. The path will * be empty if no base path is specified. */ DistinguishedName getBaseLdapPath(); /** * Get the base LDAP path as a String. * * @return the base LDAP path as a An empty String will be returned if no * base path is specified. */ String getBaseLdapPathAsString(); } ././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/ContextExecutor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000335611475313376030220 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.NamingException; import javax.naming.directory.DirContext; /** * Interface for delegating an actual operation to be performed on a * DirContext. For searches, use {@link SearchExecutor} in * stead. A typical usage of this interface could be e.g.: * *

 * ContextExecutor executor = new ContextExecutor() {
 *     public Object executeWithContext(DirContext ctx) throws NamingException {
 *         return ctx.lookup(dn);
 *     }
 * };
 * 
* * @see LdapTemplate#executeReadOnly(ContextExecutor) * @see LdapTemplate#executeReadWrite(ContextExecutor) * * @author Mattias Hellborg Arthursson */ public interface ContextExecutor { /** * Perform any operation on the context. * * @param ctx * the DirContext to perform the operation on. * @return any object resulting from the operation - might be null. * @throws NamingException * if the operation resulted in one. */ Object executeWithContext(DirContext ctx) throws NamingException; } ././@LongLink0000000000000000000000000000022400000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/LdapEntryIdentificationContextMapper.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000227311475313376030215 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; /** * ContextMapper implementation that maps the found entries to the * {@link LdapEntryIdentification} of each respective entry. * * @author Mattias Hellborg Arthursson * @since 1.3 */ public class LdapEntryIdentificationContextMapper implements ContextMapper { public Object mapFromContext(Object ctx) { DirContextOperations adapter = (DirContextOperations) ctx; return new LdapEntryIdentification(new DistinguishedName(adapter.getNameInNamespace()), new DistinguishedName( adapter.getDn())); } } ././@LongLink0000000000000000000000000000017600000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/LdapOperations.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000021325411475313376030220 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import java.util.List; import javax.naming.Binding; import javax.naming.Name; import javax.naming.NameClassPair; import javax.naming.directory.Attributes; import javax.naming.directory.ModificationItem; import javax.naming.directory.SearchControls; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.ldap.ContextNotEmptyException; import org.springframework.ldap.NamingException; import org.springframework.ldap.core.support.AbstractContextSource; import org.springframework.ldap.support.LdapUtils; /** * Interface that specifies a basic set of LDAP operations. Implemented by * LdapTemplate, but it might be a useful option to use this interface in order * to enhance testability. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public interface LdapOperations { /** * Perform a search using a particular {@link SearchExecutor} and context * processor. Use this method only if especially needed - for the most cases * there is an overloaded convenience method which calls this one with * suitable argments. This method handles all the plumbing; getting a * readonly context; looping through the NamingEnumeration and * closing the context and enumeration. The actual search is delegated to * the SearchExecutor and each found NameClassPair is passed to * the CallbackHandler. Any encountered * NamingException will be translated using * {@link LdapUtils#convertLdapException(javax.naming.NamingException)}. * * @param se The SearchExecutor to use for performing the * actual search. * @param handler The NameClassPairCallbackHandler to which * each found entry will be passed. * @param processor DirContextProcessor for custom pre- and * post-processing. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted as no entries being found. */ void search(SearchExecutor se, NameClassPairCallbackHandler handler, DirContextProcessor processor) throws NamingException; /** * Perform a search using a particular {@link SearchExecutor}. Use this * method only if especially needed - for the most cases there is an * overloaded convenience method which calls this one with suitable * argments. This method handles all the plumbing; getting a readonly * context; looping through the NamingEnumeration and closing * the context and enumeration. The actual search is delegated to the * SearchExecutor and each found NameClassPair is * passed to the CallbackHandler. Any encountered * NamingException will be translated using the * {@link LdapUtils#convertLdapException(javax.naming.NamingException)}. * * @param se The SearchExecutor to use for performing the * actual search. * @param handler The NameClassPairCallbackHandler to which * each found entry will be passed. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted as no entries being found. * @see #search(Name, String, AttributesMapper) * @see #search(Name, String, ContextMapper) */ void search(SearchExecutor se, NameClassPairCallbackHandler handler) throws NamingException; /** * Perform an operation (or series of operations) on a read-only context. * This method handles the plumbing - getting a DirContext, * translating any Exceptions and closing the context afterwards. This * method is not intended for searches; use * {@link #search(SearchExecutor, NameClassPairCallbackHandler)} or any of * the overloaded search methods for this. * * @param ce The ContextExecutor to which the actual operation * on the DirContext will be delegated. * @return the result from the ContextExecutor's operation. * @throws NamingException if the operation resulted in a * NamingException. * * @see #search(SearchExecutor, NameClassPairCallbackHandler) * @see #search(Name, String, AttributesMapper) * @see #search(Name, String, ContextMapper) */ Object executeReadOnly(ContextExecutor ce) throws NamingException; /** * Perform an operation (or series of operations) on a read-write context. * This method handles the plumbing - getting a DirContext, * translating any exceptions and closing the context afterwards. This * method is intended only for very particular cases, where there is no * suitable method in this interface to use. * * @param ce The ContextExecutor to which the actual operation * on the DirContext will be delegated. * @return the result from the ContextExecutor's operation. * @throws NamingException if the operation resulted in a * NamingException. * @see #bind(Name, Object, Attributes) * @see #unbind(Name) * @see #rebind(Name, Object, Attributes) * @see #rename(Name, Name) * @see #modifyAttributes(Name, ModificationItem[]) */ Object executeReadWrite(ContextExecutor ce) throws NamingException; /** * Search for all objects matching the supplied filter. Each * SearchResult is supplied to the specified * NameClassPairCallbackHandler. The SearchScope * specified in the supplied SearchControls will be used in the * search. Note that if you are using a ContextMapper, the * returningObjFlag needs to be set to true in the * SearchControls. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param controls The SearchControls to use in the search. * @param handler The NameClassPairCallbackHandler to supply * the SearchResult to. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ void search(Name base, String filter, SearchControls controls, NameClassPairCallbackHandler handler) throws NamingException; /** * Search for all objects matching the supplied filter. See * {@link #search(Name, String, SearchControls, NameClassPairCallbackHandler)} * for details. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param controls The SearchControls to use in the search. * @param handler The NameClassPairCallbackHandler to supply * the SearchResult to. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ void search(String base, String filter, SearchControls controls, NameClassPairCallbackHandler handler) throws NamingException; /** * Search for all objects matching the supplied filter. Each * SearchResult is supplied to the specified * NameClassPairCallbackHandler. The SearchScope * specified in the supplied SearchControls will be used in the * search. Note that if you are using a ContextMapper, the * returningObjFlag needs to be set to true in the * SearchControls. The given DirContextProcessor * will be called before and after the search. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param controls The SearchControls to use in the search. * @param handler The NameClassPairCallbackHandler to supply * the SearchResult to. * @param processor The DirContextProcessor to use before and * after the search. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ void search(Name base, String filter, SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) throws NamingException; /** * Search for all objects matching the supplied filter. The Attributes in * each SearchResult is supplied to the specified * AttributesMapper. The SearchScope specified in * the supplied SearchControls will be used in the search. The * given DirContextProcessor will be called before and after * the search. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param controls The SearchControls to use in the search. * @param mapper The AttributesMapper to use for translating * each entry. * @param processor The DirContextProcessor to use before and * after the search. * @return a List containing all entries received from the * AttributesMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(String base, String filter, SearchControls controls, AttributesMapper mapper, DirContextProcessor processor) throws NamingException; /** * Search for all objects matching the supplied filter. The Attributes in * each SearchResult is supplied to the specified * AttributesMapper. The SearchScope specified in * the supplied SearchControls will be used in the search. The * given DirContextProcessor will be called before and after * the search. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param controls The SearchControls to use in the search. * @param mapper The AttributesMapper to use for translating * each entry. * @param processor The DirContextProcessor to use before and * after the search. * @return a List containing all entries received from the * AttributesMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(Name base, String filter, SearchControls controls, AttributesMapper mapper, DirContextProcessor processor) throws NamingException; /** * Search for all objects matching the supplied filter. The Object returned * in each SearchResult is supplied to the specified * ContextMapper. The SearchScope specified in the * supplied SearchControls will be used in the search. The * given DirContextProcessor will be called before and after * the search. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param controls The SearchControls to use in the search. If * the returnObjFlag is not set in the SearchControls, this * method will set it automatically, as this is required for the * ContextMapper to work. * @param mapper The ContextMapper to use for translating each * entry. * @param processor The DirContextProcessor to use before and * after the search. * @return a List containing all entries received from the * ContextMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(String base, String filter, SearchControls controls, ContextMapper mapper, DirContextProcessor processor) throws NamingException; /** * Search for all objects matching the supplied filter. The Object returned * in each SearchResult is supplied to the specified * ContextMapper. The SearchScope specified in the * supplied SearchControls will be used in the search. The * given DirContextProcessor will be called before and after * the search. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param controls The SearchControls to use in the search. If * the returnObjFlag is not set in the SearchControls, this * method will set it automatically, as this is required for the * ContextMapper to work. * @param mapper The ContextMapper to use for translating each * entry. * @param processor The DirContextProcessor to use before and * after the search. * @return a List containing all entries received from the * ContextMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(Name base, String filter, SearchControls controls, ContextMapper mapper, DirContextProcessor processor) throws NamingException; /** * Search for all objects matching the supplied filter. See * {@link #search(Name, String, SearchControls, NameClassPairCallbackHandler, DirContextProcessor)} * for details. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param controls The SearchControls to use in the search. * @param handler The NameClassPairCallbackHandler to supply * the SearchResults to. * @param processor The DirContextProcessor to use before and * after the search. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ void search(String base, String filter, SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) throws NamingException; /** * Search for all objects matching the supplied filter. Each * SearchResult is supplied to the specified * NameClassPairCallbackHandler. Use the specified values for * search scope and return objects flag. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param searchScope The search scope to set in SearchControls * . * @param returningObjFlag Whether the bound object should be returned in * search results. Must be set to true if a * ContextMapper is used. * @param handler The NameClassPairCallbackHandler to supply * the SearchResults to. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ void search(Name base, String filter, int searchScope, boolean returningObjFlag, NameClassPairCallbackHandler handler) throws NamingException; /** * Search for all objects matching the supplied filter. Each * SearchResult is supplied to the specified * NameClassPairCallbackHandler. Use the specified values for * search scope and return objects flag. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param searchScope The search scope to set in SearchControls * . * @param returningObjFlag Whether the bound object should be returned in * search results. Must be set to true if a * ContextMapper is used. * @param handler The NameClassPairCallbackHandler to supply * the SearchResults to. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ void search(String base, String filter, int searchScope, boolean returningObjFlag, NameClassPairCallbackHandler handler) throws NamingException; /** * Search for all objects matching the supplied filter. Each * SearchResult is supplied to the specified * NameClassPairCallbackHandler. The default Search scope ( * SearchControls.SUBTREE_SCOPE) will be used and the * returnObjects flag will be set to false. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param handler The NameClassPairCallbackHandler to supply * the SearchResults to. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ void search(Name base, String filter, NameClassPairCallbackHandler handler) throws NamingException; /** * Search for all objects matching the supplied filter. Each * SearchResult is supplied to the specified * NameClassPairCallbackHandler. The default Search scope ( * SearchControls.SUBTREE_SCOPE) will be used and the * returnObjects flag will be set to false. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param handler The NameClassPairCallbackHandler to supply * the SearchResults to. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ void search(String base, String filter, NameClassPairCallbackHandler handler) throws NamingException; /** * Search for all objects matching the supplied filter. Only return any * attributes mathing the specified attribute names. The Attributes in each * SearchResult is supplied to the specified * AttributesMapper. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param searchScope The search scope to set in SearchControls * . * @param attrs The attributes to return, null means returning * all attributes. * @param mapper The AttributesMapper to use for translating * each entry. * @return a List containing all entries received from the * AttributesMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(Name base, String filter, int searchScope, String[] attrs, AttributesMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. Only return any * attributes mathing the specified attribute names. The Attributes in each * SearchResult is supplied to the specified * AttributesMapper. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param searchScope The search scope to set in SearchControls * . * @param attrs The attributes to return, null means returning * all attributes. * @param mapper The AttributesMapper to use for translating * each entry. * @return a List containing all entries received from the * AttributesMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(String base, String filter, int searchScope, String[] attrs, AttributesMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. The Attributes in * each SearchResult is supplied to the specified * AttributesMapper. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param searchScope The search scope to set in SearchControls * . * @param mapper The AttributesMapper to use for translating * each entry. * @return a List containing all entries received from the * AttributesMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(Name base, String filter, int searchScope, AttributesMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. The Attributes in * each SearchResult is supplied to the specified * AttributesMapper. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param searchScope The search scope to set in SearchControls * . * @param mapper The AttributesMapper to use for translating * each entry. * @return a List containing all entries received from the * AttributesMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(String base, String filter, int searchScope, AttributesMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. The Attributes in * each SearchResult is supplied to the specified * AttributesMapper. The default search scope will be used. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param mapper The AttributesMapper to use for translating * each entry. * @return a List containing all entries received from the * AttributesMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(Name base, String filter, AttributesMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. The Attributes in * each SearchResult is supplied to the specified * AttributesMapper. The default search scope will be used. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param mapper The AttributesMapper to use for translating * each entry. * @return a List containing all entries received from the * AttributesMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(String base, String filter, AttributesMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. The * Object returned in each SearchResult is * supplied to the specified ContextMapper. Only return the * supplied attributes. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param searchScope The search scope to set in SearchControls * . * @param attrs The attributes to return, null means all * attributes. * @param mapper The ContextMapper to use for translating each * entry. * @return a List containing all entries received from the * ContextMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(Name base, String filter, int searchScope, String[] attrs, ContextMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. The * Object returned in each SearchResult is * supplied to the specified ContextMapper. Only return the * supplied attributes. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param searchScope The search scope to set in SearchControls * . * @param attrs The attributes to return, null means all * attributes. * @param mapper The ContextMapper to use for translating each * entry. * @return a List containing all entries received from the * ContextMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(String base, String filter, int searchScope, String[] attrs, ContextMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. The * Object returned in each SearchResult is * supplied to the specified ContextMapper. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param searchScope The search scope to set in SearchControls * . * @param mapper The ContextMapper to use for translating each * entry. * @return a List containing all entries received from the * ContextMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(Name base, String filter, int searchScope, ContextMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. The * Object returned in each SearchResult is * supplied to the specified ContextMapper. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param searchScope The search scope to set in SearchControls * . * @param mapper The ContextMapper to use for translating each * entry. * @return a List containing all entries received from the * ContextMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(String base, String filter, int searchScope, ContextMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. The * Object returned in each SearchResult is * supplied to the specified ContextMapper. The default search * scope (SearchControls.SUBTREE_SCOPE) will be used. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param mapper The ContextMapper to use for translating each * entry. * @return a List containing all entries received from the * ContextMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(Name base, String filter, ContextMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. The * Object returned in each SearchResult is * supplied to the specified ContextMapper. The default search * scope (SearchControls.SUBTREE_SCOPE) will be used. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param mapper The ContextMapper to use for translating each * entry. * @return a List containing all entries received from the * ContextMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(String base, String filter, ContextMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. The * Object returned in each SearchResult is * supplied to the specified ContextMapper. The default search * scope (SearchControls.SUBTREE_SCOPE) will be used. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param mapper The ContextMapper to use for translating each * entry. * @return a List containing all entries received from the * ContextMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(String base, String filter, SearchControls controls, ContextMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. The Object returned * in each SearchResult is supplied to the specified * ContextMapper. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param controls The SearchControls to use in the search. If * the returnObjFlag is not set in the SearchControls, this * method will set it automatically, as this is required for the * ContextMapper to work. * @param mapper The ContextMapper to use for translating each * entry. * @return a List containing all entries received from the * ContextMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(Name base, String filter, SearchControls controls, ContextMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. The Attributes * returned in each SearchResult is supplied to the specified * AttributesMapper. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param controls The SearchControls to use in the search. * @param mapper The AttributesMapper to use for translating * each entry. * @return a List containing all entries received from the * ContextMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(String base, String filter, SearchControls controls, AttributesMapper mapper) throws NamingException; /** * Search for all objects matching the supplied filter. The Attributes * returned in each SearchResult is supplied to the specified * AttributesMapper. * * @param base The base DN where the search should begin. * @param filter The filter to use in the search. * @param controls The SearchControls to use in the search. * @param mapper The AttributesMapper to use for translating * each entry. * @return a List containing all entries received from the * ContextMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List search(Name base, String filter, SearchControls controls, AttributesMapper mapper) throws NamingException; /** * Perform a non-recursive listing of the children of the given * base. Each resulting NameClassPair is supplied * to the specified NameClassPairCallbackHandler. * * @param base The base DN where the list should be performed. * @param handler The NameClassPairCallbackHandler to supply * each {@link NameClassPair} to. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ void list(String base, NameClassPairCallbackHandler handler) throws NamingException; /** * Perform a non-recursive listing of the children of the given * base. Each resulting NameClassPair is supplied * to the specified NameClassPairCallbackHandler. * * @param base The base DN where the list should be performed. * @param handler The NameClassPairCallbackHandler to supply * each {@link NameClassPair} to. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ void list(Name base, NameClassPairCallbackHandler handler) throws NamingException; /** * Perform a non-recursive listing of the children of the given * base. Pass all the found NameClassPair objects * to the supplied NameClassPairMapper and return all the * returned values as a List. * * @param base The base DN where the list should be performed. * @param mapper The NameClassPairMapper to supply each * {@link NameClassPair} to. * @return a List containing the Objects returned from the * Mapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List list(String base, NameClassPairMapper mapper) throws NamingException; /** * Perform a non-recursive listing of the children of the given * base. Pass all the found NameClassPair objects * to the supplied NameClassPairMapper and return all the * returned values as a List. * * @param base The base DN where the list should be performed. * @param mapper The NameClassPairMapper to supply each * {@link NameClassPair} to. * @return a List containing the Objects returned from the * Mapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List list(Name base, NameClassPairMapper mapper) throws NamingException; /** * Perform a non-recursive listing of the children of the given * base. * * @param base The base DN where the list should be performed. * @return a List containing the names of all the contexts bound to * base. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List list(String base) throws NamingException; /** * Perform a non-recursive listing of the children of the given * base. * * @param base The base DN where the list should be performed. * @return a List containing the names of all the contexts bound to * base. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List list(Name base) throws NamingException; /** * Perform a non-recursive listing of the children of the given * base. Each resulting Binding is supplied to the * specified NameClassPairCallbackHandler. * * @param base The base DN where the list should be performed. * @param handler The NameClassPairCallbackHandler to supply * each {@link Binding} to. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ void listBindings(final String base, NameClassPairCallbackHandler handler) throws NamingException; /** * Perform a non-recursive listing of the children of the given * base. Each resulting Binding is supplied to the * specified NameClassPairCallbackHandler. * * @param base The base DN where the list should be performed. * @param handler The NameClassPairCallbackHandler to supply * each {@link Binding} to. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ void listBindings(final Name base, NameClassPairCallbackHandler handler) throws NamingException; /** * Perform a non-recursive listing of the children of the given * base. Pass all the found Binding objects to the * supplied NameClassPairMapper and return all the returned * values as a List. * * @param base The base DN where the list should be performed. * @param mapper The NameClassPairMapper to supply each * {@link Binding} to. * @return a List containing the Objects returned from the * Mapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List listBindings(String base, NameClassPairMapper mapper) throws NamingException; /** * Perform a non-recursive listing of the children of the given * base. Pass all the found Binding objects to the * supplied NameClassPairMapper and return all the returned * values as a List. * * @param base The base DN where the list should be performed. * @param mapper The NameClassPairMapper to supply each * {@link Binding} to. * @return a List containing the Objects returned from the * Mapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List listBindings(Name base, NameClassPairMapper mapper) throws NamingException; /** * Perform a non-recursive listing of children of the given * base. * * @param base The base DN where the list should be performed. * @return a List containing the names of all the contexts * bound to base. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List listBindings(final String base) throws NamingException; /** * Perform a non-recursive listing of children of the given * base. * * @param base The base DN where the list should be performed. * @return a List containing the names of all the contexts * bound to base. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List listBindings(final Name base) throws NamingException; /** * Perform a non-recursive listing of the children of the given * base. The Object returned in each {@link Binding} is * supplied to the specified ContextMapper. * * @param base The base DN where the list should be performed. * @param mapper The ContextMapper to use for mapping the found * object. * @return a List containing all entries received from the * ContextMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List listBindings(String base, ContextMapper mapper) throws NamingException; /** * Perform a non-recursive listing of the children of the given * base. The Object returned in each {@link Binding} is * supplied to the specified ContextMapper. * * @param base The base DN where the list should be performed. * @param mapper The ContextMapper to use for mapping the found * object. * @return a List containing all entries received from the * ContextMapper. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is * interpreted that no entries were found. */ List listBindings(Name base, ContextMapper mapper) throws NamingException; /** * Lookup the supplied DN and return the found object. This will typically * be a {@link DirContextAdapter}, unless the DirObjectFactory * has been modified in the ContextSource. * * @param dn The distinguished name of the object to find. * @return the found object, typically a {@link DirContextAdapter} instance. * @throws NamingException if any error occurs. * @see #lookupContext(Name) * @see AbstractContextSource#setDirObjectFactory(Class) */ Object lookup(Name dn) throws NamingException; /** * Lookup the supplied DN and return the found object. This will typically * be a {@link DirContextAdapter}, unless the DirObjectFactory * has been modified in the ContextSource. * * @param dn The distinguished name of the object to find. * @return the found object, typically a {@link DirContextAdapter} instance. * @throws NamingException if any error occurs. * @see #lookupContext(String) * @see AbstractContextSource#setDirObjectFactory(Class) */ Object lookup(String dn) throws NamingException; /** * Convenience method to get the attributes of a specified DN and * automatically pass them to an AttributesMapper. * * @param dn The distinguished name to find. * @param mapper The AttributesMapper to use for mapping the * found object. * @return the object returned from the mapper. * @throws NamingException if any error occurs. */ Object lookup(Name dn, AttributesMapper mapper) throws NamingException; /** * Convenience method to get the attributes of a specified DN and * automatically pass them to an AttributesMapper. * * @param dn The distinguished name to find. * @param mapper The AttributesMapper to use for mapping the * found object. * @return the object returned from the mapper. * @throws NamingException if any error occurs. */ Object lookup(String dn, AttributesMapper mapper) throws NamingException; /** * Convenience method to lookup a specified DN and automatically pass the * found object to a ContextMapper. * * @param dn The distinguished name to find. * @param mapper The ContextMapper to use for mapping the found * object. * @return the object returned from the mapper. * @throws NamingException if any error occurs. */ Object lookup(Name dn, ContextMapper mapper) throws NamingException; /** * Convenience method to lookup a specified DN and automatically pass the * found object to a ContextMapper. * * @param dn The distinguished name to find. * @param mapper The ContextMapper to use for mapping the found * object. * @return the object returned from the mapper. * @throws NamingException if any error occurs. */ Object lookup(String dn, ContextMapper mapper) throws NamingException; /** * Convenience method to get the specified attributes of a specified DN and * automatically pass them to an AttributesMapper. * * @param dn The distinguished name to find. * @param attributes The names of the attributes to pass to the mapper. * @param mapper The AttributesMapper to use for mapping the * found object. * @return the object returned from the mapper. * @throws NamingException if any error occurs. */ Object lookup(Name dn, String[] attributes, AttributesMapper mapper) throws NamingException; /** * Convenience method to get the specified attributes of a specified DN and * automatically pass them to an AttributesMapper. * * @param dn The distinguished name to find. * @param attributes The names of the attributes to pass to the mapper. * @param mapper The AttributesMapper to use for mapping the * found object. * @return the object returned from the mapper. * @throws NamingException if any error occurs. */ Object lookup(String dn, String[] attributes, AttributesMapper mapper) throws NamingException; /** * Convenience method to get the specified attributes of a specified DN and * automatically pass them to a ContextMapper. * * @param dn The distinguished name to find. * @param attributes The names of the attributes to pass to the mapper. * @param mapper The ContextMapper to use for mapping the found * object. * @return the object returned from the mapper. * @throws NamingException if any error occurs. */ Object lookup(Name dn, String[] attributes, ContextMapper mapper) throws NamingException; /** * Convenience method to get the specified attributes of a specified DN and * automatically pass them to a ContextMapper. * * @param dn The distinguished name to find. * @param attributes The names of the attributes to pass to the mapper. * @param mapper The ContextMapper to use for mapping the found * object. * @return the object returned from the mapper. * @throws NamingException if any error occurs. */ Object lookup(String dn, String[] attributes, ContextMapper mapper) throws NamingException; /** * Modify an entry in the LDAP tree using the supplied * ModificationItems. * * @param dn The distinguished name of the node to modify. * @param mods The modifications to perform. * @throws NamingException if any error occurs. * @see #modifyAttributes(DirContextOperations) */ void modifyAttributes(Name dn, ModificationItem[] mods) throws NamingException; /** * Modify an entry in the LDAP tree using the supplied * ModificationItems. * * @param dn The distinguished name of the node to modify. * @param mods The modifications to perform. * @throws NamingException if any error occurs. * @see #modifyAttributes(DirContextOperations) */ void modifyAttributes(String dn, ModificationItem[] mods) throws NamingException; /** * Create an entry in the LDAP tree. The attributes used to create the entry * are either retrieved from the obj parameter or the * attributes parameter (or both). One of these parameters may * be null but not both. * * @param dn The distinguished name to bind the object and attributes to. * @param obj The object to bind, may be null. Typically a * DirContext implementation. * @param attributes The attributes to bind, may be null. * @throws NamingException if any error occurs. * @see DirContextAdapter */ void bind(Name dn, Object obj, Attributes attributes) throws NamingException; /** * Create an entry in the LDAP tree. The attributes used to create the entry * are either retrieved from the obj parameter or the * attributes parameter (or both). One of these parameters may * be null but not both. * * @param dn The distinguished name to bind the object and attributes to. * @param obj The object to bind, may be null. Typically a * DirContext implementation. * @param attributes The attributes to bind, may be null. * @throws NamingException if any error occurs. * @see DirContextAdapter */ void bind(String dn, Object obj, Attributes attributes) throws NamingException; /** * Remove an entry from the LDAP tree. The entry must not have any children * - if you suspect that the entry might have descendants, use * {@link #unbind(Name, boolean)} in stead. * * @param dn The distinguished name of the entry to remove. * @throws NamingException if any error occurs. */ void unbind(Name dn) throws NamingException; /** * Remove an entry from the LDAP tree. The entry must not have any children * - if you suspect that the entry might have descendants, use * {@link #unbind(Name, boolean)} in stead. * * @param dn The distinguished name to unbind. * @throws NamingException if any error occurs. */ void unbind(String dn) throws NamingException; /** * Remove an entry from the LDAP tree, optionally removing all descendants * in the process. * * @param dn The distinguished name to unbind. * @param recursive Whether to unbind all subcontexts as well. If this * parameter is false and the entry has children, the operation * will fail. * @throws NamingException if any error occurs. */ void unbind(Name dn, boolean recursive) throws NamingException; /** * Remove an entry from the LDAP tree, optionally removing all descendants * in the process. * * @param dn The distinguished name to unbind. * @param recursive Whether to unbind all subcontexts as well. If this * parameter is false and the entry has children, the operation * will fail. * @throws NamingException if any error occurs. */ void unbind(String dn, boolean recursive) throws NamingException; /** * Remove an entry and replace it with a new one. The attributes used to * create the entry are either retrieved from the obj parameter * or the attributes parameter (or both). One of these * parameters may be null but not both. This method assumes * that the specified context already exists - if not it will fail. * * @param dn The distinguished name to rebind. * @param obj The object to bind to the DN, may be null. * Typically a DirContext implementation. * @param attributes The attributes to bind, may be null. * @throws NamingException if any error occurs. * @see DirContextAdapter */ void rebind(Name dn, Object obj, Attributes attributes) throws NamingException; /** * Remove an entry and replace it with a new one. The attributes used to * create the entry are either retrieved from the obj parameter * or the attributes parameter (or both). One of these * parameters may be null but not both. This method assumes * that the specified context already exists - if not it will fail. * * @param dn The distinguished name to rebind. * @param obj The object to bind to the DN, may be null. * Typically a DirContext implementation. * @param attributes The attributes to bind, may be null. * @throws NamingException if any error occurs. * @see DirContextAdapter */ void rebind(String dn, Object obj, Attributes attributes) throws NamingException; /** * Move an entry in the LDAP tree to a new location. * * @param oldDn The distinguished name of the entry to move; may not be * null or empty. * @param newDn The distinguished name where the entry should be moved; may * not be null or empty. * @throws ContextNotEmptyException if newDn is already bound * @throws NamingException if any other error occurs. */ void rename(final Name oldDn, final Name newDn) throws NamingException; /** * Move an entry in the LDAP tree to a new location. * * @param oldDn The distinguished name of the entry to move; may not be * null or empty. * @param newDn The distinguished name where the entry should be moved; may * not be null or empty. * @throws ContextNotEmptyException if newDn is already bound * @throws NamingException if any other error occurs. */ void rename(final String oldDn, final String newDn) throws NamingException; /** * Convenience method to lookup the supplied DN and automatically cast it to * {@link DirContextOperations}. * * @param dn The distinguished name of the object to find. * @return The found object, cast to {@link DirContextOperations}. * @throws ClassCastException if an alternative * DirObjectFactory has been registered with the * ContextSource, causing the actual class of the returned * object to be something else than {@link DirContextOperations}. * @throws NamingException if any other error occurs. * @see #lookup(Name) * @see #modifyAttributes(DirContextOperations) * @since 1.2 */ DirContextOperations lookupContext(Name dn) throws NamingException, ClassCastException; /** * Convenience method to lookup the supplied DN and automatically cast it to * {@link DirContextOperations}. * * @param dn The distinguished name of the object to find. * @return The found object, cast to {@link DirContextOperations}. * @throws ClassCastException if an alternative * DirObjectFactory has been registered with the * ContextSource, causing the actual class of the returned * object to be something else than {@link DirContextOperations}. * @throws NamingException if any other error occurs. * @see #lookup(String) * @see #modifyAttributes(DirContextOperations) * @since 1.2 */ DirContextOperations lookupContext(String dn) throws NamingException, ClassCastException; /** * Modify the attributes of the entry referenced by the supplied * {@link DirContextOperations} instance. The DN to update will be the DN of * the DirContextOperationsinstance, and the * ModificationItem array is retrieved from the * DirContextOperations instance using a call to * {@link AttributeModificationsAware#getModificationItems()}. NB: * The supplied instance needs to have been properly initialized; this means * that if it hasn't been received from a lookup operation, its * DN needs to be initialized and it must have been put in update mode ( * {@link DirContextAdapter#setUpdateMode(boolean)}). *

* Typical use of this method would be as follows: * *

	 * public void update(Person person) {
	 * 	DirContextOperations ctx = ldapOperations.lookupContext(person.getDn());
	 * 
	 * 	ctx.setAttributeValue("description", person.getDescription());
	 * 	ctx.setAttributeValue("telephoneNumber", person.getPhone());
	 * 	// More modifications here
	 * 
	 * 	ldapOperations.modifyAttributes(ctx);
	 * }
	 * 
* * @param ctx the DirContextOperations instance to use in the update. * @throws IllegalStateException if the supplied instance is not in update * mode or has not been properly initialized. * @throws NamingException if any other error occurs. * @since 1.2 * @see #lookupContext(Name) * @see DirContextAdapter */ void modifyAttributes(DirContextOperations ctx) throws IllegalStateException, NamingException; /** * Bind the data in the supplied context in the tree. All specified * attributes ctxin will be bound to the DN set on ctx. *

* Example:
* *

	 * DirContextOperations ctx = new DirContextAdapter(dn);
	 * ctx.setAttributeValue("cn", "john doe");
	 * ctx.setAttributeValue("description", "some description");
	 * //More initialization here.
	 * 
	 * ldapTemplate.bind(ctx);
	 * 
* @param ctx the context to bind * @throws IllegalStateException if no DN is set or if the instance is in * update mode. * @since 1.3 */ void bind(DirContextOperations ctx); /** * Remove an entry and replace it with a new one. The attributes used to * create the entry are retrieved from the ctx parameter. This * method assumes that the specified context already exists - if not it will * fail. The entry will be bound to the DN set on ctx. *

* Example:
* *

	 * DirContextOperations ctx = new DirContextAdapter(dn);
	 * ctx.setAttributeValue("cn", "john doe");
	 * ctx.setAttributeValue("description", "some description");
	 * //More initialization here.
	 * 
	 * ldapTemplate.rebind(ctx);
	 * 
* @param ctx the context to rebind * @throws IllegalStateException if no DN is set or if the instance is in * update mode. * @since 1.3 */ void rebind(DirContextOperations ctx); /** * Utility method to perform a simple LDAP 'bind' authentication. Search for * the LDAP entry to authenticate using the supplied base DN and filter; use * the DN of the found entry together with the password as input to * {@link ContextSource#getContext(String, String)}, thus authenticating the * entry. *

* Example:
* *

	 * AndFilter filter = new AndFilter();
	 * filter.and("objectclass", "person").and("uid", userId);
	 * boolean authenticated = ldapTemplate.authenticate(DistinguishedName.EMPTY_PATH, filter.toString(), password);
	 * 
* * @param base the DN to use as the base of the search. * @param filter the search filter - must result in a unique result. * @param password the password to use for authentication. * @return true if the authentication was successful, * false otherwise. * @since 1.3 */ boolean authenticate(Name base, String filter, String password); /** * Utility method to perform a simple LDAP 'bind' authentication. Search for * the LDAP entry to authenticate using the supplied base DN and filter; use * the DN of the found entry together with the password as input to * {@link ContextSource#getContext(String, String)}, thus authenticating the * entry. *

* Example:
* *

	 * AndFilter filter = new AndFilter();
	 * filter.and("objectclass", "person").and("uid", userId);
	 * boolean authenticated = ldapTemplate.authenticate(DistinguishedName.EMPTY_PATH, filter.toString(), password);
	 * 
* * @param base the DN to use as the base of the search. * @param filter the search filter - must result in a unique result. * @param password the password to use for authentication. * @return true if the authentication was successful, * false otherwise. * @since 1.3 */ boolean authenticate(String base, String filter, String password); /** * Utility method to perform a simple LDAP 'bind' authentication. Search for * the LDAP entry to authenticate using the supplied base DN and filter; use * the DN of the found entry together with the password as input to * {@link ContextSource#getContext(String, String)}, thus authenticating the * entry. The resulting DirContext instance is then used as input to the * supplied {@link AuthenticatedLdapEntryContextCallback} to perform any * additional LDAP operations against the authenticated DirContext. * * @param base the DN to use as the base of the search. * @param filter the search filter - must result in a unique result. * @param password the password to use for authentication. * @param callback the callback to that will be called to perform operations * on the DirContext authenticated with the found user. * @return true if the authentication was successful, * false otherwise. * @see #authenticate(Name, String, String) * @since 1.3 */ boolean authenticate(Name base, String filter, String password, AuthenticatedLdapEntryContextCallback callback); /** * Utility method to perform a simple LDAP 'bind' authentication. Search for * the LDAP entry to authenticate using the supplied base DN and filter; use * the DN of the found entry together with the password as input to * {@link ContextSource#getContext(String, String)}, thus authenticating the * entry. The resulting DirContext instance is then used as input to the * supplied {@link AuthenticatedLdapEntryContextCallback} to perform any * additional LDAP operations against the authenticated DirContext. * * @param base the DN to use as the base of the search. * @param filter the search filter - must result in a unique result. * @param password the password to use for authentication. * @param callback the callback to that will be called to perform operations * on the DirContext authenticated with the found user. * @return true if the authentication was successful, * false otherwise. * @see #authenticate(String, String, String) * @since 1.3 */ boolean authenticate(String base, String filter, String password, AuthenticatedLdapEntryContextCallback callback); /** * Utility method to perform a simple LDAP 'bind' authentication. Search for * the LDAP entry to authenticate using the supplied base DN and filter; use * the DN of the found entry together with the password as input to * {@link ContextSource#getContext(String, String)}, thus authenticating the * entry. The resulting DirContext instance is then used as input to the * supplied {@link AuthenticatedLdapEntryContextCallback} to perform any * additional LDAP operations against the authenticated DirContext. If an * exception is caught, the same exception is passed on to the given * {@link AuthenticationErrorCallback}. This enables the caller to provide a * callback that, for example, collects the exception for later processing. * * @param base the DN to use as the base of the search. * @param filter the search filter - must result in a unique result. * @param password the password to use for authentication. * @param callback the callback that will be called to perform operations * on the DirContext authenticated with the found user. * @param errorCallback the callback that will be called if an exception is caught. * @return true if the authentication was successful, * false otherwise. * @see #authenticate(Name, String, String, AuthenticatedLdapEntryContextCallback) * @since 1.3.1 */ boolean authenticate(Name base, String filter, String password, AuthenticatedLdapEntryContextCallback callback, AuthenticationErrorCallback errorCallback); /** * Utility method to perform a simple LDAP 'bind' authentication. Search for * the LDAP entry to authenticate using the supplied base DN and filter; use * the DN of the found entry together with the password as input to * {@link ContextSource#getContext(String, String)}, thus authenticating the * entry. The resulting DirContext instance is then used as input to the * supplied {@link AuthenticatedLdapEntryContextCallback} to perform any * additional LDAP operations against the authenticated DirContext. If an * exception is caught, the same exception is passed on to the given * {@link AuthenticationErrorCallback}. This enables the caller to provide a * callback that, for example, collects the exception for later processing. * * @param base the DN to use as the base of the search. * @param filter the search filter - must result in a unique result. * @param password the password to use for authentication. * @param callback the callback that will be called to perform operations * on the DirContext authenticated with the found user. * @param errorCallback the callback that will be called if an exception is caught. * @return true if the authentication was successful, * false otherwise. * @see #authenticate(String, String, String, AuthenticatedLdapEntryContextCallback) * @since 1.3.1 */ boolean authenticate(String base, String filter, String password, AuthenticatedLdapEntryContextCallback callback, AuthenticationErrorCallback errorCallback); /** * Utility method to perform a simple LDAP 'bind' authentication. Search for * the LDAP entry to authenticate using the supplied base DN and filter; use * the DN of the found entry together with the password as input to * {@link ContextSource#getContext(String, String)}, thus authenticating the * entry. If an exception is caught, the same exception is passed on to the given * {@link AuthenticationErrorCallback}. This enables the caller to provide a * callback that, for example, collects the exception for later processing. * * @param base the DN to use as the base of the search. * @param filter the search filter - must result in a unique result. * @param password the password to use for authentication. * @param errorCallback the callback that will be called if an exception is caught. * @return true if the authentication was successful, * false otherwise. * @see #authenticate(Name, String, String, AuthenticatedLdapEntryContextCallback, AuthenticationErrorCallback) * @since 1.3.1 */ boolean authenticate(Name base, String filter, String password, AuthenticationErrorCallback errorCallback); /** * Utility method to perform a simple LDAP 'bind' authentication. Search for * the LDAP entry to authenticate using the supplied base DN and filter; use * the DN of the found entry together with the password as input to * {@link ContextSource#getContext(String, String)}, thus authenticating the * entry. If an exception is caught, the same exception is passed on to the given * {@link AuthenticationErrorCallback}. This enables the caller to provide a * callback that, for example, collects the exception for later processing. * * @param base the DN to use as the base of the search. * @param filter the search filter - must result in a unique result. * @param password the password to use for authentication. * @param errorCallback the callback that will be called if an exception is caught. * @return true if the authentication was successful, * false otherwise. * @throws IncorrectResultSizeDataAccessException if more than one users were found * @see #authenticate(String, String, String, AuthenticatedLdapEntryContextCallback, AuthenticationErrorCallback) * @since 1.3.1 */ boolean authenticate(String base, String filter, String password, AuthenticationErrorCallback errorCallback); /** * Perform a search for a unique entry matching the specified search * criteria and return the found object. If no entry is found or if there * are more than one matching entry, an * {@link IncorrectResultSizeDataAccessException} is thrown. * @param base the DN to use as the base of the search. * @param filter the search filter. * @param mapper the mapper to use for the search. * @return the single object returned by the mapper that matches the search * criteria. * @throws IncorrectResultSizeDataAccessException if the result is not one unique entry * @since 1.3 */ Object searchForObject(Name base, String filter, ContextMapper mapper); /** * Perform a search for a unique entry matching the specified search * criteria and return the found object. If no entry is found or if there * are more than one matching entry, an * {@link IncorrectResultSizeDataAccessException} is thrown. * @param base the DN to use as the base of the search. * @param filter the search filter. * @param mapper the mapper to use for the search. * @return the single object returned by the mapper that matches the search * criteria. * @throws IncorrectResultSizeDataAccessException if the result is not one unique entry * @since 1.3 */ Object searchForObject(String base, String filter, ContextMapper mapper); } ././@LongLink0000000000000000000000000000017500000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/ContextMapper.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000524711475313376030221 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.Binding; import javax.naming.Name; import javax.naming.directory.SearchResult; import org.springframework.ldap.core.support.AbstractContextMapper; import org.springframework.ldap.core.support.DefaultDirObjectFactory; /** * An interface used by LdapTemplate to map LDAP Contexts to beans. When a * DirObjectFactory is set on the ContextSource, the objects returned from * search and listBindings operations are * automatically transformed to DirContext objects (when using the * {@link DefaultDirObjectFactory} - which is typically the case, unless * something else has been explicitly specified - you get a * {@link DirContextAdapter} object). This object will then be passed to the * ContextMapper implementation for transformation to the desired bean. *

* ContextMapper implementations are typically stateless and thus reusable; they * are ideal for implementing mapping logic in one place. *

* Alternatively, consider using an {@link AttributesMapper} in stead. * * @see LdapTemplate#search(Name, String, ContextMapper) * @see LdapTemplate#listBindings(Name, ContextMapper) * @see LdapTemplate#lookup(Name, ContextMapper) * @see AttributesMapper * @see DefaultDirObjectFactory * @see DirContextAdapter * @see AbstractContextMapper * * @author Mattias Hellborg Arthursson */ public interface ContextMapper { /** * Map a single LDAP Context to an object. The supplied Object * ctx is the object from a single {@link SearchResult}, * {@link Binding}, or a lookup operation. * * @param ctx * the context to map to an object. Typically this will be a * {@link DirContextAdapter} instance, unless a project specific * DirObjectFactory has been specified on the * ContextSource. * @return an object built from the data in the context. */ Object mapFromContext(Object ctx); } ././@LongLink0000000000000000000000000000016700000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000021611475313376030210 0ustar Core package of the JNDI/LDAP support. Provides a LdapTemplate class and various callback interfaces. ././@LongLink0000000000000000000000000000020700000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/DistinguishedNameEditor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000314711475313376030216 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import java.beans.PropertyEditorSupport; /** * Property editor for use with {@link DistinguishedName} instances. The * {@link #setAsText(String)} method sets the value as an immutable * instance of a DistinguishedName. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class DistinguishedNameEditor extends PropertyEditorSupport { /* * (non-Javadoc) * @see java.beans.PropertyEditorSupport#setAsText(java.lang.String) */ public void setAsText(String text) throws IllegalArgumentException { if (text == null) { setValue(null); } else { setValue(new DistinguishedName(text).immutableDistinguishedName()); } } /* * (non-Javadoc) * @see java.beans.PropertyEditorSupport#getAsText() */ public String getAsText() { Object theValue = getValue(); if (theValue == null) { return null; } else { return ((DistinguishedName) theValue).toString(); } } } ././@LongLink0000000000000000000000000000017000000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/DnParser.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000230611475313376030212 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; /** * A parser for RFC2253-compliant Distinguished Names. * * @author Mattias Hellborg Arthursson * */ public interface DnParser { /** * Parse a full Distinguished Name. * * @return the DistinguishedName corresponding to the parsed * stream. */ public DistinguishedName dn() throws ParseException; /** * Parse a Relative Distinguished Name. * * @return the next rdn on the stream. */ public LdapRdn rdn() throws ParseException; } ././@LongLink0000000000000000000000000000022600000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/CollectingNameClassPairCallbackHandler.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000371111475313376030213 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import java.util.LinkedList; import java.util.List; import javax.naming.NameClassPair; /** * A NameClassPairCallbackHandler to collect all results in an internal List. * * @see LdapTemplate * * @author Mattias Hellborg Arthursson */ public abstract class CollectingNameClassPairCallbackHandler implements NameClassPairCallbackHandler { private List list = new LinkedList(); /** * Get the assembled list. * * @return the list of all assembled objects. */ public List getList() { return list; } /** * Pass on the supplied NameClassPair to * {@link #getObjectFromNameClassPair(NameClassPair)} and add the result to * the internal list. */ public void handleNameClassPair(NameClassPair nameClassPair) { list.add(getObjectFromNameClassPair(nameClassPair)); } /** * Handle a NameClassPair and transform it to an Object of the desired type * and with data from the NameClassPair. * * @param nameClassPair * a NameClassPair from a search operation. * @return an object constructed from the data in the NameClassPair. */ public abstract Object getObjectFromNameClassPair( NameClassPair nameClassPair); } ././@LongLink0000000000000000000000000000021000000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/ObjectRetrievalException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000274411475313376030220 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import org.springframework.ldap.NamingException; /** * Thrown by a {@link ContextMapperCallbackHandler} when it cannot retrieve an * object from the given Binding. * * @author Ulrik Sandberg * @since 1.2 */ public class ObjectRetrievalException extends NamingException { /** * Create a new ObjectRetrievalException. * * @param msg * the detail message * */ public ObjectRetrievalException(String msg) { super(msg); } /** * Create a new ObjectRetrievalException. * * @param msg * the detail message * @param cause * the root cause (if any) */ public ObjectRetrievalException(String msg, Throwable cause) { super(msg, cause); } } ././@LongLink0000000000000000000000000000021700000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/AttributesMapperCallbackHandler.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000432711475313376030217 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.NameClassPair; import javax.naming.directory.Attributes; import javax.naming.directory.SearchResult; import org.springframework.ldap.support.LdapUtils; /** * A CollectingNameClassPairCallbackHandler to wrap an {@link AttributesMapper}. * That is, the found object is extracted from the {@link Attributes} of each * {@link SearchResult}, and then passed to the specified * {@link AttributesMapper} for translation. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg * @since 1.2 */ public class AttributesMapperCallbackHandler extends CollectingNameClassPairCallbackHandler { private AttributesMapper mapper; /** * Constructs a new instance around the specified {@link AttributesMapper}. * * @param mapper the target mapper. */ public AttributesMapperCallbackHandler(AttributesMapper mapper) { this.mapper = mapper; } /** * Cast the NameClassPair to a SearchResult and pass its attributes to the * {@link AttributesMapper}. * * @param nameClassPair a SearchResult instance. * @return the Object returned from the mapper. */ public Object getObjectFromNameClassPair(NameClassPair nameClassPair) { if (!(nameClassPair instanceof SearchResult)) { throw new IllegalArgumentException("Parameter must be an instance of SearchResult"); } SearchResult searchResult = (SearchResult) nameClassPair; Attributes attributes = searchResult.getAttributes(); try { return mapper.mapFromAttributes(attributes); } catch (javax.naming.NamingException e) { throw LdapUtils.convertLdapException(e); } } }././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/DirContextProxy.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000220211475313376030205 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.directory.DirContext; /** * Helper interface to be able to get hold of the target DirContext * from proxies created by ContextSource proxies. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public interface DirContextProxy { /** * Get the target DirContext of the proxy. * * @return the target DirContext. */ DirContext getTargetContext(); } ././@LongLink0000000000000000000000000000016700000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/LdapRdn.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001722011475313376030213 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.springframework.ldap.BadLdapGrammarException; import org.springframework.ldap.support.ListComparator; /** * Datatype for a LDAP name, a part of a path. * * The name: uid=adam.skogman Key: uid Value: adam.skogman * * @author Adam Skogman * @author Mattias Hellborg Arthursson */ public class LdapRdn implements Serializable, Comparable { private static final long serialVersionUID = 5681397547245228750L; private List components = new LinkedList(); /** * Default constructor. Create an empty, uninitialized LdapRdn. */ public LdapRdn() { } /** * Parse the supplied string and construct this instance accordingly. * * @param string the string to parse. */ public LdapRdn(String string) { DnParser parser = DefaultDnParserFactory.createDnParser(string); LdapRdn rdn; try { rdn = parser.rdn(); } catch (ParseException e) { throw new BadLdapGrammarException("Failed to parse Rdn", e); } catch (TokenMgrError e) { throw new BadLdapGrammarException("Failed to parse Rdn", e); } this.components = rdn.components; } /** * Construct an LdapRdn using the supplied key and value. * * @param key the attribute name. * @param value the attribute value. */ public LdapRdn(String key, String value) { components.add(new LdapRdnComponent(key, value)); } /** * Add an LdapRdnComponent to this LdapRdn. * * @param rdnComponent the LdapRdnComponent to add.s */ public void addComponent(LdapRdnComponent rdnComponent) { components.add(rdnComponent); } /** * Gets all components in this LdapRdn. * * @return the List of all LdapRdnComponents composing this LdapRdn. */ public List getComponents() { return components; } /** * Gets the first LdapRdnComponent of this LdapRdn. * * @return The first LdapRdnComponent of this LdapRdn. * @throws IndexOutOfBoundsException if there are no components in this Rdn. */ public LdapRdnComponent getComponent() { return (LdapRdnComponent) components.get(0); } /** * Get the LdapRdnComponent at index idx. * * @param idx the 0-based index of the component to get. * @return the LdapRdnComponent at index idx. * @throws IndexOutOfBoundsException if there are no components in this Rdn. */ public LdapRdnComponent getComponent(int idx) { return (LdapRdnComponent) components.get(idx); } /** * Get a properly rfc2253-encoded String representation of this LdapRdn. * * @return an escaped String corresponding to this LdapRdn. * @throws IndexOutOfBoundsException if there are no components in this Rdn. */ public String getLdapEncoded() { if (components.size() == 0) { throw new IndexOutOfBoundsException("No components in Rdn."); } StringBuffer sb = new StringBuffer(100); for (Iterator iter = components.iterator(); iter.hasNext();) { LdapRdnComponent component = (LdapRdnComponent) iter.next(); sb.append(component.encodeLdap()); if (iter.hasNext()) { sb.append("+"); } } return sb.toString(); } /** * Get a String representation of this LdapRdn for use in urls. * * @return a String representation of this LdapRdn for use in urls. */ public String encodeUrl() { StringBuffer sb = new StringBuffer(100); for (Iterator iter = components.iterator(); iter.hasNext();) { LdapRdnComponent component = (LdapRdnComponent) iter.next(); sb.append(component.encodeUrl()); if (iter.hasNext()) { sb.append("+"); } } return sb.toString(); } /** * Compare this LdapRdn to another object. * * @param obj the object to compare to. * @throws ClassCastException if the supplied object is not an LdapRdn * instance. */ public int compareTo(Object obj) { LdapRdn that = (LdapRdn) obj; Comparator comparator = new ListComparator(); return comparator.compare(this.components, that.components); } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { if (obj == null || obj.getClass() != this.getClass()) { return false; } LdapRdn that = (LdapRdn) obj; return this.getComponents().equals(that.getComponents()); } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ public int hashCode() { return this.getClass().hashCode() ^ getComponents().hashCode(); } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ public String toString() { return getLdapEncoded(); } /** * Get the value of this LdapRdn. Note that if this Rdn is multi-value the * first value will be returned. E.g. for the Rdn * cn=john doe+sn=doe, the return value would be * john doe. * * @return the (first) value of this LdapRdn. * @throws IndexOutOfBoundsException if there are no components in this Rdn. */ public String getValue() { return getComponent().getValue(); } /** * Get the key of this LdapRdn. Note that if this Rdn is multi-value the * first key will be returned. E.g. for the Rdn * cn=john doe+sn=doe, the return value would be * cn. * * @return the (first) key of this LdapRdn. * @throws IndexOutOfBoundsException if there are no components in this Rdn. */ public String getKey() { return getComponent().getKey(); } /** * Get the value of the LdapComponent with the specified key (Attribute * name). * * @param key the key * @return the value. * @throws IllegalArgumentException if there is no component with the * specified key. */ public String getValue(String key) { for (Iterator iter = components.iterator(); iter.hasNext();) { LdapRdnComponent component = (LdapRdnComponent) iter.next(); if (StringUtils.equals(component.getKey(), key)) { return component.getValue(); } } throw new IllegalArgumentException("No RdnComponent with the key " + key); } /** * Create an immutable copy of this instance. It will not be possible to add * or remove components or modify the keys and values of these components. * * @return an immutable copy of this instance. * @since 1.3 */ public LdapRdn immutableLdapRdn() { List listWithImmutableRdns = new ArrayList(components.size()); for (Iterator iterator = components.iterator(); iterator.hasNext();) { LdapRdnComponent rdnComponent = (LdapRdnComponent) iterator.next(); listWithImmutableRdns.add(rdnComponent.immutableLdapRdnComponent()); } List unmodifiableListOfImmutableRdns = Collections.unmodifiableList(listWithImmutableRdns); LdapRdn immutableRdn = new LdapRdn(); immutableRdn.components = unmodifiableListOfImmutableRdns; return immutableRdn; } }././@LongLink0000000000000000000000000000017300000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/LdapEncoder.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001643011475313376030215 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import org.springframework.ldap.BadLdapGrammarException; /** * Helper class to encode and decode ldap names and values. * * @author Adam Skogman * @author Mattias Hellborg Arthursson */ public class LdapEncoder { private static String[] nameEscapeTable = new String[96]; private static String[] filterEscapeTable = new String['\\' + 1]; static { // Name encoding table ------------------------------------- // all below 0x20 (control chars) for (char c = 0; c < ' '; c++) { nameEscapeTable[c] = "\\" + toTwoCharHex(c); } nameEscapeTable['#'] = "\\#"; nameEscapeTable[','] = "\\,"; nameEscapeTable[';'] = "\\;"; nameEscapeTable['='] = "\\="; nameEscapeTable['+'] = "\\+"; nameEscapeTable['<'] = "\\<"; nameEscapeTable['>'] = "\\>"; nameEscapeTable['\"'] = "\\\""; nameEscapeTable['\\'] = "\\\\"; // Filter encoding table ------------------------------------- // fill with char itself for (char c = 0; c < filterEscapeTable.length; c++) { filterEscapeTable[c] = String.valueOf(c); } // escapes (RFC2254) filterEscapeTable['*'] = "\\2a"; filterEscapeTable['('] = "\\28"; filterEscapeTable[')'] = "\\29"; filterEscapeTable['\\'] = "\\5c"; filterEscapeTable[0] = "\\00"; } /** * All static methods - not to be instantiated. */ private LdapEncoder() { } protected static String toTwoCharHex(char c) { String raw = Integer.toHexString(c).toUpperCase(); if (raw.length() > 1) return raw; else return "0" + raw; } /** * Escape a value for use in a filter. * * @param value * the value to escape. * @return a properly escaped representation of the supplied value. */ public static String filterEncode(String value) { if (value == null) return null; // make buffer roomy StringBuffer encodedValue = new StringBuffer(value.length() * 2); int length = value.length(); for (int i = 0; i < length; i++) { char c = value.charAt(i); if (c < filterEscapeTable.length) { encodedValue.append(filterEscapeTable[c]); } else { // default: add the char encodedValue.append(c); } } return encodedValue.toString(); } /** * LDAP Encodes a value for use with a DN. Escapes for LDAP, not JNDI! * *
Escapes:
' ' [space] - "\ " [if first or last]
'#' * [hash] - "\#"
',' [comma] - "\,"
';' [semicolon] - "\;"
'= * [equals] - "\="
'+' [plus] - "\+"
'<' [less than] - * "\<"
'>' [greater than] - "\>"
'"' [double quote] - * "\""
'\' [backslash] - "\\"
* * @param value * the value to escape. * @return The escaped value. */ static public String nameEncode(String value) { if (value == null) return null; // make buffer roomy StringBuffer encodedValue = new StringBuffer(value.length() * 2); int length = value.length(); int last = length - 1; for (int i = 0; i < length; i++) { char c = value.charAt(i); // space first or last if (c == ' ' && (i == 0 || i == last)) { encodedValue.append("\\ "); continue; } if (c < nameEscapeTable.length) { // check in table for escapes String esc = nameEscapeTable[c]; if (esc != null) { encodedValue.append(esc); continue; } } // default: add the char encodedValue.append(c); } return encodedValue.toString(); } /** * Decodes a value. Converts escaped chars to ordinary chars. * * @param value * Trimmed value, so no leading an trailing blanks, except an * escaped space last. * @return The decoded value as a string. * @throws BadLdapGrammarException */ static public String nameDecode(String value) throws BadLdapGrammarException { if (value == null) return null; // make buffer same size StringBuffer decoded = new StringBuffer(value.length()); int i = 0; while (i < value.length()) { char currentChar = value.charAt(i); if (currentChar == '\\') { if (value.length() <= i + 1) { // Ending with a single backslash is not allowed throw new BadLdapGrammarException( "Unexpected end of value " + "unterminated '\\'"); } else { char nextChar = value.charAt(i + 1); if (nextChar == ',' || nextChar == '=' || nextChar == '+' || nextChar == '<' || nextChar == '>' || nextChar == '#' || nextChar == ';' || nextChar == '\\' || nextChar == '\"' || nextChar == ' ') { // Normal backslash escape decoded.append(nextChar); i += 2; } else { if (value.length() <= i + 2) { throw new BadLdapGrammarException( "Unexpected end of value " + "expected special or hex, found '" + nextChar + "'"); } else { // This should be a hex value String hexString = "" + nextChar + value.charAt(i + 2); decoded.append((char) Integer.parseInt(hexString, 16)); i += 3; } } } } else { // This character wasn't escaped - just append it decoded.append(currentChar); i++; } } return decoded.toString(); } } ././@LongLink0000000000000000000000000000020300000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/NameClassPairMapper.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000324711475313376030217 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.NameClassPair; import javax.naming.NamingException; /** * Responsible for mapping NameClassPair objects to beans. * * @author Mattias Hellborg Arthursson */ public interface NameClassPairMapper { /** * Map NameClassPair to an Object. The supplied * NameClassPair is one of the results from a search * operation (search, list or listBindings). Depending on which search * operation is being performed, the NameClassPair might be a * SearchResult, Binding or * NameClassPair. * * @param nameClassPair * NameClassPair from a search operation. * @return and Object built from the NameClassPair. * @throws NamingException * if one is encountered in the operation. */ Object mapFromNameClassPair(NameClassPair nameClassPair) throws NamingException; } ././@LongLink0000000000000000000000000000017600000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/SearchExecutor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000340511475313376030213 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.DirContext; /** * Interface for delegating an actual search operation. The typical * implementation of executeSearch would be something like: * *

 * SearchExecutor executor = new SearchExecutor(){
 *   public NamingEnumeration executeSearch(DirContext ctx) throws NamingException{
 *     return ctx.search(dn, filter, searchControls);
 *   }
 * }
 * 
* * @see org.springframework.ldap.core.LdapTemplate#search(SearchExecutor, * NameClassPairCallbackHandler) * * @author Mattias Hellborg Arthursson */ public interface SearchExecutor { /** * Execute the actual search. * * @param ctx * the DirContext on which to work. * @return the NamingEnumeration resulting from the search * operation. * @throws NamingException * if the search results in one. */ NamingEnumeration executeSearch(DirContext ctx) throws NamingException; } ././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/DirContextAdapter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000011203111475313376030207 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import java.util.ArrayList; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; import javax.naming.Context; import javax.naming.Name; import javax.naming.NameNotFoundException; import javax.naming.NameParser; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttributes; import javax.naming.directory.DirContext; import javax.naming.directory.ModificationItem; import javax.naming.directory.SearchControls; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.NoSuchAttributeException; import org.springframework.ldap.support.LdapUtils; import org.springframework.util.StringUtils; /** * Adapter that implements the interesting methods of the DirContext interface. * In particular it contains utility methods for getting and setting attributes. * Using the * {@link org.springframework.ldap.core.support.DefaultDirObjectFactory} in your * ContextSource (which is the default) you will receive instances * of this class from searches and lookups. This can be particularly useful when * updating data, since this class implements * {@link AttributeModificationsAware}, providing a * {@link #getModificationItems()} method. When in update mode, an object of * this class keeps track of the changes made to its attributes, making them * available as an array of ModificationItem objects, suitable as * input to {@link LdapTemplate#modifyAttributes(DirContextOperations)}. * * Note that this is not a complete implementation of DirContext. Several * methods are not relevant for the intended usage of this class, so they * throw UnsupportOperationException. * * @see #setAttributeValue(String, Object) * @see #setAttributeValues(String, Object[]) * @see #getStringAttribute(String) * @see #getStringAttributes(String) * @see #getObjectAttribute(String) * @see #addAttributeValue(String, Object) * @see #removeAttributeValue(String, Object) * @see #setUpdateMode(boolean) * @see #isUpdateMode() * * @author Magnus Robertsson * @author Andreas Ronge * @author Adam Skogman * @author Mattias Hellborg Arthursson */ public class DirContextAdapter implements DirContextOperations { private static final boolean DONT_ADD_IF_DUPLICATE_EXISTS = false; private static final String EMPTY_STRING = ""; private static final boolean ORDER_DOESNT_MATTER = false; private static Log log = LogFactory.getLog(DirContextAdapter.class); private final Attributes originalAttrs; private DistinguishedName dn; private DistinguishedName base; private boolean updateMode = false; private Attributes updatedAttrs; private String referralUrl; /** * Default constructor. */ public DirContextAdapter() { this(null, null, null); } /** * Create a new DirContextAdapter from the supplied DN String. * @param dnString the DN string. Must be syntactically correct, or an * exception will be thrown. */ public DirContextAdapter(String dnString) { this(new DistinguishedName(dnString)); } /** * Create a new adapter from the supplied dn. * * @param dn the dn. */ public DirContextAdapter(Name dn) { this(null, dn); } /** * Create a new adapter from the supplied attributes and dn. * * @param attrs the attributes. * @param dn the dn. */ public DirContextAdapter(Attributes attrs, Name dn) { this(attrs, dn, null); } /** * Create a new adapter from the supplied attributes, dn, and base. * * @param attrs the attributes. * @param dn the dn. * @param base the base name. */ public DirContextAdapter(Attributes attrs, Name dn, Name base) { this(attrs, dn, base, null); } /** * Create a new adapter from the supplied attributes, dn, base, and referral * url. * @param attrs the attributes. * @param dn the dn. * @param base the base. * @param referralUrl the referral url (if this instance results from a * referral). */ public DirContextAdapter(Attributes attrs, Name dn, Name base, String referralUrl) { if (attrs != null) { this.originalAttrs = attrs; } else { this.originalAttrs = new BasicAttributes(true); } if (dn != null) { this.dn = new DistinguishedName(dn); } else { this.dn = new DistinguishedName(); } if (base != null) { this.base = new DistinguishedName(base); } else { this.base = new DistinguishedName(); } if (referralUrl != null) { this.referralUrl = referralUrl; } else { this.referralUrl = EMPTY_STRING; } } /** * Constructor for cloning an existing adapter. * * @param master The adapter to be copied. */ protected DirContextAdapter(DirContextAdapter master) { this.originalAttrs = (Attributes) master.originalAttrs.clone(); this.dn = master.dn; this.updatedAttrs = (Attributes) master.updatedAttrs.clone(); this.updateMode = master.updateMode; } /** * Sets the update mode. The update mode should be false for a * new entry and true for an existing entry that is being * updated. * * @param mode Update mode. */ public void setUpdateMode(boolean mode) { this.updateMode = mode; if (updateMode) { updatedAttrs = new BasicAttributes(true); } } /* * @see org.springframework.ldap.support.DirContextOperations#isUpdateMode() */ public boolean isUpdateMode() { return updateMode; } /* * @seeorg.springframework.ldap.support.DirContextOperations# * getNamesOfModifiedAttributes() */ public String[] getNamesOfModifiedAttributes() { List tmpList = new ArrayList(); NamingEnumeration attributesEnumeration; if (isUpdateMode()) { attributesEnumeration = updatedAttrs.getAll(); } else { attributesEnumeration = originalAttrs.getAll(); } try { while (attributesEnumeration.hasMore()) { Attribute oneAttribute = (Attribute) attributesEnumeration .next(); tmpList.add(oneAttribute.getID()); } } catch (NamingException e) { throw LdapUtils.convertLdapException(e); } finally { closeNamingEnumeration(attributesEnumeration); } return (String[]) tmpList.toArray(new String[0]); } private void closeNamingEnumeration(NamingEnumeration enumeration) { try { if (enumeration != null) { enumeration.close(); } } catch (NamingException e) { // Never mind this } } /* * @seeorg.springframework.ldap.support.AttributeModificationsAware# * getModificationItems() */ public ModificationItem[] getModificationItems() { if (!updateMode) { return new ModificationItem[0]; } List tmpList = new LinkedList(); NamingEnumeration attributesEnumeration = null; try { attributesEnumeration = updatedAttrs.getAll(); // find attributes that have been changed, removed or added while (attributesEnumeration.hasMore()) { Attribute oneAttr = (Attribute) attributesEnumeration.next(); collectModifications(oneAttr, tmpList); } } catch (NamingException e) { throw LdapUtils.convertLdapException(e); } finally { closeNamingEnumeration(attributesEnumeration); } if (log.isDebugEnabled()) { log.debug("Number of modifications:" + tmpList.size()); } return (ModificationItem[]) tmpList .toArray(new ModificationItem[tmpList.size()]); } /** * Collect all modifications for the changed attribute. If no changes have * been made, return immediately. If modifications have been made, and the * original size as well as the updated size of the attribute is 1, replace * the attribute. If the size of the updated attribute is 0, remove the * attribute. Otherwise, the attribute is a multi-value attribute; if it's * an ordered one it should be replaced in its entirety to preserve the new * ordering, if not all modifications to the original value (removals and * additions) will be collected individually. * * @param changedAttr the value of the changed attribute. * @param modificationList the list in which to add the modifications. * @throws NamingException if thrown by called Attribute methods. */ private void collectModifications(Attribute changedAttr, List modificationList) throws NamingException { Attribute currentAttribute = originalAttrs.get(changedAttr.getID()); if (changedAttr.equals(currentAttribute)) { // No changes return; } else if (currentAttribute != null && currentAttribute.size() == 1 && changedAttr.size() == 1) { // Replace single-vale attribute. modificationList.add(new ModificationItem( DirContext.REPLACE_ATTRIBUTE, changedAttr)); } else if (changedAttr.size() == 0 && currentAttribute != null) { // Attribute has been removed. modificationList.add(new ModificationItem( DirContext.REMOVE_ATTRIBUTE, changedAttr)); } else if ((currentAttribute == null || currentAttribute.size() == 0) && changedAttr.size() > 0) { // Attribute has been added. modificationList.add(new ModificationItem(DirContext.ADD_ATTRIBUTE, changedAttr)); } else if (changedAttr.size() > 0 && changedAttr.isOrdered()) { // This is a multivalue attribute and it is ordered - the original // value should be replaced with the new values so that the ordering // is preserved. modificationList.add(new ModificationItem( DirContext.REPLACE_ATTRIBUTE, changedAttr)); } else if (changedAttr.size() > 0) { // Change of multivalue Attribute. Collect additions and removals // individually. List myModifications = new LinkedList(); collectModifications(currentAttribute, changedAttr, myModifications); if (myModifications.isEmpty()) { // This means that the attributes are not equal, but the // actual values are the same - thus the order must have // changed. This should result in a REPLACE_ATTRIBUTE operation. myModifications.add(new ModificationItem( DirContext.REPLACE_ATTRIBUTE, changedAttr)); } modificationList.addAll(myModifications); } } private void collectModifications(Attribute originalAttr, Attribute changedAttr, List modificationList) throws NamingException { Attribute originalClone = (Attribute) originalAttr.clone(); Attribute addedValuesAttribute = new BasicAttribute(originalAttr .getID()); for (int i = 0; i < changedAttr.size(); i++) { Object attributeValue = changedAttr.get(i); if (!originalClone.remove(attributeValue)) { addedValuesAttribute.add(attributeValue); } } // We have now traversed and removed all values from the original that // were also present in the new values. The remaining values in the // original must be the ones that were removed. if (originalClone.size() > 0) { modificationList.add(new ModificationItem( DirContext.REMOVE_ATTRIBUTE, originalClone)); } if (addedValuesAttribute.size() > 0) { modificationList.add(new ModificationItem(DirContext.ADD_ATTRIBUTE, addedValuesAttribute)); } } /** * returns true if the attribute is empty. It is empty if a == null, size == * 0 or get() == null or an exception if thrown when accessing the get * method */ private boolean isEmptyAttribute(Attribute a) { try { return (a == null || a.size() == 0 || a.get() == null); } catch (NamingException e) { return true; } } /** * Compare the existing attribute name with the values on the * array values. The order of the array must be the same order * as the existing multivalued attribute. *

* Also handles the case where the values have been reset to the original * values after a previous change. For example, changing * [a,b,c] to [a,b] and then back to * [a,b,c] again must result in this method returning * true so the first change can be overwritten with the latest * change. * * @param name Name of the original multi-valued attribute. * @param values Array of values to check if they have been changed. * @return true if there has been a change compared to original attribute, * or a previous update */ private boolean isChanged(String name, Object[] values, boolean orderMatters) { Attribute orig = originalAttrs.get(name); Attribute prev = updatedAttrs.get(name); // values == null and values.length == 0 is treated the same way boolean emptyNewValue = (values == null || values.length == 0); // Setting to empty --------------------- if (emptyNewValue) { // FALSE: if both are null, it is not changed (both don't exist) // TRUE: if new value is null and old value exists (should be // removed) // TODO Also include prev in null check // TODO Also check if there is a single null element if (orig != null) { return true; } return false; } // NOT setting to empty ------------------- // TRUE if existing value is null if (orig == null) { return true; } // TRUE if different length compared to original attributes if (orig.size() != values.length) { return true; } // TRUE if different length compared to previously updated attributes if (prev != null && prev.size() != values.length) { return true; } // Check contents of arrays // Order DOES matter, e.g. first names try { for (int i = 0; i < orig.size(); i++) { Object obj = orig.get(i); // TRUE if one value is not equal if (!(obj instanceof String)) { return true; } if (orderMatters) { // check only the string with same index if (!values[i].equals(obj)) { return true; } } else { // check all strings if (!ArrayUtils.contains(values, obj)) { return true; } } } } catch (NamingException e) { // TRUE if we can't access the value return true; } if (prev != null) { // Also check against updatedAttrs, since there might have been // a previous update try { for (int i = 0; i < prev.size(); i++) { Object obj = prev.get(i); // TRUE if one value is not equal if (!(obj instanceof String)) { return true; } if (orderMatters) { // check only the string with same index if (!values[i].equals(obj)) { return true; } } else { // check all strings if (!ArrayUtils.contains(values, obj)) { return true; } } } } catch (NamingException e) { // TRUE if we can't access the value return true; } } // FALSE since we have compared all values return false; } /** * Checks if an entry has a specific attribute. * * This method simply calls exists(String) with the attribute name. * * @param attr the attribute to check. * @return true if attribute exists in entry. */ protected final boolean exists(Attribute attr) { return exists(attr.getID()); } /** * Checks if the attribute exists in this entry, either it was read or it * has been added and update() has been called. * * @param attrId id of the attribute to check. * @return true if the attribute exists in the entry. */ protected final boolean exists(String attrId) { return originalAttrs.get(attrId) != null; } /* * @see * org.springframework.ldap.support.DirContextOperations#getStringAttribute * (java.lang.String) */ public String getStringAttribute(String name) { return (String) getObjectAttribute(name); } /* * @see org.springframework.ldap.support.DirContextOperations#getObjectAttribute * (java.lang.String) */ public Object getObjectAttribute(String name) { Attribute oneAttr = originalAttrs.get(name); if (oneAttr == null || oneAttr.size() == 0) { // LDAP-215 return null; } try { return oneAttr.get(); } catch (NamingException e) { throw LdapUtils.convertLdapException(e); } } // LDAP-215 /* (non-Javadoc) * @see org.springframework.ldap.core.DirContextOperations#attributeExists(java.lang.String) */ public boolean attributeExists(String name) { Attribute oneAttr = originalAttrs.get(name); if (oneAttr == null) { return false; } else { return true; } } /* * @see * org.springframework.ldap.support.DirContextOperations#setAttributeValue * (java.lang.String, java.lang.Object) */ public void setAttributeValue(String name, Object value) { // new entry if (!updateMode && value != null) { originalAttrs.put(name, value); } // updating entry if (updateMode) { BasicAttribute attribute = new BasicAttribute(name); if (value != null) { attribute.add(value); } updatedAttrs.put(attribute); } } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.DirContextOperations#addAttributeValue( * java.lang.String, java.lang.Object) */ public void addAttributeValue(String name, Object value) { addAttributeValue(name, value, DONT_ADD_IF_DUPLICATE_EXISTS); } public void addAttributeValue(String name, Object value, boolean addIfDuplicateExists) { if (!updateMode && value != null) { Attribute attr = originalAttrs.get(name); if (attr == null) { originalAttrs.put(name, value); } else { attr.add(value); } } else if (updateMode) { Attribute attr = updatedAttrs.get(name); if (attr == null) { if (originalAttrs.get(name) == null) { // No match in the original attributes - // add a new Attribute to updatedAttrs updatedAttrs.put(name, value); } else { // The attribute exists in the original attributes - clone // that and add the new entry to it attr = (Attribute) originalAttrs.get(name).clone(); if (addIfDuplicateExists || !attr.contains(value)) { attr.add(value); } updatedAttrs.put(attr); } } else { attr.add(value); } } } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.DirContextOperations#removeAttributeValue * (java.lang.String, java.lang.Object) */ public void removeAttributeValue(String name, Object value) { if (!updateMode && value != null) { Attribute attr = originalAttrs.get(name); if (attr != null) { attr.remove(value); if (attr.size() == 0) { originalAttrs.remove(name); } } } else if (updateMode) { Attribute attr = updatedAttrs.get(name); if (attr == null) { if (originalAttrs.get(name) != null) { attr = (Attribute) originalAttrs.get(name).clone(); attr.remove(value); updatedAttrs.put(attr); } } else { attr.remove(value); } } } /* * @see * org.springframework.ldap.support.DirContextOperations#setAttributeValues * (java.lang.String, java.lang.Object[]) */ public void setAttributeValues(String name, Object[] values) { setAttributeValues(name, values, ORDER_DOESNT_MATTER); } /* * @see * org.springframework.ldap.support.DirContextOperations#setAttributeValues * (java.lang.String, java.lang.Object[], boolean) */ public void setAttributeValues(String name, Object[] values, boolean orderMatters) { Attribute a = new BasicAttribute(name, orderMatters); for (int i = 0; values != null && i < values.length; i++) { a.add(values[i]); } // only change the original attribute if not in update mode if (!updateMode && values != null && values.length > 0) { // don't save empty arrays originalAttrs.put(a); } // possible to set an already existing attribute to an empty array if (updateMode && isChanged(name, values, orderMatters)) { updatedAttrs.put(a); } } /* * @see org.springframework.ldap.support.DirContextOperations#update() */ public void update() { NamingEnumeration attributesEnumeration = null; try { attributesEnumeration = updatedAttrs.getAll(); // find what to update while (attributesEnumeration.hasMore()) { Attribute a = (Attribute) attributesEnumeration.next(); // if it does not exist it should be added if (isEmptyAttribute(a)) { originalAttrs.remove(a.getID()); } else { // Otherwise it should be set. originalAttrs.put(a); } } } catch (NamingException e) { throw LdapUtils.convertLdapException(e); } finally { closeNamingEnumeration(attributesEnumeration); } // Reset the attributes to be updated updatedAttrs = new BasicAttributes(true); } /* * @see * org.springframework.ldap.core.DirContextOperations#getStringAttributes * (java.lang.String) */ public String[] getStringAttributes(String name) { try { return (String[]) collectAttributeValuesAsList(name).toArray( new String[0]); } catch (NoSuchAttributeException e) { // The attribute does not exist - contract says to return null. return null; } } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.DirContextOperations#getObjectAttributes * (java.lang.String) */ public Object[] getObjectAttributes(String name) { try { return collectAttributeValuesAsList(name).toArray(new Object[0]); } catch (NoSuchAttributeException e) { // The attribute does not exist - contract says to return null. return null; } } private List collectAttributeValuesAsList(String name) { List list = new LinkedList(); LdapUtils.collectAttributeValues(originalAttrs, name, list); return list; } /* * @seeorg.springframework.ldap.support.DirContextOperations# * getAttributeSortedStringSet(java.lang.String) */ public SortedSet getAttributeSortedStringSet(String name) { try { TreeSet attrSet = new TreeSet(); LdapUtils.collectAttributeValues(originalAttrs, name, attrSet); return attrSet; } catch (NoSuchAttributeException e) { // The attribute does not exist - contract says to return null. return null; } } /** * Set the supplied attribute. * * @param attribute the attribute to set. */ public void setAttribute(Attribute attribute) { if (!updateMode) { originalAttrs.put(attribute); } else { updatedAttrs.put(attribute); } } /** * Get all attributes. * * @return all attributes. */ public Attributes getAttributes() { return originalAttrs; } /** * @see javax.naming.directory.DirContext#getAttributes(Name) */ public Attributes getAttributes(Name name) throws NamingException { return getAttributes(name.toString()); } /** * @see javax.naming.directory.DirContext#getAttributes(String) */ public Attributes getAttributes(String name) throws NamingException { if (StringUtils.hasLength(name)) { throw new NameNotFoundException(); } return (Attributes) originalAttrs.clone(); } /** * @see javax.naming.directory.DirContext#getAttributes(Name, String[]) */ public Attributes getAttributes(Name name, String[] attrIds) throws NamingException { return getAttributes(name.toString(), attrIds); } /** * @see javax.naming.directory.DirContext#getAttributes(String, String[]) */ public Attributes getAttributes(String name, String[] attrIds) throws NamingException { if (StringUtils.hasLength(name)) { throw new NameNotFoundException(); } Attributes a = new BasicAttributes(true); Attribute target; for (int i = 0; i < attrIds.length; i++) { target = originalAttrs.get(attrIds[i]); if (target != null) { a.put(target); } } return a; } /** * @see javax.naming.directory.DirContext#modifyAttributes(javax.naming.Name, * int, javax.naming.directory.Attributes) */ public void modifyAttributes(Name name, int modOp, Attributes attrs) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#modifyAttributes(String, int, * Attributes) */ public void modifyAttributes(String name, int modOp, Attributes attrs) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#modifyAttributes(Name, * ModificationItem[]) */ public void modifyAttributes(Name name, ModificationItem[] mods) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#modifyAttributes(String, * ModificationItem[]) */ public void modifyAttributes(String name, ModificationItem[] mods) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#bind(Name, Object, Attributes) */ public void bind(Name name, Object obj, Attributes attrs) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#bind(String, Object, Attributes) */ public void bind(String name, Object obj, Attributes attrs) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#rebind(Name, Object, Attributes) */ public void rebind(Name name, Object obj, Attributes attrs) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#rebind(String, Object, Attributes) */ public void rebind(String name, Object obj, Attributes attrs) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#createSubcontext(Name, Attributes) */ public DirContext createSubcontext(Name name, Attributes attrs) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#createSubcontext(String, * Attributes) */ public DirContext createSubcontext(String name, Attributes attrs) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#getSchema(Name) */ public DirContext getSchema(Name name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#getSchema(String) */ public DirContext getSchema(String name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#getSchemaClassDefinition(Name) */ public DirContext getSchemaClassDefinition(Name name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#getSchemaClassDefinition(String) */ public DirContext getSchemaClassDefinition(String name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#search(Name, Attributes, String[]) */ public NamingEnumeration search(Name name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#search(String, Attributes, * String[]) */ public NamingEnumeration search(String name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#search(Name, Attributes) */ public NamingEnumeration search(Name name, Attributes matchingAttributes) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#search(String, Attributes) */ public NamingEnumeration search(String name, Attributes matchingAttributes) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#search(Name, String, * SearchControls) */ public NamingEnumeration search(Name name, String filter, SearchControls cons) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#search(String, String, * SearchControls) */ public NamingEnumeration search(String name, String filter, SearchControls cons) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#search(Name, String, Object[], * SearchControls) */ public NamingEnumeration search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.directory.DirContext#search(String, String, Object[], * SearchControls) */ public NamingEnumeration search(String name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#lookup(Name) */ public Object lookup(Name name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#lookup(String) */ public Object lookup(String name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#bind(Name, Object) */ public void bind(Name name, Object obj) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#bind(String, Object) */ public void bind(String name, Object obj) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#rebind(Name, Object) */ public void rebind(Name name, Object obj) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#rebind(String, Object) */ public void rebind(String name, Object obj) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#unbind(Name) */ public void unbind(Name name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#unbind(String) */ public void unbind(String name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#rename(Name, Name) */ public void rename(Name oldName, Name newName) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#rename(String, String) */ public void rename(String oldName, String newName) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#list(Name) */ public NamingEnumeration list(Name name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#list(String) */ public NamingEnumeration list(String name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#listBindings(Name) */ public NamingEnumeration listBindings(Name name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#listBindings(String) */ public NamingEnumeration listBindings(String name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#destroySubcontext(Name) */ public void destroySubcontext(Name name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#destroySubcontext(String) */ public void destroySubcontext(String name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#createSubcontext(Name) */ public Context createSubcontext(Name name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#createSubcontext(String) */ public Context createSubcontext(String name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#lookupLink(Name) */ public Object lookupLink(Name name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#lookupLink(String) */ public Object lookupLink(String name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#getNameParser(Name) */ public NameParser getNameParser(Name name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#getNameParser(String) */ public NameParser getNameParser(String name) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#composeName(Name, Name) */ public Name composeName(Name name, Name prefix) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#composeName(String, String) */ public String composeName(String name, String prefix) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#addToEnvironment(String, Object) */ public Object addToEnvironment(String propName, Object propVal) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#removeFromEnvironment(String) */ public Object removeFromEnvironment(String propName) throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#getEnvironment() */ public Hashtable getEnvironment() throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#close() */ public void close() throws NamingException { throw new UnsupportedOperationException("Not implemented."); } /** * @see javax.naming.Context#getNameInNamespace() */ public String getNameInNamespace() { DistinguishedName result = new DistinguishedName(dn); result.prepend(base); return result.toString(); } /* * (non-Javadoc) * * @see org.springframework.ldap.support.DirContextOperations#getDn() */ public Name getDn() { return new DistinguishedName(dn); } /* * (non-Javadoc) * * @see * org.springframework.ldap.support.DirContextOperations#setDn(javax.naming * .Name) */ public final void setDn(Name dn) { if (!updateMode) { this.dn = new DistinguishedName(dn.toString()); } else { throw new IllegalStateException( "Not possible to call setDn() on a DirContextAdapter in update mode"); } } /** * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { // A subclass with identical values should NOT be considered equal. // EqualsBuilder in commons-lang cannot handle subclasses correctly. if (obj == null || obj.getClass() != this.getClass()) { return false; } return EqualsBuilder.reflectionEquals(this, obj); } /** * @see Object#hashCode() */ public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } /** * @see java.lang.Object#toString() */ public String toString() { StringBuffer buf = new StringBuffer(); buf.append(getClass().getName()); buf.append(":"); if (dn != null) { buf.append(" dn=" + dn); } buf.append(" {"); try { for (NamingEnumeration i = originalAttrs.getAll(); i.hasMore();) { Attribute attribute = (Attribute) i.next(); if (attribute.size() == 1) { buf.append(attribute.getID()); buf.append('='); buf.append(attribute.get()); } else { for (int j = 0; j < attribute.size(); j++) { if (j > 0) { buf.append(", "); } buf.append(attribute.getID()); buf.append('['); buf.append(j); buf.append("]="); buf.append(attribute.get(j)); } } if (i.hasMore()) { buf.append(", "); } } } catch (NamingException e) { log.warn("Error in toString()"); } buf.append('}'); return buf.toString(); } /* * (non-Javadoc) * * @see org.springframework.ldap.core.DirContextOperations#getReferralUrl() */ public String getReferralUrl() { return referralUrl; } /* * (non-Javadoc) * * @see org.springframework.ldap.core.DirContextOperations#isReferral() */ public boolean isReferral() { return StringUtils.hasLength(referralUrl); } } ././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/LdapRdnComponent.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001631311475313376030215 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import java.io.Serializable; import java.net.URI; import java.net.URISyntaxException; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Represents part of an LdapRdn. As specified in RFC2253 an LdapRdn may be * composed of several attributes, separated by "+". An * LdapRdnComponent represents one of these attributes. * * @author Mattias Hellborg Arthursson * */ public class LdapRdnComponent implements Comparable, Serializable { private static final long serialVersionUID = -3296747972616243038L; private static final Log log = LogFactory.getLog(LdapRdnComponent.class); public static final boolean DONT_DECODE_VALUE = false; private String key; private String value; /** * Constructs an LdapRdnComponent without decoding the value. * * @param key the Attribute name. * @param value the Attribute value. */ public LdapRdnComponent(String key, String value) { this(key, value, DONT_DECODE_VALUE); } /** * Constructs an LdapRdnComponent, optionally decoding the value. *

* Depending on the value of the "key case fold" System property, the keys * will be lowercased, uppercased, or preserve their original case. Default * is to convert them to lowercase. * * @param key the Attribute name. * @param value the Attribute value. * @param decodeValue if true the value is decoded (typically * used when a DN is parsed from a String), otherwise the value is used as * specified. * @see DistinguishedName#KEY_CASE_FOLD_PROPERTY */ public LdapRdnComponent(String key, String value, boolean decodeValue) { Validate.notEmpty(key, "Key must not be empty"); Validate.notEmpty(value, "Value must not be empty"); String caseFold = System.getProperty(DistinguishedName.KEY_CASE_FOLD_PROPERTY); if (StringUtils.isBlank(caseFold) || caseFold.equals(DistinguishedName.KEY_CASE_FOLD_LOWER)) { this.key = StringUtils.lowerCase(key); } else if (caseFold.equals(DistinguishedName.KEY_CASE_FOLD_UPPER)) { this.key = StringUtils.upperCase(key); } else if (caseFold.equals(DistinguishedName.KEY_CASE_FOLD_NONE)) { this.key = key; } else { log .warn("\"" + caseFold + "\" invalid property value for " + DistinguishedName.KEY_CASE_FOLD_PROPERTY + "; expected \"" + DistinguishedName.KEY_CASE_FOLD_LOWER + "\", \"" + DistinguishedName.KEY_CASE_FOLD_UPPER + "\", or \"" + DistinguishedName.KEY_CASE_FOLD_NONE + "\""); this.key = StringUtils.lowerCase(key); } if (decodeValue) { this.value = LdapEncoder.nameDecode(value); } else { this.value = value; } } /** * Get the key (Attribute name) of this component. * * @return the key. */ public String getKey() { return key; } /** * Set the key (Attribute name) of this component. * * @param key the key. * @deprecated Using this method changes the internal state of surrounding * DistinguishedName instance. This should be avoided. */ public void setKey(String key) { this.key = key; } /** * Get the (Attribute) value of this component. * * @return the value. */ public String getValue() { return value; } /** * Set the (Attribute) value of this component. * * @param value the value. * @deprecated Using this method changes the internal state of surrounding * DistinguishedName instance. This should be avoided. */ public void setValue(String value) { this.value = value; } /** * Encode key and value to ldap. * * @return Properly ldap escaped rdn. */ protected String encodeLdap() { StringBuffer buff = new StringBuffer(key.length() + value.length() * 2); buff.append(key); buff.append('='); buff.append(LdapEncoder.nameEncode(value)); return buff.toString(); } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ public String toString() { return getLdapEncoded(); } /** * @return The LdapRdn as a string where the value is LDAP-encoded. */ public String getLdapEncoded() { return encodeLdap(); } /** * Get a String representation of this instance for use in URLs. * * @return a properly URL encoded representation of this instancs. */ public String encodeUrl() { // Use the URI class to properly URL encode the value. try { URI valueUri = new URI(null, null, value, null); return key + "=" + valueUri.toString(); } catch (URISyntaxException e) { // This should really never happen... return key + "=" + "value"; } } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ public int hashCode() { return key.toUpperCase().hashCode() ^ value.toUpperCase().hashCode(); } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { // Slightly more lenient equals comparison here to enable immutable // instances to equal mutable ones. if (obj != null && obj instanceof LdapRdnComponent) { LdapRdnComponent that = (LdapRdnComponent) obj; return StringUtils.equalsIgnoreCase(this.key, that.key) && StringUtils.equalsIgnoreCase(this.value, that.value); } else { return false; } } /** * Compare this instance to the supplied object. * * @param obj the object to compare to. * @throws ClassCastException if the object is not possible to cast to an * LdapRdnComponent. */ public int compareTo(Object obj) { LdapRdnComponent that = (LdapRdnComponent) obj; return this.toString().compareTo(that.toString()); } /** * Create an immutable copy of this instance. It will not be possible to * modify the key or the value of the returned instance. * * @return an immutable copy of this instance. * @since 1.3 */ public LdapRdnComponent immutableLdapRdnComponent() { return new ImmutableLdapRdnComponent(key, value); } private static class ImmutableLdapRdnComponent extends LdapRdnComponent { private static final long serialVersionUID = -7099970046426346567L; public ImmutableLdapRdnComponent(String key, String value) { super(key, value); } public void setKey(String key) { throw new UnsupportedOperationException("SetValue not supported for this immutable LdapRdnComponent"); } public void setValue(String value) { throw new UnsupportedOperationException("SetKey not supported for this immutable LdapRdnComponent"); } } } ././@LongLink0000000000000000000000000000020600000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/DefaultDnParserFactory.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000252011475313376030210 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import java.io.StringReader; import org.springframework.ldap.core.DnParserImpl; /** * A factory for creating DnParser instances. The actual implementation of * DnParser is generated using javacc and should not be constructed directly. * * @author Mattias Hellborg Arthursson * */ public class DefaultDnParserFactory { /** * Create a new DnParser instance. * * @param string * the DN String to be parsed. * @return a new DnParser instance for parsing the supplied DN string. */ public static DnParser createDnParser(String string) { return new DnParserImpl(new StringReader(string)); } } ././@LongLink0000000000000000000000000000017500000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/ContextSource.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000453011475313376030213 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.directory.DirContext; import org.springframework.ldap.NamingException; /** * A ContextSource is responsible for configuring and creating * DirContext instances. It is typically used from * {@link LdapTemplate} to acquiring contexts for LDAP operations, but may be * used standalone to perform LDAP authentication. * * @see org.springframework.ldap.core.LdapTemplate * * @author Adam Skogman * @author Mattias Hellborg Arthursson */ public interface ContextSource { /** * Gets a read-only DirContext. The returned * DirContext must be possible to perform read-only operations * on. * * @return A DirContext instance, never null. * @throws NamingException if some error occurs creating an DirContext. */ DirContext getReadOnlyContext() throws NamingException; /** * Gets a read-write DirContext instance. * * @return A DirContext instance, never null. * @throws NamingException if some error occurs creating an * DirContext. */ DirContext getReadWriteContext() throws NamingException; /** * Gets a DirContext instance authenticated using the supplied * principal and credentials. * * @param principal The principal (typically a distinguished name of a user * in the LDAP tree) to use for authentication. * @param credentials The credentials to use for authentication. * @return an authenticated DirContext instance, never * null. * @since 1.3 */ DirContext getContext(String principal, String credentials) throws NamingException; }././@LongLink0000000000000000000000000000020400000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/AuthenticationSource.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000240411475313376030211 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; /** * An AuthenticationSource is responsible for providing the * principal (user DN) and credentials to be used when creating a new context. * * @author Mattias Hellborg Arthursson * */ public interface AuthenticationSource { /** * Get the principal to use when creating an authenticated context. * * @return the principal (userDn). */ String getPrincipal(); /** * Get the credentials to use when creating an authenticated context. * * @return the credentials (password). */ String getCredentials(); } ././@LongLink0000000000000000000000000000021300000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/AuthenticationErrorCallback.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000120211475313376030204 0ustar package org.springframework.ldap.core; /** * Callback interface to be used in the authentication methods in * {@link LdapOperations} for performing operations when there * are authentication errors. Can be useful when the cause of the * authentication failure needs to be retrieved. * * @author Ulrik Sandberg * @since 1.3.1 */ public interface AuthenticationErrorCallback { /** * This method will be called with the authentication exception in * case there is a problem with the authentication. * * @param e the exception that was caught in the authentication method */ void execute(Exception e); } ././@LongLink0000000000000000000000000000021200000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/DefaultNameClassPairMapper.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000270411475313376030214 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.NameClassPair; import javax.naming.NamingException; /** * The default NameClassPairMapper implementation. This implementation simply * takes the Name string from the supplied NameClassPair and returns it as * result. * * @author Mattias Hellborg Arthursson * */ public class DefaultNameClassPairMapper implements NameClassPairMapper { /** * Gets the Name from the supplied NameClassPair and returns it as the * result. * * @param nameClassPair * the NameClassPair to transform. * @return the Name string from the NameClassPair. */ public Object mapFromNameClassPair(NameClassPair nameClassPair) throws NamingException { return nameClassPair.getName(); } } ././@LongLink0000000000000000000000000000017400000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/LdapTemplate.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000014510011475313376030212 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import java.util.List; import javax.naming.Binding; import javax.naming.Name; import javax.naming.NameClassPair; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.PartialResultException; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.ModificationItem; import javax.naming.directory.SearchControls; import org.apache.commons.lang.Validate; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.ldap.NamingException; import org.springframework.ldap.support.LdapUtils; /** * Executes core LDAP functionality and helps to avoid common errors, relieving * the user of the burden of looking up contexts, looping through * NamingEnumerations and closing contexts. *

* Note for Active Directory (AD) users: AD servers are apparently unable * to handle referrals automatically, which causes a * PartialResultException to be thrown whenever a referral is * encountered in a search. To avoid this, set the * ignorePartialResultException property to true. * There is currently no way of manually handling these referrals in the form of * ReferralException, i.e. either you get the exception (and your * results are lost) or all referrals are ignored (if the server is unable to * handle them properly. Neither is there any simple way to get notified that a * PartialResultException has been ignored (other than in the log). * * @see org.springframework.ldap.core.ContextSource * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class LdapTemplate implements LdapOperations, InitializingBean { private static final Log log = LogFactory.getLog(LdapTemplate.class); private static final int DEFAULT_SEARCH_SCOPE = SearchControls.SUBTREE_SCOPE; private static final boolean DONT_RETURN_OBJ_FLAG = false; private static final boolean RETURN_OBJ_FLAG = true; private static final String[] ALL_ATTRIBUTES = null; private ContextSource contextSource; private boolean ignorePartialResultException = false; private boolean ignoreNameNotFoundException = false; /** * Constructor for bean usage. */ public LdapTemplate() { } /** * Constructor to setup instance directly. * * @param contextSource the ContextSource to use. */ public LdapTemplate(ContextSource contextSource) { this.contextSource = contextSource; } /** * Set the ContextSource. Call this method when the default constructor has * been used. * * @param contextSource the ContextSource. */ public void setContextSource(ContextSource contextSource) { this.contextSource = contextSource; } /** * Get the ContextSource. * * @return the ContextSource. */ public ContextSource getContextSource() { return contextSource; } /** * Specify whether NameNotFoundException should be ignored in * searches. In previous version, NameNotFoundException caused * by the search base not being found was silently ignored. The default * behavior is now to treat this as an error (as it should), and to convert * and re-throw the exception. The ability to revert to the previous * behavior still exists. The only difference is that the incident is in * that case no longer silently ignored, but logged as a warning. * * @param ignore true if NameNotFoundException * should be ignored in searches, false otherwise. Default is * false. * * @since 1.3 */ public void setIgnoreNameNotFoundException(boolean ignore) { this.ignoreNameNotFoundException = ignore; } /** * Specify whether PartialResultException should be ignored in * searches. AD servers typically have a problem with referrals. Normally a * referral should be followed automatically, but this does not seem to work * with AD servers. The problem manifests itself with a a * PartialResultException being thrown when a referral is * encountered by the server. Setting this property to true * presents a workaround to this problem by causing * PartialResultException to be ignored, so that the search * method returns normally. Default value of this parameter is * false. * * @param ignore true if PartialResultException * should be ignored in searches, false otherwise. Default is * false. */ public void setIgnorePartialResultException(boolean ignore) { this.ignorePartialResultException = ignore; } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, int, boolean, * org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void search(Name base, String filter, int searchScope, boolean returningObjFlag, NameClassPairCallbackHandler handler) { search(base, filter, getDefaultSearchControls(searchScope, returningObjFlag, ALL_ATTRIBUTES), handler); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, int, boolean, * org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void search(String base, String filter, int searchScope, boolean returningObjFlag, NameClassPairCallbackHandler handler) { search(base, filter, getDefaultSearchControls(searchScope, returningObjFlag, ALL_ATTRIBUTES), handler); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void search(final Name base, final String filter, final SearchControls controls, NameClassPairCallbackHandler handler) { // Create a SearchExecutor to perform the search. SearchExecutor se = new SearchExecutor() { public NamingEnumeration executeSearch(DirContext ctx) throws javax.naming.NamingException { return ctx.search(base, filter, controls); } }; if (handler instanceof ContextMapperCallbackHandler) { assureReturnObjFlagSet(controls); } search(se, handler); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void search(final String base, final String filter, final SearchControls controls, NameClassPairCallbackHandler handler) { // Create a SearchExecutor to perform the search. SearchExecutor se = new SearchExecutor() { public NamingEnumeration executeSearch(DirContext ctx) throws javax.naming.NamingException { return ctx.search(base, filter, controls); } }; if (handler instanceof ContextMapperCallbackHandler) { assureReturnObjFlagSet(controls); } search(se, handler); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.NameClassPairCallbackHandler, * org.springframework.ldap.core.DirContextProcessor) */ public void search(final Name base, final String filter, final SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) { // Create a SearchExecutor to perform the search. SearchExecutor se = new SearchExecutor() { public NamingEnumeration executeSearch(DirContext ctx) throws javax.naming.NamingException { return ctx.search(base, filter, controls); } }; if (handler instanceof ContextMapperCallbackHandler) { assureReturnObjFlagSet(controls); } search(se, handler, processor); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.NameClassPairCallbackHandler, * org.springframework.ldap.core.DirContextProcessor) */ public void search(final String base, final String filter, final SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) { // Create a SearchExecutor to perform the search. SearchExecutor se = new SearchExecutor() { public NamingEnumeration executeSearch(DirContext ctx) throws javax.naming.NamingException { return ctx.search(base, filter, controls); } }; if (handler instanceof ContextMapperCallbackHandler) { assureReturnObjFlagSet(controls); } search(se, handler, processor); } /** * Perform a search operation, such as a search(), list() or listBindings(). * This method handles all the plumbing; getting a readonly context; looping * through the NamingEnumeration and closing the context and enumeration. It * also calls the supplied DirContextProcessor before and after the search, * respectively. This enables custom pre-processing and post-processing, * like for example when handling paged results or other search controls. *

* The actual list is delegated to the {@link SearchExecutor} and each * {@link NameClassPair} (this might be a NameClassPair or a subclass * thereof) is passed to the CallbackHandler. Any encountered * NamingException will be translated using the NamingExceptionTranslator. * * @param se the SearchExecutor to use for performing the actual list. * @param handler the NameClassPairCallbackHandler to which each found entry * will be passed. * @param processor DirContextProcessor for custom pre- and post-processing. * Must not be null. If no custom processing should take place, * please use e.g. * {@link #search(SearchExecutor, NameClassPairCallbackHandler)}. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is interpreted that * no entries were found. */ public void search(SearchExecutor se, NameClassPairCallbackHandler handler, DirContextProcessor processor) { DirContext ctx = contextSource.getReadOnlyContext(); NamingEnumeration results = null; RuntimeException ex = null; try { processor.preProcess(ctx); results = se.executeSearch(ctx); while (results.hasMore()) { NameClassPair result = (NameClassPair) results.next(); handler.handleNameClassPair(result); } } catch (NameNotFoundException e) { // It is possible to ignore errors caused by base not found if (ignoreNameNotFoundException) { log.warn("Base context not found, ignoring: " + e.getMessage()); } else { ex = LdapUtils.convertLdapException(e); } } catch (PartialResultException e) { // Workaround for AD servers not handling referrals correctly. if (ignorePartialResultException) { log.debug("PartialResultException encountered and ignored", e); } else { ex = LdapUtils.convertLdapException(e); } } catch (javax.naming.NamingException e) { ex = LdapUtils.convertLdapException(e); } finally { try { processor.postProcess(ctx); } catch (javax.naming.NamingException e) { if (ex == null) { ex = LdapUtils.convertLdapException(e); } else { // We already had an exception from above and should ignore // this one. log.debug("Ignoring Exception from postProcess, " + "main exception thrown instead", e); } } closeContextAndNamingEnumeration(ctx, results); // If we got an exception it should be thrown. if (ex != null) { throw ex; } } } /** * Perform a search operation, such as a search(), list() or listBindings(). * This method handles all the plumbing; getting a readonly context; looping * through the NamingEnumeration and closing the context and enumeration. *

* The actual list is delegated to the {@link SearchExecutor} and each * {@link NameClassPair} (this might be a NameClassPair or a subclass * thereof) is passed to the CallbackHandler. Any encountered * NamingException will be translated using the NamingExceptionTranslator. * * @param se the SearchExecutor to use for performing the actual list. * @param handler the NameClassPairCallbackHandler to which each found entry * will be passed. * @throws NamingException if any error occurs. Note that a * NameNotFoundException will be ignored. Instead this is interpreted that * no entries were found. */ public void search(SearchExecutor se, NameClassPairCallbackHandler handler) { search(se, handler, new NullDirContextProcessor()); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, * org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void search(Name base, String filter, NameClassPairCallbackHandler handler) { SearchControls controls = getDefaultSearchControls(DEFAULT_SEARCH_SCOPE, DONT_RETURN_OBJ_FLAG, ALL_ATTRIBUTES); if (handler instanceof ContextMapperCallbackHandler) { assureReturnObjFlagSet(controls); } search(base, filter, controls, handler); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, * org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void search(String base, String filter, NameClassPairCallbackHandler handler) { SearchControls controls = getDefaultSearchControls(DEFAULT_SEARCH_SCOPE, DONT_RETURN_OBJ_FLAG, ALL_ATTRIBUTES); if (handler instanceof ContextMapperCallbackHandler) { assureReturnObjFlagSet(controls); } search(base, filter, controls, handler); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, int, java.lang.String[], * org.springframework.ldap.core.AttributesMapper) */ public List search(Name base, String filter, int searchScope, String[] attrs, AttributesMapper mapper) { return search(base, filter, getDefaultSearchControls(searchScope, DONT_RETURN_OBJ_FLAG, attrs), mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, int, java.lang.String[], * org.springframework.ldap.core.AttributesMapper) */ public List search(String base, String filter, int searchScope, String[] attrs, AttributesMapper mapper) { return search(base, filter, getDefaultSearchControls(searchScope, DONT_RETURN_OBJ_FLAG, attrs), mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, int, org.springframework.ldap.core.AttributesMapper) */ public List search(Name base, String filter, int searchScope, AttributesMapper mapper) { return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, int, org.springframework.ldap.core.AttributesMapper) */ public List search(String base, String filter, int searchScope, AttributesMapper mapper) { return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, org.springframework.ldap.core.AttributesMapper) */ public List search(Name base, String filter, AttributesMapper mapper) { return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, org.springframework.ldap.core.AttributesMapper) */ public List search(String base, String filter, AttributesMapper mapper) { return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, int, java.lang.String[], * org.springframework.ldap.core.ContextMapper) */ public List search(Name base, String filter, int searchScope, String[] attrs, ContextMapper mapper) { return search(base, filter, getDefaultSearchControls(searchScope, RETURN_OBJ_FLAG, attrs), mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, int, java.lang.String[], * org.springframework.ldap.core.ContextMapper) */ public List search(String base, String filter, int searchScope, String[] attrs, ContextMapper mapper) { return search(base, filter, getDefaultSearchControls(searchScope, RETURN_OBJ_FLAG, attrs), mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, int, org.springframework.ldap.core.ContextMapper) */ public List search(Name base, String filter, int searchScope, ContextMapper mapper) { return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, int, org.springframework.ldap.core.ContextMapper) */ public List search(String base, String filter, int searchScope, ContextMapper mapper) { return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, org.springframework.ldap.core.ContextMapper) */ public List search(Name base, String filter, ContextMapper mapper) { return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, org.springframework.ldap.core.ContextMapper) */ public List search(String base, String filter, ContextMapper mapper) { return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.ContextMapper) */ public List search(String base, String filter, SearchControls controls, ContextMapper mapper) { return search(base, filter, controls, mapper, new NullDirContextProcessor()); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.ContextMapper) */ public List search(Name base, String filter, SearchControls controls, ContextMapper mapper) { return search(base, filter, controls, mapper, new NullDirContextProcessor()); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.AttributesMapper) */ public List search(Name base, String filter, SearchControls controls, AttributesMapper mapper) { return search(base, filter, controls, mapper, new NullDirContextProcessor()); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.AttributesMapper) */ public List search(String base, String filter, SearchControls controls, AttributesMapper mapper) { return search(base, filter, controls, mapper, new NullDirContextProcessor()); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.AttributesMapper, * org.springframework.ldap.core.DirContextProcessor) */ public List search(String base, String filter, SearchControls controls, AttributesMapper mapper, DirContextProcessor processor) { AttributesMapperCallbackHandler handler = new AttributesMapperCallbackHandler(mapper); search(base, filter, controls, handler, processor); return handler.getList(); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.AttributesMapper, * org.springframework.ldap.core.DirContextProcessor) */ public List search(Name base, String filter, SearchControls controls, AttributesMapper mapper, DirContextProcessor processor) { AttributesMapperCallbackHandler handler = new AttributesMapperCallbackHandler(mapper); search(base, filter, controls, handler, processor); return handler.getList(); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.ContextMapper, * org.springframework.ldap.core.DirContextProcessor) */ public List search(String base, String filter, SearchControls controls, ContextMapper mapper, DirContextProcessor processor) { assureReturnObjFlagSet(controls); ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler(mapper); search(base, filter, controls, handler, processor); return handler.getList(); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.ContextMapper, * org.springframework.ldap.core.DirContextProcessor) */ public List search(Name base, String filter, SearchControls controls, ContextMapper mapper, DirContextProcessor processor) { assureReturnObjFlagSet(controls); ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler(mapper); search(base, filter, controls, handler, processor); return handler.getList(); } /* * @see org.springframework.ldap.core.LdapOperations#list(java.lang.String, * org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void list(final String base, NameClassPairCallbackHandler handler) { SearchExecutor searchExecutor = new SearchExecutor() { public NamingEnumeration executeSearch(DirContext ctx) throws javax.naming.NamingException { return ctx.list(base); } }; search(searchExecutor, handler); } /* * @see org.springframework.ldap.core.LdapOperations#list(javax.naming.Name, * org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void list(final Name base, NameClassPairCallbackHandler handler) { SearchExecutor searchExecutor = new SearchExecutor() { public NamingEnumeration executeSearch(DirContext ctx) throws javax.naming.NamingException { return ctx.list(base); } }; search(searchExecutor, handler); } /* * @see org.springframework.ldap.core.LdapOperations#list(java.lang.String, * org.springframework.ldap.core.NameClassPairMapper) */ public List list(String base, NameClassPairMapper mapper) { CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(mapper); list(base, handler); return handler.getList(); } /* * @see org.springframework.ldap.core.LdapOperations#list(javax.naming.Name, * org.springframework.ldap.core.NameClassPairMapper) */ public List list(Name base, NameClassPairMapper mapper) { CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(mapper); list(base, handler); return handler.getList(); } /* * @see org.springframework.ldap.core.LdapOperations#list(javax.naming.Name) */ public List list(final Name base) { return list(base, new DefaultNameClassPairMapper()); } /* * @see org.springframework.ldap.core.LdapOperations#list(java.lang.String) */ public List list(final String base) { return list(base, new DefaultNameClassPairMapper()); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(java.lang.String * , org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void listBindings(final String base, NameClassPairCallbackHandler handler) { SearchExecutor searchExecutor = new SearchExecutor() { public NamingEnumeration executeSearch(DirContext ctx) throws javax.naming.NamingException { return ctx.listBindings(base); } }; search(searchExecutor, handler); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(javax.naming * .Name, org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void listBindings(final Name base, NameClassPairCallbackHandler handler) { SearchExecutor searchExecutor = new SearchExecutor() { public NamingEnumeration executeSearch(DirContext ctx) throws javax.naming.NamingException { return ctx.listBindings(base); } }; search(searchExecutor, handler); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(java.lang.String * , org.springframework.ldap.core.NameClassPairMapper) */ public List listBindings(String base, NameClassPairMapper mapper) { CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(mapper); listBindings(base, handler); return handler.getList(); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(javax.naming * .Name, org.springframework.ldap.core.NameClassPairMapper) */ public List listBindings(Name base, NameClassPairMapper mapper) { CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(mapper); listBindings(base, handler); return handler.getList(); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(java.lang.String * ) */ public List listBindings(final String base) { return listBindings(base, new DefaultNameClassPairMapper()); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(javax.naming * .Name) */ public List listBindings(final Name base) { return listBindings(base, new DefaultNameClassPairMapper()); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(java.lang.String * , org.springframework.ldap.core.ContextMapper) */ public List listBindings(String base, ContextMapper mapper) { ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler(mapper); listBindings(base, handler); return handler.getList(); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(javax.naming * .Name, org.springframework.ldap.core.ContextMapper) */ public List listBindings(Name base, ContextMapper mapper) { ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler(mapper); listBindings(base, handler); return handler.getList(); } /* * @seeorg.springframework.ldap.core.LdapOperations#executeReadOnly(org. * springframework.ldap.core.DirContextProcessor) */ public Object executeReadOnly(ContextExecutor ce) { DirContext ctx = contextSource.getReadOnlyContext(); return executeWithContext(ce, ctx); } /* * @seeorg.springframework.ldap.core.LdapOperations#executeReadWrite(org. * springframework.ldap.core.DirContextProcessor) */ public Object executeReadWrite(ContextExecutor ce) { DirContext ctx = contextSource.getReadWriteContext(); return executeWithContext(ce, ctx); } private Object executeWithContext(ContextExecutor ce, DirContext ctx) { try { return ce.executeWithContext(ctx); } catch (javax.naming.NamingException e) { throw LdapUtils.convertLdapException(e); } finally { closeContext(ctx); } } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(javax.naming.Name) */ public Object lookup(final Name dn) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { return ctx.lookup(dn); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(java.lang.String) */ public Object lookup(final String dn) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { return ctx.lookup(dn); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(javax.naming.Name, * org.springframework.ldap.core.AttributesMapper) */ public Object lookup(final Name dn, final AttributesMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Attributes attributes = ctx.getAttributes(dn); return mapper.mapFromAttributes(attributes); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(java.lang.String, * org.springframework.ldap.core.AttributesMapper) */ public Object lookup(final String dn, final AttributesMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Attributes attributes = ctx.getAttributes(dn); return mapper.mapFromAttributes(attributes); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(javax.naming.Name, * org.springframework.ldap.core.ContextMapper) */ public Object lookup(final Name dn, final ContextMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Object object = ctx.lookup(dn); return mapper.mapFromContext(object); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(java.lang.String, * org.springframework.ldap.core.ContextMapper) */ public Object lookup(final String dn, final ContextMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Object object = ctx.lookup(dn); return mapper.mapFromContext(object); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(javax.naming.Name, * java.lang.String[], org.springframework.ldap.core.AttributesMapper) */ public Object lookup(final Name dn, final String[] attributes, final AttributesMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Attributes filteredAttributes = ctx.getAttributes(dn, attributes); return mapper.mapFromAttributes(filteredAttributes); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(java.lang.String, * java.lang.String[], org.springframework.ldap.core.AttributesMapper) */ public Object lookup(final String dn, final String[] attributes, final AttributesMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Attributes filteredAttributes = ctx.getAttributes(dn, attributes); return mapper.mapFromAttributes(filteredAttributes); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(javax.naming.Name, * java.lang.String[], org.springframework.ldap.core.ContextMapper) */ public Object lookup(final Name dn, final String[] attributes, final ContextMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Attributes filteredAttributes = ctx.getAttributes(dn, attributes); DirContextAdapter contextAdapter = new DirContextAdapter(filteredAttributes, dn); return mapper.mapFromContext(contextAdapter); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(java.lang.String, * java.lang.String[], org.springframework.ldap.core.ContextMapper) */ public Object lookup(final String dn, final String[] attributes, final ContextMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Attributes filteredAttributes = ctx.getAttributes(dn, attributes); DistinguishedName name = new DistinguishedName(dn); DirContextAdapter contextAdapter = new DirContextAdapter(filteredAttributes, name); return mapper.mapFromContext(contextAdapter); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#modifyAttributes(javax.naming * .Name, javax.naming.directory.ModificationItem[]) */ public void modifyAttributes(final Name dn, final ModificationItem[] mods) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.modifyAttributes(dn, mods); return null; } }); } /* * @see * org.springframework.ldap.core.LdapOperations#modifyAttributes(java.lang * .String, javax.naming.directory.ModificationItem[]) */ public void modifyAttributes(final String dn, final ModificationItem[] mods) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.modifyAttributes(dn, mods); return null; } }); } /* * @see org.springframework.ldap.core.LdapOperations#bind(javax.naming.Name, * java.lang.Object, javax.naming.directory.Attributes) */ public void bind(final Name dn, final Object obj, final Attributes attributes) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.bind(dn, obj, attributes); return null; } }); } /* * @see org.springframework.ldap.core.LdapOperations#bind(java.lang.String, * java.lang.Object, javax.naming.directory.Attributes) */ public void bind(final String dn, final Object obj, final Attributes attributes) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.bind(dn, obj, attributes); return null; } }); } /* * @see * org.springframework.ldap.core.LdapOperations#unbind(javax.naming.Name) */ public void unbind(final Name dn) { doUnbind(dn); } /* * @see * org.springframework.ldap.core.LdapOperations#unbind(java.lang.String) */ public void unbind(final String dn) { doUnbind(dn); } /* * @see * org.springframework.ldap.core.LdapOperations#unbind(javax.naming.Name, * boolean) */ public void unbind(final Name dn, boolean recursive) { if (!recursive) { doUnbind(dn); } else { doUnbindRecursively(dn); } } /* * @see * org.springframework.ldap.core.LdapOperations#unbind(java.lang.String, * boolean) */ public void unbind(final String dn, boolean recursive) { if (!recursive) { doUnbind(dn); } else { doUnbindRecursively(dn); } } private void doUnbind(final Name dn) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.unbind(dn); return null; } }); } private void doUnbind(final String dn) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.unbind(dn); return null; } }); } private void doUnbindRecursively(final Name dn) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) { deleteRecursively(ctx, new DistinguishedName(dn)); return null; } }); } private void doUnbindRecursively(final String dn) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { deleteRecursively(ctx, new DistinguishedName(dn)); return null; } }); } /** * Delete all subcontexts including the current one recursively. * * @param ctx The context to use for deleting. * @param name The starting point to delete recursively. * @throws NamingException if any error occurs */ protected void deleteRecursively(DirContext ctx, DistinguishedName name) { NamingEnumeration enumeration = null; try { enumeration = ctx.listBindings(name); while (enumeration.hasMore()) { Binding binding = (Binding) enumeration.next(); DistinguishedName childName = new DistinguishedName(binding.getName()); childName.prepend((DistinguishedName) name); deleteRecursively(ctx, childName); } ctx.unbind(name); if (log.isDebugEnabled()) { log.debug("Entry " + name + " deleted"); } } catch (javax.naming.NamingException e) { throw LdapUtils.convertLdapException(e); } finally { try { enumeration.close(); } catch (Exception e) { // Never mind this } } } /* * @see * org.springframework.ldap.core.LdapOperations#rebind(javax.naming.Name, * java.lang.Object, javax.naming.directory.Attributes) */ public void rebind(final Name dn, final Object obj, final Attributes attributes) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.rebind(dn, obj, attributes); return null; } }); } /* * @see * org.springframework.ldap.core.LdapOperations#rebind(java.lang.String, * java.lang.Object, javax.naming.directory.Attributes) */ public void rebind(final String dn, final Object obj, final Attributes attributes) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.rebind(dn, obj, attributes); return null; } }); } /* * @see * org.springframework.ldap.core.LdapOperations#rename(javax.naming.Name, * javax.naming.Name) */ public void rename(final Name oldDn, final Name newDn) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.rename(oldDn, newDn); return null; } }); } /* * @see * org.springframework.ldap.core.LdapOperations#rename(java.lang.String, * java.lang.String) */ public void rename(final String oldDn, final String newDn) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.rename(oldDn, newDn); return null; } }); } /* * @see * org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ public void afterPropertiesSet() throws Exception { if (contextSource == null) { throw new IllegalArgumentException("Property 'contextSource' must be set."); } } private void closeContextAndNamingEnumeration(DirContext ctx, NamingEnumeration results) { closeNamingEnumeration(results); closeContext(ctx); } /** * Close the supplied DirContext if it is not null. Swallow any exceptions, * as this is only for cleanup. * * @param ctx the context to close. */ private void closeContext(DirContext ctx) { if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } /** * Close the supplied NamingEnumeration if it is not null. Swallow any * exceptions, as this is only for cleanup. * * @param results the NamingEnumeration to close. */ private void closeNamingEnumeration(NamingEnumeration results) { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } } private SearchControls getDefaultSearchControls(int searchScope, boolean returningObjFlag, String[] attrs) { SearchControls controls = new SearchControls(); controls.setSearchScope(searchScope); controls.setReturningObjFlag(returningObjFlag); controls.setReturningAttributes(attrs); return controls; } /** * Make sure the returnObjFlag is set in the supplied SearchControls. Set it * and log if it's not set. * * @param controls the SearchControls to check. */ private void assureReturnObjFlagSet(SearchControls controls) { Validate.notNull(controls); if (!controls.getReturningObjFlag()) { log.info("The returnObjFlag of supplied SearchControls is not set" + " but a ContextMapper is used - setting flag to true"); controls.setReturningObjFlag(true); } } private final static class NullDirContextProcessor implements DirContextProcessor { public void postProcess(DirContext ctx) throws NamingException { // Do nothing } public void preProcess(DirContext ctx) throws NamingException { // Do nothing } } /** * A {@link NameClassPairCallbackHandler} that passes the NameClassPairs * found to a NameClassPairMapper and collects the results in a list. * * @author Mattias Hellborg Arthursson */ public final static class MappingCollectingNameClassPairCallbackHandler extends CollectingNameClassPairCallbackHandler { private NameClassPairMapper mapper; public MappingCollectingNameClassPairCallbackHandler(NameClassPairMapper mapper) { this.mapper = mapper; } /* * @seeorg.springframework.ldap.CollectingNameClassPairCallbackHandler# * getObjectFromNameClassPair(javax.naming.NameClassPair) */ public Object getObjectFromNameClassPair(NameClassPair nameClassPair) { try { return mapper.mapFromNameClassPair(nameClassPair); } catch (javax.naming.NamingException e) { throw LdapUtils.convertLdapException(e); } } } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#lookupContext(javax.naming * .Name) */ public DirContextOperations lookupContext(Name dn) { return (DirContextOperations) lookup(dn); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#lookupContext(java.lang. * String) */ public DirContextOperations lookupContext(String dn) { return (DirContextOperations) lookup(dn); } /* * (non-Javadoc) * * @seeorg.springframework.ldap.core.LdapOperations#modifyAttributes(org. * springframework.ldap.core.DirContextOperations) */ public void modifyAttributes(DirContextOperations ctx) { Name dn = ctx.getDn(); if (dn != null && ctx.isUpdateMode()) { modifyAttributes(dn, ctx.getModificationItems()); } else { throw new IllegalStateException("The DirContextOperations instance needs to be properly initialized."); } } /* * (non-Javadoc) * * @seeorg.springframework.ldap.core.LdapOperations#bind(org. * springframework.ldap.core.DirContextOperations) */ public void bind(DirContextOperations ctx) { Name dn = ctx.getDn(); if (dn != null && !ctx.isUpdateMode()) { bind(dn, ctx, null); } else { throw new IllegalStateException("The DirContextOperations instance needs to be properly initialized."); } } /* * @see * org.springframework.ldap.core.LdapOperations#rebind(org.springframework. * ldap.core.DirContextOperations) */ public void rebind(DirContextOperations ctx) { Name dn = ctx.getDn(); if (dn != null && !ctx.isUpdateMode()) { rebind(dn, ctx, null); } else { throw new IllegalStateException( "The DirContextOperations instance needs to be properly initialized."); } } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(javax.naming * .Name, java.lang.String, java.lang.String) */ public boolean authenticate(Name base, String filter, String password) { return authenticate(base, filter, password, new NullAuthenticatedLdapEntryContextCallback(), new NullAuthenticationErrorCallback()); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(java.lang.String * , java.lang.String, java.lang.String) */ public boolean authenticate(String base, String filter, String password) { return authenticate(new DistinguishedName(base), filter, password, new NullAuthenticatedLdapEntryContextCallback(), new NullAuthenticationErrorCallback()); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(java.lang.String * , java.lang.String, java.lang.String, * org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback) */ public boolean authenticate(String base, String filter, String password, AuthenticatedLdapEntryContextCallback callback) { return authenticate(new DistinguishedName(base), filter, password, callback, new NullAuthenticationErrorCallback()); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(javax.naming * .Name, java.lang.String, java.lang.String, * org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback) */ public boolean authenticate(Name base, String filter, String password, final AuthenticatedLdapEntryContextCallback callback) { return authenticate(base, filter, password, callback, new NullAuthenticationErrorCallback()); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(java.lang.String * , java.lang.String, java.lang.String, * org.springframework.ldap.core.AuthenticationErrorCallback) */ public boolean authenticate(String base, String filter, String password, AuthenticationErrorCallback errorCallback) { return authenticate(new DistinguishedName(base), filter, password, new NullAuthenticatedLdapEntryContextCallback(), errorCallback); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(javax.naming * .Name, java.lang.String, java.lang.String, * org.springframework.ldap.core.AuthenticationErrorCallback) */ public boolean authenticate(Name base, String filter, String password, final AuthenticationErrorCallback errorCallback) { return authenticate(base, filter, password, new NullAuthenticatedLdapEntryContextCallback(), errorCallback); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(java.lang.String * , java.lang.String, java.lang.String, * org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback, * org.springframework.ldap.core.AuthenticationErrorCallback) */ public boolean authenticate(String base, String filter, String password, final AuthenticatedLdapEntryContextCallback callback, final AuthenticationErrorCallback errorCallback) { return authenticate(new DistinguishedName(base), filter, password, callback, errorCallback); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(javax.naming * .Name, java.lang.String, java.lang.String, * org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback, * org.springframework.ldap.core.AuthenticationErrorCallback) */ public boolean authenticate(Name base, String filter, String password, final AuthenticatedLdapEntryContextCallback callback, final AuthenticationErrorCallback errorCallback) { List result = search(base, filter, new LdapEntryIdentificationContextMapper()); if (result.size() == 0) { String msg = "No results found for search, base: '" + base + "'; filter: '" + filter + "'."; log.info(msg); return false; } else if (result.size() > 1) { String msg = "base: '" + base + "'; filter: '" + filter + "'."; throw new IncorrectResultSizeDataAccessException(msg, 1, result.size()); } final LdapEntryIdentification entryIdentification = (LdapEntryIdentification) result.get(0); try { DirContext ctx = contextSource.getContext(entryIdentification.getAbsoluteDn().toString(), password); executeWithContext(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { callback.executeWithContext(ctx, entryIdentification); return null; } }, ctx); return true; } catch (Exception e) { log.info("Authentication failed for entry with DN '" + entryIdentification.getAbsoluteDn() + "'", e); errorCallback.execute(e); return false; } } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#searchForObject(javax.naming * .Name, java.lang.String, org.springframework.ldap.core.ContextMapper) */ public Object searchForObject(Name base, String filter, ContextMapper mapper) { List result = search(base, filter, mapper); if (result.size() == 0) { throw new EmptyResultDataAccessException(1); } else if (result.size() != 1) { throw new IncorrectResultSizeDataAccessException(1, result.size()); } return result.get(0); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#searchForObject(java.lang * .String, java.lang.String, org.springframework.ldap.core.ContextMapper) */ public Object searchForObject(String base, String filter, ContextMapper mapper) { return searchForObject(new DistinguishedName(base), filter, mapper); } private static final class NullAuthenticatedLdapEntryContextCallback implements AuthenticatedLdapEntryContextCallback { public void executeWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) { // Do nothing } } private static final class NullAuthenticationErrorCallback implements AuthenticationErrorCallback { public void execute(Exception e) { // Do nothing } } } ././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/ContextAssembler.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000234011475313376030210 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; /** * Helper interface to be used by Dao implementations for assembling to and from * context. Useful if we have assembler classes responsible for mapping to and * from a specific entry. * * @author Mattias Hellborg Arthursson */ public interface ContextAssembler extends ContextMapper { /** * Map the supplied object to the specified context. * * @param obj * the object to read data from. * @param ctx * the context to map to. */ void mapToContext(Object obj, Object ctx); } ././@LongLink0000000000000000000000000000021400000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/ContextMapperCallbackHandler.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000435511475313376030220 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.Binding; import javax.naming.NameClassPair; import org.apache.commons.lang.Validate; /** * A CollectingNameClassPairCallbackHandler to wrap a ContextMapper. That is, * the found object is extracted from each {@link Binding}, and then passed to * the specified ContextMapper for translation. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg * @since 1.2 */ public class ContextMapperCallbackHandler extends CollectingNameClassPairCallbackHandler { private ContextMapper mapper; /** * Constructs a new instance wrapping the supplied {@link ContextMapper}. * * @param mapper * the mapper to be called for each entry. */ public ContextMapperCallbackHandler(ContextMapper mapper) { Validate.notNull(mapper, "Mapper must not be empty"); this.mapper = mapper; } /** * Cast the NameClassPair to a {@link Binding} and pass its object to * the ContextMapper. * * @param nameClassPair * a Binding instance. * @return the Object returned from the mapper. */ public Object getObjectFromNameClassPair(NameClassPair nameClassPair) { if (!(nameClassPair instanceof Binding)) { throw new IllegalArgumentException("Parameter must be an instance of Binding"); } Binding binding = (Binding) nameClassPair; Object object = binding.getObject(); if (object == null) { throw new ObjectRetrievalException( "Binding did not contain any object."); } return mapper.mapFromContext(object); } }././@LongLink0000000000000000000000000000021300000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/core/AttributeModificationsAware.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000233011475313376030207 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import javax.naming.directory.ModificationItem; /** * Indicates that the implementing class is capable of keeping track of any * attribute modifications and return them as ModificationItems. * * @author Mattias Hellborg Arthursson * */ public interface AttributeModificationsAware { /** * Creates an array of which attributes have been changed, added or removed * since the initialization of this object. * * @return an array of modification items. */ ModificationItem[] getModificationItems(); } ././@LongLink0000000000000000000000000000017600000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/NotContextException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000175511475313376030221 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI NotContextException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.NotContextException */ public class NotContextException extends NamingException { public NotContextException(javax.naming.NotContextException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020500000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/SizeLimitExceededException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000204511475313376030212 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI SizeLimitExceededException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.SizeLimitExceededException */ public class SizeLimitExceededException extends LimitExceededException { public SizeLimitExceededException( javax.naming.SizeLimitExceededException cause) { super(cause); } } ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/support/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0002755000000000000000000000000011475313376030211 5ustar ././@LongLink0000000000000000000000000000022000000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/support/AttributeValueCallbackHandler.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000220511475313376030210 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.support; /** * Callback interface for use when looping through Attribute values. * * @author Mattias Hellborg Arthursson * @since 1.3 */ public interface AttributeValueCallbackHandler { /** * Implement to take handle one of the Attribute values. * * @param attributeName the name of the Attribute. * @param attributeValue the value. * @param index the index of the value within the Attribute. */ void handleAttributeValue(String attributeName, Object attributeValue, int index); } ././@LongLink0000000000000000000000000000017200000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/support/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000011011475313376030201 0ustar Support classes for Spring-LDAP. ././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/support/ListComparator.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000400511475313376030210 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.support; import java.io.Serializable; import java.util.Comparator; import java.util.List; /** * Comparator for comparing lists of Comparable objects. * * @author Mattias Hellborg Arthursson */ public class ListComparator implements Comparator, Serializable { private static final long serialVersionUID = -3068381879731157178L; /** * Compare two lists of Comparable objects. * * @param o1 the first object to be compared. * @param o2 the second object to be compared. * @throws ClassCastException if any of the lists contains an object that * is not Comparable. */ public int compare(Object o1, Object o2) { List list1 = (List) o1; List list2 = (List) o2; for (int i = 0; i < list1.size(); i++) { if (list2.size() > i) { Comparable component1 = (Comparable) list1.get(i); Comparable component2 = (Comparable) list2.get(i); int componentsCompared = component1.compareTo(component2); if (componentsCompared != 0) { return componentsCompared; } } else { // First instance has more components, so that instance is // greater. return 1; } } // All components so far are equal - if the other instance has // more components it is greater otherwise they are equal. if (list2.size() > list1.size()) { return -1; } else { return 0; } } } ././@LongLink0000000000000000000000000000017400000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/support/LdapUtils.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000004527511475313376030226 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.support; import java.math.BigInteger; import java.util.Collection; import javax.naming.CompositeName; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.ldap.LdapContext; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.NamingException; import org.springframework.ldap.NoSuchAttributeException; import org.springframework.util.Assert; /** * Generic utility methods for working with LDAP. Mainly for internal use within * the framework, but also useful for custom code. * * @author Ulrik Sandberg * @since 1.2 */ public final class LdapUtils { private static final Log logger = LogFactory.getLog(LdapUtils.class); /** * Not to be instantiated. */ private LdapUtils() { } /** * Close the given JNDI Context and ignore any thrown exception. This is * useful for typical finally blocks in JNDI code. * * @param context the JNDI Context to close (may be null) */ public static void closeContext(DirContext context) { if (context != null) { try { context.close(); } catch (NamingException ex) { logger.debug("Could not close JNDI DirContext", ex); } catch (Throwable ex) { // We don't trust the JNDI provider: It might throw // RuntimeException or Error. logger.debug("Unexpected exception on closing JNDI DirContext", ex); } } } /** * Convert the specified checked {@link javax.naming.NamingException * NamingException} to a Spring LDAP runtime * {@link org.springframework.ldap.NamingException NamingException} * equivalent. * * @param ex the original checked NamingException to convert * @return the Spring LDAP runtime NamingException wrapping the given * exception */ public static NamingException convertLdapException(javax.naming.NamingException ex) { Assert.notNull(ex, "NamingException must not be null"); if (ex.getClass().equals(javax.naming.directory.AttributeInUseException.class)) { return new org.springframework.ldap.AttributeInUseException( (javax.naming.directory.AttributeInUseException) ex); } if (ex.getClass().equals(javax.naming.directory.AttributeModificationException.class)) { return new org.springframework.ldap.AttributeModificationException( (javax.naming.directory.AttributeModificationException) ex); } if (ex.getClass().equals(javax.naming.CannotProceedException.class)) { return new org.springframework.ldap.CannotProceedException((javax.naming.CannotProceedException) ex); } if (ex.getClass().equals(javax.naming.CommunicationException.class)) { return new org.springframework.ldap.CommunicationException((javax.naming.CommunicationException) ex); } if (ex.getClass().equals(javax.naming.ConfigurationException.class)) { return new org.springframework.ldap.ConfigurationException((javax.naming.ConfigurationException) ex); } if (ex.getClass().equals(javax.naming.ContextNotEmptyException.class)) { return new org.springframework.ldap.ContextNotEmptyException((javax.naming.ContextNotEmptyException) ex); } if (ex.getClass().equals(javax.naming.InsufficientResourcesException.class)) { return new org.springframework.ldap.InsufficientResourcesException( (javax.naming.InsufficientResourcesException) ex); } if (ex.getClass().equals(javax.naming.InterruptedNamingException.class)) { return new org.springframework.ldap.InterruptedNamingException((javax.naming.InterruptedNamingException) ex); } if (ex.getClass().equals(javax.naming.directory.InvalidAttributeIdentifierException.class)) { return new org.springframework.ldap.InvalidAttributeIdentifierException( (javax.naming.directory.InvalidAttributeIdentifierException) ex); } if (ex.getClass().equals(javax.naming.directory.InvalidAttributesException.class)) { return new org.springframework.ldap.InvalidAttributesException( (javax.naming.directory.InvalidAttributesException) ex); } if (ex.getClass().equals(javax.naming.directory.InvalidAttributeValueException.class)) { return new org.springframework.ldap.InvalidAttributeValueException( (javax.naming.directory.InvalidAttributeValueException) ex); } if (ex.getClass().equals(javax.naming.InvalidNameException.class)) { return new org.springframework.ldap.InvalidNameException((javax.naming.InvalidNameException) ex); } if (ex.getClass().equals(javax.naming.directory.InvalidSearchControlsException.class)) { return new org.springframework.ldap.InvalidSearchControlsException( (javax.naming.directory.InvalidSearchControlsException) ex); } if (ex.getClass().equals(javax.naming.directory.InvalidSearchFilterException.class)) { return new org.springframework.ldap.InvalidSearchFilterException( (javax.naming.directory.InvalidSearchFilterException) ex); } // this class is abstract, so it can never be of exactly this class; // using instanceof if (ex instanceof javax.naming.ldap.LdapReferralException) { return new org.springframework.ldap.LdapReferralException((javax.naming.ldap.LdapReferralException) ex); } // Skipping the abstract superclass javax.naming.ReferralException // LimitExceededException hierarchy if (ex.getClass().equals(javax.naming.SizeLimitExceededException.class)) { return new org.springframework.ldap.SizeLimitExceededException((javax.naming.SizeLimitExceededException) ex); } if (ex.getClass().equals(javax.naming.TimeLimitExceededException.class)) { return new org.springframework.ldap.TimeLimitExceededException((javax.naming.TimeLimitExceededException) ex); } // this class is the superclass of the two above if (ex.getClass().equals(javax.naming.LimitExceededException.class)) { return new org.springframework.ldap.LimitExceededException((javax.naming.LimitExceededException) ex); } // LinkException hierarchy if (ex.getClass().equals(javax.naming.LinkLoopException.class)) { return new org.springframework.ldap.LinkLoopException((javax.naming.LinkLoopException) ex); } if (ex.getClass().equals(javax.naming.MalformedLinkException.class)) { return new org.springframework.ldap.MalformedLinkException((javax.naming.MalformedLinkException) ex); } // this class is the superclass of the two above if (ex.getClass().equals(javax.naming.LinkException.class)) { return new org.springframework.ldap.LinkException((javax.naming.LinkException) ex); } if (ex.getClass().equals(javax.naming.NameAlreadyBoundException.class)) { return new org.springframework.ldap.NameAlreadyBoundException((javax.naming.NameAlreadyBoundException) ex); } if (ex.getClass().equals(javax.naming.NameNotFoundException.class)) { return new org.springframework.ldap.NameNotFoundException((javax.naming.NameNotFoundException) ex); } // NamingSecurityException hierarchy if (ex.getClass().equals(javax.naming.NoPermissionException.class)) { return new org.springframework.ldap.NoPermissionException((javax.naming.NoPermissionException) ex); } if (ex.getClass().equals(javax.naming.AuthenticationException.class)) { return new org.springframework.ldap.AuthenticationException((javax.naming.AuthenticationException) ex); } if (ex.getClass().equals(javax.naming.AuthenticationNotSupportedException.class)) { return new org.springframework.ldap.AuthenticationNotSupportedException( (javax.naming.AuthenticationNotSupportedException) ex); } // Skipping the abstract superclass javax.naming.NamingSecurityException if (ex.getClass().equals(javax.naming.NoInitialContextException.class)) { return new org.springframework.ldap.NoInitialContextException((javax.naming.NoInitialContextException) ex); } if (ex.getClass().equals(javax.naming.directory.NoSuchAttributeException.class)) { return new org.springframework.ldap.NoSuchAttributeException( (javax.naming.directory.NoSuchAttributeException) ex); } if (ex.getClass().equals(javax.naming.NotContextException.class)) { return new org.springframework.ldap.NotContextException((javax.naming.NotContextException) ex); } if (ex.getClass().equals(javax.naming.OperationNotSupportedException.class)) { return new org.springframework.ldap.OperationNotSupportedException( (javax.naming.OperationNotSupportedException) ex); } if (ex.getClass().equals(javax.naming.PartialResultException.class)) { return new org.springframework.ldap.PartialResultException((javax.naming.PartialResultException) ex); } if (ex.getClass().equals(javax.naming.directory.SchemaViolationException.class)) { return new org.springframework.ldap.SchemaViolationException( (javax.naming.directory.SchemaViolationException) ex); } if (ex.getClass().equals(javax.naming.ServiceUnavailableException.class)) { return new org.springframework.ldap.ServiceUnavailableException( (javax.naming.ServiceUnavailableException) ex); } // fallback return new org.springframework.ldap.UncategorizedLdapException(ex); } /** * Get the actual class of the supplied DirContext instance; LdapContext or * DirContext. * * @param context the DirContext instance to check. * @return LdapContext.class if context is an LdapContext, DirContext.class * otherwise. */ public static Class getActualTargetClass(DirContext context) { if (context instanceof LdapContext) { return LdapContext.class; } return DirContext.class; } /** * Collect all the values of a the specified attribute from the supplied * Attributes. * * @param attributes The Attributes; not null. * @param name The name of the Attribute to get values for. * @param collection the collection to collect the values in. * @throws NoSuchAttributeException if no attribute with the specified name * exists. * @since 1.3 */ public static void collectAttributeValues(Attributes attributes, String name, Collection collection) { Assert.notNull(attributes, "Attributes must not be null"); Attribute attribute = attributes.get(name); if (attribute == null) { throw new NoSuchAttributeException("No attribute with name '" + name + "'"); } iterateAttributeValues(attribute, new CollectingAttributeValueCallbackHandler(collection)); } /** * Iterate through all the values of the specified Attribute calling back to * the specified callbackHandler. * @param attribute the Attribute to work with; not null. * @param callbackHandler the callbackHandler; not null. * @since 1.3 */ public static void iterateAttributeValues(Attribute attribute, AttributeValueCallbackHandler callbackHandler) { Assert.notNull(attribute, "Attribute must not be null"); Assert.notNull(callbackHandler, "callbackHandler must not be null"); for (int i = 0; i < attribute.size(); i++) { try { callbackHandler.handleAttributeValue(attribute.getID(), attribute.get(i), i); } catch (javax.naming.NamingException e) { throw LdapUtils.convertLdapException(e); } } } /** * An {@link AttributeValueCallbackHandler} to collect values in a supplied * collection. * * @author Mattias Hellborg Arthursson */ private final static class CollectingAttributeValueCallbackHandler implements AttributeValueCallbackHandler { private final Collection collection; public CollectingAttributeValueCallbackHandler(Collection collection) { Assert.notNull(collection, "Collection must not be null"); this.collection = collection; } public final void handleAttributeValue(String attributeName, Object attributeValue, int index) { collection.add(attributeValue); } } /** * Converts a CompositeName to a String in a way that avoids escaping * problems, such as the dreaded "triple backslash" problem. * * @param compositeName The CompositeName to convert * @return String containing the String representation of name */ public static String convertCompositeNameToString( CompositeName compositeName) { if (compositeName.size() > 0) { // A lookup with an empty String seems to produce an empty // compositeName here; need to take this into account. return compositeName.get(0); } else { return ""; } } /** * Converts a binary SID to its String representation, according to the * algorithm described here. Thanks to Eyal * Lupu for algorithmic inspiration. * *

	 * If you have a SID like S-a-b-c-d-e-f-g-...
	 * 
	 * Then the bytes are
	 * a	(revision)
	 * N	(number of dashes minus two)
	 * bbbbbb	(six bytes of "b" treated as a 48-bit number in big-endian format)
	 * cccc	(four bytes of "c" treated as a 32-bit number in little-endian format)
	 * dddd	(four bytes of "d" treated as a 32-bit number in little-endian format)
	 * eeee	(four bytes of "e" treated as a 32-bit number in little-endian format)
	 * ffff	(four bytes of "f" treated as a 32-bit number in little-endian format)
	 * etc.	
	 * 
	 * So for example, if your SID is S-1-5-21-2127521184-1604012920-1887927527-72713, then your raw hex SID is
	 * 
	 * 010500000000000515000000A065CF7E784B9B5FE77C8770091C0100
	 * 
	 * This breaks down as follows:
	 * 01	S-1
	 * 05	(seven dashes, seven minus two = 5)
	 * 000000000005	(5 = 0x000000000005, big-endian)
	 * 15000000	(21 = 0x00000015, little-endian)
	 * A065CF7E	(2127521184 = 0x7ECF65A0, little-endian)
	 * 784B9B5F	(1604012920 = 0x5F9B4B78, little-endian)
	 * E77C8770	(1887927527 = 0X70877CE7, little-endian)
	 * 091C0100	(72713 = 0x00011c09, little-endian)
	 * 
	 * S-1-	version number (SID_REVISION)
	 * -5-	SECURITY_NT_AUTHORITY
	 * -21-	SECURITY_NT_NON_UNIQUE
	 * -...-...-...-	these identify the machine that issued the SID
	 * 72713	unique user id on the machine
	 * 
* * @param sid binary SID in byte array format * @return String version of the given sid * @since 1.3.1 */ public static String convertBinarySidToString(byte[] sid) { // Add the 'S' prefix StringBuffer sidAsString = new StringBuffer("S-"); // bytes[0] : in the array is the version (must be 1 but might // change in the future) sidAsString.append(sid[0]).append('-'); // bytes[2..7] : the Authority StringBuffer sb = new StringBuffer(); for (int t = 2; t <= 7; t++) { String hexString = Integer.toHexString(sid[t] & 0xFF); sb.append(hexString); } sidAsString.append(Long.parseLong(sb.toString(), 16)); // bytes[1] : the sub authorities count int count = sid[1]; // bytes[8..end] : the sub authorities (these are Integers - notice // the endian) for (int i = 0; i < count; i++) { int currSubAuthOffset = i * 4; sb.setLength(0); sb.append(toHexString((byte) (sid[11 + currSubAuthOffset] & 0xFF))); sb.append(toHexString((byte) (sid[10 + currSubAuthOffset] & 0xFF))); sb.append(toHexString((byte) (sid[9 + currSubAuthOffset] & 0xFF))); sb.append(toHexString((byte) (sid[8 + currSubAuthOffset] & 0xFF))); sidAsString.append('-').append(Long.parseLong(sb.toString(), 16)); } // That's it - we have the SID return sidAsString.toString(); } /** * Converts a String SID to its binary representation, according to the * algorithm described here. * * @param string SID in readable format * @return Binary version of the given sid * @see LdapUtils#convertBinarySidToString(byte[]) * @since 1.3.1 */ public static byte[] convertStringSidToBinary(String string) { String[] parts = string.split("-"); byte sidRevision = (byte) Integer.parseInt(parts[1]); int subAuthCount = parts.length - 3; byte[] sid = new byte[] {sidRevision, (byte) subAuthCount}; sid = ArrayUtils.addAll(sid, numberToBytes(parts[2], 6, true)); for (int i = 0; i < subAuthCount; i++) { sid = ArrayUtils.addAll(sid, numberToBytes(parts[3 + i], 4, false)); } return sid; } /** * Converts the given number to a binary representation of the specified * length and "endian-ness". * * @param number String with number to convert * @param length How long the resulting binary array should be * @param bigEndian true if big endian (5=0005), or * false if little endian (5=5000) * @return byte array containing the binary result in the given order */ static byte[] numberToBytes(String number, int length, boolean bigEndian) { BigInteger bi = new BigInteger(number); byte[] bytes = bi.toByteArray(); int remaining = length - bytes.length; if (remaining < 0) { bytes = ArrayUtils.subarray(bytes, -remaining, bytes.length); } else { byte[] fill = new byte[remaining]; bytes = ArrayUtils.addAll(fill, bytes); } if (!bigEndian) { ArrayUtils.reverse(bytes); } return bytes; } /** * Converts a byte into its hexadecimal representation, padding with a * leading zero to get an even number of characters. * * @param b value to convert * @return hex string, possibly padded with a zero */ static String toHexString(final byte b) { String hexString = Integer.toHexString(b & 0xFF); if (hexString.length() % 2 != 0) { // Pad with 0 hexString = "0" + hexString; } return hexString; } /** * Converts a byte array into its hexadecimal representation, padding each * with a leading zero to get an even number of characters. * * @param b values to convert * @return hex string, possibly with elements padded with a zero */ static String toHexString(final byte[] b) { StringBuffer sb = new StringBuffer("{"); for (int i = 0; i < b.length; i++) { sb.append(toHexString(b[i])); if (i < b.length - 1) { sb.append(","); } } sb.append("}"); return sb.toString(); } } ././@LongLink0000000000000000000000000000020300000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/SchemaViolationException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000205011475313376030206 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI SchemaViolationException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.directory.SchemaViolationException */ public class SchemaViolationException extends NamingException { public SchemaViolationException( javax.naming.directory.SchemaViolationException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/LdapReferralException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000227211475313376030214 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI LdapReferralException. * * This class is not abstract. We need to be able to instantiate it, should the * caught exception be a provider-specific subclass of * {@link javax.naming.ldap.LdapReferralException}. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.ldap.LdapReferralException */ public class LdapReferralException extends ReferralException { public LdapReferralException(javax.naming.ldap.LdapReferralException cause) { super(cause); } } ././@LongLink0000000000000000000000000000021600000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/InvalidAttributeIdentifierException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000213711475313376030214 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI InvalidAttributeIdentifierException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.directory.InvalidAttributeIdentifierException */ public class InvalidAttributeIdentifierException extends NamingException { public InvalidAttributeIdentifierException( javax.naming.directory.InvalidAttributeIdentifierException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020200000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/AuthenticationException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000201111475313376030203 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI AuthenticationException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.AuthenticationException */ public class AuthenticationException extends NamingSecurityException { public AuthenticationException(javax.naming.AuthenticationException cause) { super(cause); } } ././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000021211475313376030204 0ustar Base package of Spring LDAP, containing an unchecked mirror of the JNDI NamingException hierarchy. ././@LongLink0000000000000000000000000000020500000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/UncategorizedLdapException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000227711475313376030221 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * NamingException to be thrown when no other matching subclass is found. * * @author Ulrik Sandberg * @since 1.2 */ public class UncategorizedLdapException extends NamingException { public UncategorizedLdapException(String msg) { super(msg); } public UncategorizedLdapException(String msg, Throwable cause) { super(msg, cause); } public UncategorizedLdapException(Throwable cause) { super("Uncategorized exception occured during LDAP processing", cause); } } ././@LongLink0000000000000000000000000000020200000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/AttributeInUseException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000204311475313376030210 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI AttributeInUseException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.directory.AttributeInUseException */ public class AttributeInUseException extends NamingException { public AttributeInUseException( javax.naming.directory.AttributeInUseException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/CannotProceedException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000177411475313376030222 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI CannotProceedException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.CannotProceedException */ public class CannotProceedException extends NamingException { public CannotProceedException(javax.naming.CannotProceedException cause) { super(cause); } } ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/control/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0002755000000000000000000000000011475313376030211 5ustar ././@LongLink0000000000000000000000000000017600000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/control/PagedResult.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000501111475313376030206 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.control; import java.util.List; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; /** * Bean to encapsulate a result List and a {@link PagedResultsCookie} to use for * returning the results when using {@link PagedResultsRequestControl}. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class PagedResult { private List resultList; private PagedResultsCookie cookie; /** * Constructs a PagedResults using the supplied List and * {@link PagedResultsCookie}. * * @param resultList * the result list. * @param cookie * the cookie. */ public PagedResult(List resultList, PagedResultsCookie cookie) { this.resultList = resultList; this.cookie = cookie; } /** * Get the cookie. * * @return the cookie. */ public PagedResultsCookie getCookie() { return cookie; } /** * Get the result list. * * @return the result list. */ public List getResultList() { return resultList; } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { if (obj != null && this.getClass().equals(obj.getClass())) { PagedResult that = (PagedResult) obj; return new EqualsBuilder().append(this.resultList, that.resultList) .append(this.cookie, that.cookie).isEquals(); } return false; } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ public int hashCode() { return new HashCodeBuilder().append(this.resultList) .append(this.cookie).toHashCode(); } } ././@LongLink0000000000000000000000000000022100000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/control/SortControlDirContextProcessor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000674011475313376030220 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.control; import javax.naming.ldap.Control; /** * DirContextProcessor implementation for managing the SortControl. Note that * this class is stateful, so a new instance needs to be instantiated for each * new search. * * @author Ulrik Sandberg */ public class SortControlDirContextProcessor extends AbstractFallbackRequestAndResponseControlDirContextProcessor { private static final String DEFAULT_REQUEST_CONTROL = "javax.naming.ldap.SortControl"; private static final String FALLBACK_REQUEST_CONTROL = "com.sun.jndi.ldap.ctl.SortControl"; private static final String DEFAULT_RESPONSE_CONTROL = "javax.naming.ldap.SortResponseControl"; private static final String FALLBACK_RESPONSE_CONTROL = "com.sun.jndi.ldap.ctl.SortResponseControl"; /** * What key to sort on. */ String sortKey; /** * Whether the search result actually was sorted. */ private boolean sorted; /** * The result code of the supposedly sorted search. */ private int resultCode; /** * Constructs a new instance using the supplied sort key. * * @param sortKey the sort key, i.e. the attribute name to sort on. */ public SortControlDirContextProcessor(String sortKey) { this.sortKey = sortKey; this.sorted = false; this.resultCode = -1; defaultRequestControl = DEFAULT_REQUEST_CONTROL; defaultResponseControl = DEFAULT_RESPONSE_CONTROL; fallbackRequestControl = FALLBACK_REQUEST_CONTROL; fallbackResponseControl = FALLBACK_RESPONSE_CONTROL; loadControlClasses(); } /** * Check whether the returned values were actually sorted by the server. * * @return true if the result was sorted, false * otherwise. */ public boolean isSorted() { return sorted; } /** * Get the result code returned by the control. * * @return result code. */ public int getResultCode() { return resultCode; } /** * Get the sort key. * * @return the sort key. */ public String getSortKey() { return sortKey; } /* * @see * org.springframework.ldap.control.AbstractRequestControlDirContextProcessor * #createRequestControl() */ public Control createRequestControl() { return super.createRequestControl(new Class[] { String[].class, boolean.class }, new Object[] { new String[] { sortKey }, Boolean.valueOf(critical) }); } /* * @see org.springframework.ldap.control. * AbstractFallbackRequestAndResponseControlDirContextProcessor * #handleResponse(java.lang.Object) */ protected void handleResponse(Object control) { Boolean result = (Boolean) invokeMethod("isSorted", responseControlClass, control); this.sorted = result.booleanValue(); Integer code = (Integer) invokeMethod("getResultCode", responseControlClass, control); this.resultCode = code.intValue(); } } ././@LongLink0000000000000000000000000000017200000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/control/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000014611475313376030212 0ustar Support classes for custom request control context processors. ././@LongLink0000000000000000000000000000025700000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/control/AbstractFallbackRequestAndResponseControlDirContextProcessor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001464611475313376030224 0ustar package org.springframework.ldap.control; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.ldap.Control; import javax.naming.ldap.LdapContext; import org.springframework.ldap.UncategorizedLdapException; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; /** * Convenient base class useful when implementing a standard DirContextProcessor * which has a request control and a response control. It handles the loading of * the control classes, using fallback implementations specified by the subclass * if necessary. It handles the request control constructor invocation; it only * needs the constructor arguments to be provided. It also handles most of the * work in the post processing of the response control, only delegating to a * template method for the actual value retrieval. In short, it makes it easy to * implement a custom DirContextProcessor.

* *
 * public class SortControlDirContextProcessor extends AbstractFallbackRequestAndResponseControlDirContextProcessor {
 * 	String sortKey;
 * 
 * 	private boolean sorted = false;
 * 
 * 	private int resultCode = -1;
 * 
 * 	public SortControlDirContextProcessor(String sortKey) {
 * 		this.sortKey = sortKey;
 * 
 * 		defaultRequestControl = "javax.naming.ldap.SortControl";
 * 		defaultResponseControl = "com.sun.jndi.ldap.ctl.SortControl";
 * 		fallbackRequestControl = "javax.naming.ldap.SortResponseControl";
 * 		fallbackResponseControl = "com.sun.jndi.ldap.ctl.SortResponseControl";
 * 
 * 		loadControlClasses();
 * 	}
 * 
 * 	public boolean isSorted() {
 * 		return sorted;
 * 	}
 * 
 * 	public int getResultCode() {
 * 		return resultCode;
 * 	}
 * 
 * 	public Control createRequestControl() {
 * 		return super.createRequestControl(new Class[] { String[].class, boolean.class }, new Object[] {
 *				new String[] { sortKey }, Boolean.valueOf(critical) });
 * 	}
 * 
 * 	protected void handleResponse(Object control) {
 * 		Boolean result = (Boolean) invokeMethod("isSorted", responseControlClass, control);
 * 		this.sorted = result.booleanValue();
 * 		Integer code = (Integer) invokeMethod("getResultCode", responseControlClass, control);
 * 		resultCode = code.intValue();
 * 	}
 * }
 * 
* * @author Ulrik Sandberg */ public abstract class AbstractFallbackRequestAndResponseControlDirContextProcessor extends AbstractRequestControlDirContextProcessor { private static final boolean CRITICAL_CONTROL = true; protected Class responseControlClass; protected Class requestControlClass; protected boolean critical = CRITICAL_CONTROL; protected String defaultRequestControl; protected String defaultResponseControl; protected String fallbackRequestControl; protected String fallbackResponseControl; protected void loadControlClasses() { Assert.notNull(defaultRequestControl, "defaultRequestControl must not be null"); Assert.notNull(defaultResponseControl, "defaultResponseControl must not be null"); Assert.notNull(fallbackRequestControl, "fallbackRequestControl must not be null"); Assert.notNull(fallbackResponseControl, "fallbackReponseControl must not be null"); try { requestControlClass = Class.forName(defaultRequestControl); responseControlClass = Class.forName(defaultResponseControl); } catch (ClassNotFoundException e) { log.debug("Default control classes not found - falling back to LdapBP classes", e); try { requestControlClass = Class.forName(fallbackRequestControl); responseControlClass = Class.forName(fallbackResponseControl); } catch (ClassNotFoundException e1) { throw new UncategorizedLdapException( "Neither default nor fallback classes are available - unable to proceed", e); } } } /** * Set the class of the expected ResponseControl for the sorted result * response. * * @param responseControlClass Class of the expected response control. */ public void setResponseControlClass(Class responseControlClass) { this.responseControlClass = responseControlClass; } public void setRequestControlClass(Class requestControlClass) { this.requestControlClass = requestControlClass; } /** * Utility method for invoking a method on a Control. * @param method name of method to invoke * @param clazz Class of the object that the method should be invoked on * @param control Instance that the method should be invoked on * @return the invocation result, if any */ protected Object invokeMethod(String method, Class clazz, Object control) { Method actualMethod = ReflectionUtils.findMethod(clazz, method); return ReflectionUtils.invokeMethod(actualMethod, control); } /** * Creates a request control using the constructor parameters given in * params. * @param paramTypes Types of the constructor parameters * @param params Actual constructor parameters * @return Control to be used by the DirContextProcessor */ public Control createRequestControl(Class[] paramTypes, Object[] params) { Constructor constructor = ClassUtils.getConstructorIfAvailable(requestControlClass, paramTypes); if (constructor == null) { throw new IllegalArgumentException("Failed to find an appropriate RequestControl constructor"); } Control result = null; try { result = (Control) constructor.newInstance(params); } catch (Exception e) { ReflectionUtils.handleReflectionException(e); } return result; } /* * @see * org.springframework.ldap.core.DirContextProcessor#postProcess(javax.naming * .directory.DirContext) */ public void postProcess(DirContext ctx) throws NamingException { LdapContext ldapContext = (LdapContext) ctx; Control[] responseControls = ldapContext.getResponseControls(); if (responseControls == null) { responseControls = new Control[0]; } // Go through response controls and get info, regardless of class for (int i = 0; i < responseControls.length; i++) { Control responseControl = responseControls[i]; // check for match, try fallback otherwise if (responseControl.getClass().isAssignableFrom(responseControlClass)) { Object control = responseControl; handleResponse(control); return; } } log.fatal("No matching response control found for paged results - looking for '" + responseControlClass); } protected abstract void handleResponse(Object control); } ././@LongLink0000000000000000000000000000021500000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/control/PagedResultsRequestControl.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001626011475313376030216 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.control; import org.springframework.ldap.UncategorizedLdapException; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.ldap.Control; import javax.naming.ldap.LdapContext; import java.lang.reflect.Constructor; import java.lang.reflect.Method; /** * DirContextProcessor implementation for managing the paged results control. * Note that due to the internal workings of LdapTemplate, the * target connection is closed after each LDAP call. The PagedResults control * require the same connection be used for each call, which means we need to * make sure the target connection is never actually closed. There's basically * two ways of making this happen: use the SingleContextSource * implementation or make sure all calls happen within a single LDAP transaction * (using ContextSourceTransactionManager). * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg * @deprecated Use PagedResultsDirContextProcessor instead. */ public class PagedResultsRequestControl extends AbstractRequestControlDirContextProcessor { private static final boolean CRITICAL_CONTROL = true; private static final String DEFAULT_REQUEST_CONTROL = "javax.naming.ldap.PagedResultsControl"; private static final String LDAPBP_REQUEST_CONTROL = "com.sun.jndi.ldap.ctl.PagedResultsControl"; private static final String DEFAULT_RESPONSE_CONTROL = "javax.naming.ldap.PagedResultsResponseControl"; private static final String LDAPBP_RESPONSE_CONTROL = "com.sun.jndi.ldap.ctl.PagedResultsResponseControl"; private int pageSize; private PagedResultsCookie cookie; private int resultSize; private boolean critical = CRITICAL_CONTROL; private Class responseControlClass; private Class requestControlClass; /** * Constructs a new instance. This constructor should be used when * performing the first paged search operation, when no other results have * been retrieved. * * @param pageSize the page size. */ public PagedResultsRequestControl(int pageSize) { this(pageSize, null); } /** * Constructs a new instance with the supplied page size and cookie. The * cookie must be the exact same instance as received from a previous paged * resullts search, or null if it is the first in an operation * sequence. * * @param pageSize the page size. * @param cookie the cookie, as received from a previous search. */ public PagedResultsRequestControl(int pageSize, PagedResultsCookie cookie) { this.pageSize = pageSize; this.cookie = cookie; loadControlClasses(); } private void loadControlClasses() { try { requestControlClass = Class.forName(DEFAULT_REQUEST_CONTROL); responseControlClass = Class.forName(DEFAULT_RESPONSE_CONTROL); } catch (ClassNotFoundException e) { log.debug("Default control classes not found - falling back to LdapBP classes", e); try { requestControlClass = Class.forName(LDAPBP_REQUEST_CONTROL); responseControlClass = Class.forName(LDAPBP_RESPONSE_CONTROL); } catch (ClassNotFoundException e1) { throw new UncategorizedLdapException( "Neither default nor fallback classes are available - unable to proceed", e); } } } /** * Get the cookie. * * @return the cookie. */ public PagedResultsCookie getCookie() { return cookie; } /** * Get the page size. * * @return the page size. */ public int getPageSize() { return pageSize; } /** * Get the total estimated number of entries that matches the issued search. * Note that this value is optional for the LDAP server to return, so it * does not always contain any valid data. * * @return the estimated result size, if returned from the server. */ public int getResultSize() { return resultSize; } /** * Set the class of the expected ResponseControl for the paged results * response. * * @param responseControlClass Class of the expected response control. */ public void setResponseControlClass(Class responseControlClass) { this.responseControlClass = responseControlClass; } public void setRequestControlClass(Class requestControlClass) { this.requestControlClass = requestControlClass; } /* * @see * org.springframework.ldap.control.AbstractRequestControlDirContextProcessor * #createRequestControl() */ public Control createRequestControl() { byte[] actualCookie = null; if (cookie != null) { actualCookie = cookie.getCookie(); } Constructor constructor = ClassUtils.getConstructorIfAvailable(requestControlClass, new Class[] { int.class, byte[].class, boolean.class }); if (constructor == null) { throw new IllegalArgumentException("Failed to find an appropriate RequestControl constructor"); } Control result = null; try { result = (Control) constructor.newInstance(new Object[] { new Integer(pageSize), actualCookie, Boolean.valueOf(critical) }); } catch (Exception e) { ReflectionUtils.handleReflectionException(e); } return result; } /* * @see * org.springframework.ldap.core.DirContextProcessor#postProcess(javax.naming * .directory.DirContext) */ public void postProcess(DirContext ctx) throws NamingException { LdapContext ldapContext = (LdapContext) ctx; Control[] responseControls = ldapContext.getResponseControls(); if (responseControls == null) { responseControls = new Control[0]; } // Go through response controls and get info, regardless of class for (int i = 0; i < responseControls.length; i++) { Control responseControl = responseControls[i]; // check for match, try fallback otherwise if (responseControl.getClass().isAssignableFrom(responseControlClass)) { Object control = responseControl; byte[] result = (byte[]) invokeMethod("getCookie", responseControlClass, control); this.cookie = new PagedResultsCookie(result); Integer wrapper = (Integer) invokeMethod("getResultSize", responseControlClass, control); this.resultSize = wrapper.intValue(); return; } } log.fatal("No matching response control found for paged results - looking for '" + responseControlClass); } private Object invokeMethod(String method, Class clazz, Object control) { Method actualMethod = ReflectionUtils.findMethod(clazz, method); return ReflectionUtils.invokeMethod(actualMethod, control); } } ././@LongLink0000000000000000000000000000020500000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/control/PagedResultsCookie.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000420011475313376030205 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.control; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import com.sun.jndi.ldap.ctl.PagedResultsControl; /** * Wrapper class for the cookie returned when using the * {@link PagedResultsControl}. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class PagedResultsCookie { private byte[] cookie; /** * Constructor. * * @param cookie * the cookie returned by a PagedResultsResponseControl. */ public PagedResultsCookie(byte[] cookie) { this.cookie = ArrayUtils.clone(cookie); } /** * Get the cookie. * * @return the cookie. */ public byte[] getCookie() { return ArrayUtils.clone(cookie); } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { if (obj != null && this.getClass().equals(obj.getClass())) { PagedResultsCookie that = (PagedResultsCookie) obj; return new EqualsBuilder().append(this.cookie, that.cookie) .isEquals(); } return false; } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ public int hashCode() { return new HashCodeBuilder().append(this.cookie).toHashCode(); } } ././@LongLink0000000000000000000000000000021700000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/control/CreateControlFailedException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000273011475313376030213 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.control; import org.springframework.ldap.NamingException; /** * Thrown by an AbstractRequestControlDirContextProcessor when it cannot create * a request control. * * @author Ulrik Sandberg * @since 1.2 */ public class CreateControlFailedException extends NamingException { /** * Create a new CreateControlFailedException. * * @param msg * the detail message */ public CreateControlFailedException(String msg) { super(msg); } /** * Create a new CreateControlFailedException. * * @param msg * the detail message * @param cause * the root cause (if any) */ public CreateControlFailedException(String msg, Throwable cause) { super(msg, cause); } } ././@LongLink0000000000000000000000000000022200000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/control/PagedResultsDirContextProcessor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001106011475313376030207 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.control; import javax.naming.ldap.Control; /** * DirContextProcessor implementation for managing the paged results control. * Note that due to the internal workings of LdapTemplate, the * target connection is closed after each LDAP call. The PagedResults control * require the same connection be used for each call, which means we need to * make sure the target connection is never actually closed. There's basically * two ways of making this happen: use the SingleContextSource * implementation or make sure all calls happen within a single LDAP transaction * (using ContextSourceTransactionManager). * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public class PagedResultsDirContextProcessor extends AbstractFallbackRequestAndResponseControlDirContextProcessor { private static final String DEFAULT_REQUEST_CONTROL = "javax.naming.ldap.PagedResultsControl"; private static final String FALLBACK_REQUEST_CONTROL = "com.sun.jndi.ldap.ctl.PagedResultsControl"; private static final String DEFAULT_RESPONSE_CONTROL = "javax.naming.ldap.PagedResultsResponseControl"; private static final String FALLBACK_RESPONSE_CONTROL = "com.sun.jndi.ldap.ctl.PagedResultsResponseControl"; private int pageSize; private PagedResultsCookie cookie; private int resultSize; /** * Constructs a new instance. This constructor should be used when * performing the first paged search operation, when no other results have * been retrieved. * * @param pageSize the page size. */ public PagedResultsDirContextProcessor(int pageSize) { this(pageSize, null); } /** * Constructs a new instance with the supplied page size and cookie. The * cookie must be the exact same instance as received from a previous paged * results search, or null if it is the first in an operation * sequence. * * @param pageSize the page size. * @param cookie the cookie, as received from a previous search. */ public PagedResultsDirContextProcessor(int pageSize, PagedResultsCookie cookie) { this.pageSize = pageSize; this.cookie = cookie; defaultRequestControl = DEFAULT_REQUEST_CONTROL; defaultResponseControl = DEFAULT_RESPONSE_CONTROL; fallbackRequestControl = FALLBACK_REQUEST_CONTROL; fallbackResponseControl = FALLBACK_RESPONSE_CONTROL; loadControlClasses(); } /** * Get the cookie. * * @return the cookie. */ public PagedResultsCookie getCookie() { return cookie; } /** * Get the page size. * * @return the page size. */ public int getPageSize() { return pageSize; } /** * Get the total estimated number of entries that matches the issued search. * Note that this value is optional for the LDAP server to return, so it * does not always contain any valid data. * * @return the estimated result size, if returned from the server. */ public int getResultSize() { return resultSize; } /* * @see * org.springframework.ldap.control.AbstractRequestControlDirContextProcessor * #createRequestControl() */ public Control createRequestControl() { byte[] actualCookie = null; if (cookie != null) { actualCookie = cookie.getCookie(); } return super.createRequestControl(new Class[] { int.class, byte[].class, boolean.class }, new Object[] {new Integer(pageSize), actualCookie, Boolean.valueOf(critical)}); } /* * @seeorg.springframework.ldap.control. * AbstractFallbackRequestAndResponseControlDirContextProcessor * #handleResponse(java.lang.Object) */ protected void handleResponse(Object control) { byte[] result = (byte[]) invokeMethod("getCookie", responseControlClass, control); this.cookie = new PagedResultsCookie(result); Integer wrapper = (Integer) invokeMethod("getResultSize", responseControlClass, control); this.resultSize = wrapper.intValue(); } } ././@LongLink0000000000000000000000000000023400000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/control/AbstractRequestControlDirContextProcessor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001145311475313376030215 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.control; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.ldap.Control; import javax.naming.ldap.LdapContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.core.DirContextProcessor; /** * Abstract superclass with responsibility to apply a single RequestControl on * an LdapContext, preserving any existing controls. Subclasses should implement * {@link DirContextProcessor#postProcess(DirContext)} and template method * {@link #createRequestControl()}. * * @author Mattias Hellborg Arthursson * @author Ulrik Sandberg */ public abstract class AbstractRequestControlDirContextProcessor implements DirContextProcessor { protected Log log = LogFactory.getLog(AbstractRequestControlDirContextProcessor.class); private boolean replaceSameControlEnabled = true; /** * If there already exists a request control of the same class as the one * created by {@link #createRequestControl()} in the context, the new * control can either replace the existing one (default behavior) or be * added. * * @return true if an already existing control will be replaced */ public boolean isReplaceSameControlEnabled() { return replaceSameControlEnabled; } /** * If there already exists a request control of the same class as the one * created by {@link #createRequestControl()} in the context, the new * control can either replace the existing one (default behavior) or be * added. * * @param replaceSameControlEnabled true if an already * existing control should be replaced */ public void setReplaceSameControlEnabled(boolean replaceSameControlEnabled) { this.replaceSameControlEnabled = replaceSameControlEnabled; } /** * Get the existing RequestControls from the LdapContext, call * {@link #createRequestControl()} to get a new instance, build a new array * of Controls and set it on the LdapContext. *

* The {@link Control} feature is specific for LDAP v3 and thus applies only * to {@link LdapContext}. However, the generic DirContextProcessor * mechanism used for calling preProcess and * postProcess uses DirContext, since it also works for LDAP * v2. This is the reason that DirContext has to be cast to a LdapContext. * * @param ctx an LdapContext instance. * @throws NamingException * @throws IllegalArgumentException if the supplied DirContext is not an * LdapContext. */ public void preProcess(DirContext ctx) throws NamingException { LdapContext ldapContext; if (ctx instanceof LdapContext) { ldapContext = (LdapContext) ctx; } else { throw new IllegalArgumentException("Request Control operations require LDAPv3 - " + "Context must be of type LdapContext"); } Control[] requestControls = ldapContext.getRequestControls(); if (requestControls == null) { requestControls = new Control[0]; } Control newControl = createRequestControl(); Control[] newControls = new Control[requestControls.length + 1]; for (int i = 0; i < requestControls.length; i++) { if (replaceSameControlEnabled && requestControls[i].getClass() == newControl.getClass()) { log.debug("Replacing already existing control in context: " + newControl); requestControls[i] = newControl; ldapContext.setRequestControls(requestControls); return; } newControls[i] = requestControls[i]; } // Add the new Control at the end of the array. newControls[newControls.length - 1] = newControl; ldapContext.setRequestControls(newControls); } /** * Create an instance of the appropriate RequestControl. * * @return the new instance. */ public abstract Control createRequestControl(); } ././@LongLink0000000000000000000000000000017000000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/LinkException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000171711475313376030217 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI LinkException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.LinkException */ public class LinkException extends NamingException { public LinkException(javax.naming.LinkException cause) { super(cause); } } ././@LongLink0000000000000000000000000000021600000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/AuthenticationNotSupportedException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000213411475313376030211 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI AuthenticationNotSupportedException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.AuthenticationNotSupportedException */ public class AuthenticationNotSupportedException extends NamingSecurityException { public AuthenticationNotSupportedException( javax.naming.AuthenticationNotSupportedException cause) { super(cause); } } ././@LongLink0000000000000000000000000000021100000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/InsufficientResourcesException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000206211475313376030211 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI InsufficientResourcesException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.InsufficientResourcesException */ public class InsufficientResourcesException extends NamingException { public InsufficientResourcesException( javax.naming.InsufficientResourcesException cause) { super(cause); } } ././@LongLink0000000000000000000000000000021100000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/InvalidAttributeValueException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000210611475313376030210 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI InvalidAttributeValueException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.directory.InvalidAttributeValueException */ public class InvalidAttributeValueException extends NamingException { public InvalidAttributeValueException( javax.naming.directory.InvalidAttributeValueException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020200000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/BadLdapGrammarException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000225611475313376030216 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Thrown to indicate that an invalid value has been supplied to an LDAP * operation. This could be an invalid filter or dn. * * @author Mattias Hellborg Arthursson */ public class BadLdapGrammarException extends NamingException { private static final long serialVersionUID = 961612585331409470L; public BadLdapGrammarException(String message) { super(message); } public BadLdapGrammarException(String message, Throwable cause) { super(message, cause); } } ././@LongLink0000000000000000000000000000020600000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/ServiceUnavailableException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000204311475313376030210 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI ServiceUnavailableException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.ServiceUnavailableException */ public class ServiceUnavailableException extends NamingException { public ServiceUnavailableException( javax.naming.ServiceUnavailableException cause) { super(cause); } } ././@LongLink0000000000000000000000000000021100000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/InvalidSearchControlsException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000210611475313376030210 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI InvalidSearchControlsException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.directory.InvalidSearchControlsException */ public class InvalidSearchControlsException extends NamingException { public InvalidSearchControlsException( javax.naming.directory.InvalidSearchControlsException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/NoPermissionException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000177711475313376030225 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI NoPermissionException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.NoPermissionException */ public class NoPermissionException extends NamingSecurityException { public NoPermissionException(javax.naming.NoPermissionException cause) { super(cause); } } ././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/InvalidNameException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000176211475313376030217 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI InvalidNameException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.InvalidNameException */ public class InvalidNameException extends NamingException { public InvalidNameException(javax.naming.InvalidNameException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020200000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/NamingSecurityException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000201211475313376030204 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI NamingSecurityException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.NamingSecurityException */ public abstract class NamingSecurityException extends NamingException { public NamingSecurityException(javax.naming.NamingSecurityException cause) { super(cause); } } ././@LongLink0000000000000000000000000000017200000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/NamingException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001570511475313376030221 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable; import javax.naming.Name; import org.springframework.core.NestedRuntimeException; /** * Base class for exception thrown by the framework whenever it encounters a * problem related to LDAP. * * @author Ulrik Sandberg * @since 1.2 */ public abstract class NamingException extends NestedRuntimeException { private Throwable cause; /** * Overrides {@link NestedRuntimeException#getCause()} since serialization * always tries to serialize the base class before the subclass. Our * cause may have a resolvedObj that is not * serializable. By storing the cause in this class, we get a chance at * temporarily nulling the cause before serialization, thus in effect making * the current instance serializable. */ public Throwable getCause() { // Even if you cannot set the cause of this exception other than through // the constructor, we check for the cause being "this" here, as the cause // could still be set to "this" via reflection: for example, by a remoting // deserializer like Hessian's. return (this.cause == this ? null : this.cause); } /** * Constructor that takes a message. * * @param msg * the detail message */ public NamingException(String msg) { super(msg); } /** * Constructor that allows a message and a root cause. * * @param msg * the detail message * @param cause * the cause of the exception. This argument is generally * expected to be a proper subclass of * {@link javax.naming.NamingException}. */ public NamingException(String msg, Throwable cause) { super(msg); this.cause = cause; } /** * Constructor that allows a plain root cause, intended for subclasses * mirroring corresponding javax.naming exceptions. * * @param cause * the cause of the exception. This argument is generally * expected to be a proper subclass of * {@link javax.naming.NamingException}. */ public NamingException(Throwable cause) { this(cause != null ? cause.getMessage() : null, cause); } /** * Convenience method to get the explanation associated with this exception, * if the root cause was an instance of {@link javax.naming.NamingException}. * * @return a detail string explaining more about this exception if the root * cause is an instance of javax.naming.NamingException, or * null if there is no detail message for this * exception */ public String getExplanation() { if (getCause() instanceof javax.naming.NamingException) { return ((javax.naming.NamingException) getCause()).getExplanation(); } return null; } /** * Convenience method to get the unresolved part of the name associated with * this exception, if the root cause was an instance of * {@link javax.naming.NamingException}. * * @return a composite name describing the part of the name that has not * been resolved if the root cause is an instance of * javax.naming.NamingException, or null if the * remaining name field has not been set */ public Name getRemainingName() { if (getCause() instanceof javax.naming.NamingException) { return ((javax.naming.NamingException) getCause()) .getRemainingName(); } return null; } /** * Convenience method to get the leading portion of the resolved name * associated with this exception, if the root cause was an instance of * {@link javax.naming.NamingException}. * * @return a composite name describing the the leading portion of the name * that was resolved successfully if the root cause is an instance * of javax.naming.NamingException, or null if the * resolved name field has not been set */ public Name getResolvedName() { if (getCause() instanceof javax.naming.NamingException) { return ((javax.naming.NamingException) getCause()) .getResolvedName(); } return null; } /** * Convenience method to get the resolved object associated with this * exception, if the root cause was an instance of * {@link javax.naming.NamingException}. * * @return the object that was resolved so far if the root cause is an * instance of javax.naming.NamingException, or null * if the resolved object field has not been set */ public Object getResolvedObj() { if (getCause() instanceof javax.naming.NamingException) { return ((javax.naming.NamingException) getCause()).getResolvedObj(); } return null; } /** * Checks if the resolvedObj of the causing exception is * suspected to be non-serializable, and if so temporarily nulls it before * calling the default serialization mechanism. * * @param stream * the stream onto which this object is serialized * @throws IOException * if there is an error writing this object to the stream */ private void writeObject(ObjectOutputStream stream) throws IOException { Object resolvedObj = getResolvedObj(); boolean serializable = resolvedObj instanceof Serializable; if (resolvedObj != null && !serializable) { // the cause is of this type, since resolvedObj is not null javax.naming.NamingException namingException = (javax.naming.NamingException) getCause(); namingException.setResolvedObj(null); try { stream.defaultWriteObject(); } finally { namingException.setResolvedObj(resolvedObj); } } else { stream.defaultWriteObject(); } } } ././@LongLink0000000000000000000000000000020400000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/NameAlreadyBoundException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000203111475313376030205 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI NameAlreadyBoundException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.NameAlreadyBoundException */ public class NameAlreadyBoundException extends NamingException { public NameAlreadyBoundException( javax.naming.NameAlreadyBoundException cause) { super(cause); } } ././@LongLink0000000000000000000000000000021100000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/AttributeModificationException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000210611475313376030210 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI AttributeModificationException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.directory.AttributeModificationException */ public class AttributeModificationException extends NamingException { public AttributeModificationException( javax.naming.directory.AttributeModificationException cause) { super(cause); } } ././@LongLink0000000000000000000000000000017400000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/LinkLoopException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000174111475313376030214 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI LinkLoopException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.LinkLoopException */ public class LinkLoopException extends LinkException { public LinkLoopException(javax.naming.LinkLoopException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020400000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/NoInitialContextException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000203111475313376030205 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI NoInitialContextException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.NoInitialContextException */ public class NoInitialContextException extends NamingException { public NoInitialContextException( javax.naming.NoInitialContextException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/ConfigurationException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000177411475313376030222 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI ConfigurationException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.ConfigurationException */ public class ConfigurationException extends NamingException { public ConfigurationException(javax.naming.ConfigurationException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020300000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/ContextNotEmptyException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000200611475313376030207 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI ContextNotEmptyException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.ContextNotEmptyException */ public class ContextNotEmptyException extends NamingException { public ContextNotEmptyException(javax.naming.ContextNotEmptyException cause) { super(cause); } } ././@LongLink0000000000000000000000000000016500000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/authentication/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0002755000000000000000000000000011475313376030211 5ustar ././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/authentication/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000012211475313376030204 0ustar Support classes for custom authentication. ././@LongLink0000000000000000000000000000024400000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/authentication/DefaultValuesAuthenticationSourceDecorator.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000001213611475313376030214 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.authentication; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.ldap.core.AuthenticationSource; /** * Decorator on AuthenticationSource to have default authentication information * be returned should the target return empty principal and credentials. Useful * in combination with AcegiAuthenticationSource if users are to be * allowed to read some information even though they are not logged in. *

* Note: The defaultUser should be an non-privileged * user. This is important as this is the one that will be used when no user is * logged in (i.e. empty principal is returned from the target * AuthenticationSource). * * @author Mattias Hellborg Arthursson * */ public class DefaultValuesAuthenticationSourceDecorator implements AuthenticationSource, InitializingBean { private AuthenticationSource target; private String defaultUser; private String defaultPassword; /** * Constructor for bean usage. */ public DefaultValuesAuthenticationSourceDecorator() { } /** * Constructor to setup instance directly. * * @param target * the target AuthenticationSource. * @param defaultUser * dn of the user to use when the target returns an empty * principal. * @param defaultPassword * password of the user to use when the target returns an empty * principal. */ public DefaultValuesAuthenticationSourceDecorator( AuthenticationSource target, String defaultUser, String defaultPassword) { this.target = target; this.defaultUser = defaultUser; this.defaultPassword = defaultPassword; } /** * Checks if the target's principal is not empty; if not, the credentials * from the target is returned - otherwise return the * defaultPassword. * * @return the target's password if the target's principal is not empty, the * defaultPassword otherwise. */ public String getCredentials() { if (StringUtils.isNotEmpty(target.getPrincipal())) { return target.getCredentials(); } else { return defaultPassword; } } /** * Checks if the target's principal is not empty; if not, this is returned - * otherwise return the defaultPassword. * * @return the target's principal if it is not empty, the * defaultPassword otherwise. */ public String getPrincipal() { String principal = target.getPrincipal(); if (StringUtils.isNotEmpty(principal)) { return principal; } else { return defaultUser; } } /** * Set the password of the default user. * * @param defaultPassword * the password of the default user. */ public void setDefaultPassword(String defaultPassword) { this.defaultPassword = defaultPassword; } /** * Set the default user DN. This should be a non-privileged user, since it * will be used when no authentication information is returned from the * target. * * @param defaultUser * DN of the default user. */ public void setDefaultUser(String defaultUser) { this.defaultUser = defaultUser; } /** * Set the target AuthenticationSource. * * @param target * the target AuthenticationSource. */ public void setTarget(AuthenticationSource target) { this.target = target; } /* * (non-Javadoc) * * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ public void afterPropertiesSet() throws Exception { if (target == null) { throw new IllegalArgumentException( "Property 'target' must be set.'"); } if (defaultUser == null) { throw new IllegalArgumentException( "Property 'defaultUser' must be set.'"); } if (defaultPassword == null) { throw new IllegalArgumentException( "Property 'defaultPassword' must be set.'"); } } } ././@LongLink0000000000000000000000000000020500000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/InvalidAttributesException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000206211475313376030211 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI InvalidAttributesException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.directory.InvalidAttributesException */ public class InvalidAttributesException extends NamingException { public InvalidAttributesException( javax.naming.directory.InvalidAttributesException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020500000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/InterruptedNamingException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000203611475313376030212 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI InterruptedNamingException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.InterruptedNamingException */ public class InterruptedNamingException extends NamingException { public InterruptedNamingException( javax.naming.InterruptedNamingException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/NameNotFoundException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000211111475313376030204 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI NameNotFoundException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.NameNotFoundException */ public class NameNotFoundException extends NamingException { public NameNotFoundException(String msg) { super(msg); } public NameNotFoundException(javax.naming.NameNotFoundException cause) { super(cause); } } ././@LongLink0000000000000000000000000000021100000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/OperationNotSupportedException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000206211475313376030211 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI OperationNotSupportedException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.OperationNotSupportedException */ public class OperationNotSupportedException extends NamingException { public OperationNotSupportedException( javax.naming.OperationNotSupportedException cause) { super(cause); } } ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0002755000000000000000000000000011475313376030211 5ustar ././@LongLink0000000000000000000000000000017300000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/AndFilter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000330611475313376030213 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; /** * A filter for a logical AND. Example: * *

 *     AndFilter filter = new AndFilter();
 *     filter.and(new EqualsFilter("objectclass", "person");
 *     filter.and(new EqualsFilter("cn", "Some CN");
 *     System.out.println(filter.encode());    
 * 
* * would result in: (&(objectclass=person)(cn=Some CN)) * * @see org.springframework.ldap.filter.EqualsFilter * @author Adam Skogman * @author Mattias Hellborg Arthursson */ public class AndFilter extends BinaryLogicalFilter { private static final String AMPERSAND = "&"; /* * @see org.springframework.ldap.filter.BinaryLogicalFilter#getLogicalOperator() */ protected String getLogicalOperator() { return AMPERSAND; } /** * Add a query to the AND expression. * * @param query The expression to AND with the rest of the AND:ed * expressions. * @return This LdapAndQuery */ public AndFilter and(Filter query) { append(query); return this; } } ././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/AbstractFilter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000253111475313376030212 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; /** * Convenience class that implements most of the methods in the Filter * interface. * * @author Adam Skogman */ public abstract class AbstractFilter implements Filter { protected AbstractFilter() { super(); } /* * @see org.springframework.ldap.filter.Filter#encode(java.lang.StringBuffer) */ public abstract StringBuffer encode(StringBuffer buff); /* * @see org.springframework.ldap.filter.Filter#encode() */ public String encode() { StringBuffer buf = new StringBuffer(256); buf = encode(buf); return buf.toString(); } /* * @see java.lang.Object#toString() */ public String toString() { return encode(); } } ././@LongLink0000000000000000000000000000017300000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/NotFilter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000421111475313376030207 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; import org.apache.commons.lang.Validate; import org.apache.commons.lang.builder.EqualsBuilder; /** * A filter for 'not'. The following code: * *
 * Filter filter = new NotFilter(new EqualsFilter("cn", "foo");
 * System.out.println(filter.encode());
 * 
* * would result in: * *
 * (!(cn = foo))
 * 
* * @author Adam Skogman */ public class NotFilter extends AbstractFilter { private final Filter filter; static private final int HASH = "!".hashCode(); /** * Create a filter that negates the outcome of the given filter. * * @param filter The filter that should be negated. */ public NotFilter(Filter filter) { Validate.notNull(filter); this.filter = filter; } /* * @see org.springframework.ldap.filter.AbstractFilter#encode(java.lang.StringBuffer) */ public StringBuffer encode(StringBuffer buff) { buff.append("(!"); filter.encode(buff); buff.append(')'); return buff; } /* * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object o) { if (o == null) { return false; } if (o == this) { return true; } if (o.getClass() != getClass()) { return false; } NotFilter f = (NotFilter) o; return new EqualsBuilder().append(this.filter, f.filter).isEquals(); } /* * @see java.lang.Object#hashCode() */ public int hashCode() { return HASH ^ filter.hashCode(); } } ././@LongLink0000000000000000000000000000020200000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/NotPresentFilter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000452611475313376030220 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.springframework.ldap.filter.AbstractFilter; /** * A convenience class that combines {@code NOT} behavior with {@code present} * behavior to allow the user to check for the non-existence of a attribute. For * an attribute to be {@code NOT present} it must not have any values set. To * filter on attributes at are {@code present} use the {@link PresentFilter}. * *
 * NotPresentFilter filter = new NotPresentFilter("foo");
 * System.out.println(filter.encode());
 * 
* * would result in: * *
 *  (!(foo=*))
 * 
* @author Jordan Hein */ public class NotPresentFilter extends AbstractFilter { private String attribute; /** * Creates a new instance of a not present filter for a particular * attribute. * * @param attribute the attribute expected to be not-present (ie, unset, or * null). */ public NotPresentFilter(String attribute) { this.attribute = attribute; } public StringBuffer encode(StringBuffer buff) { buff.append("(!("); buff.append(attribute); buff.append("=*))"); return buff; } /* * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object o) { if (o == null) { return false; } if (o == this) { return true; } if (o.getClass() != getClass()) { return false; } NotPresentFilter f = (NotPresentFilter) o; return new EqualsBuilder().append(this.attribute, f.attribute).isEquals(); } /* * @see java.lang.Object#hashCode() */ public int hashCode() { HashCodeBuilder builder = new HashCodeBuilder().append(attribute); return builder.toHashCode(); } }././@LongLink0000000000000000000000000000017200000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/OrFilter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000311011475313376030204 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; /** * Filter for logical OR. * *
 * OrFilter filter = new OrFilter();
 * filter.or(new EqualsFilter("objectclass", "person");
 * filter.or(new EqualsFilter("objectclass", "organizationalUnit");
 * System.out.println(filter.encode());    
 * 
* * would result in: * (|(objectclass=person)(objectclass=organizationalUnit)) * * @author Adam Skogman * @author Mattias Hellborg Arthursson */ public class OrFilter extends BinaryLogicalFilter { private static final String PIPE_SIGN = "|"; /** * Add a query to the OR expression * * @param query The query to or with the rest of the or:ed queries. * @return This LdapOrQuery */ public OrFilter or(Filter query) { append(query); return this; } /* * @see org.springframework.ldap.filter.BinaryLogicalFilter#getLogicalOperator() */ protected String getLogicalOperator() { return PIPE_SIGN; } } ././@LongLink0000000000000000000000000000021300000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/GreaterThanOrEqualsFilter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000304411475313376030212 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; /** * A filter to compare >=. LDAP RFC does not allow > comparison. The following * code: * *
 * GreaterThanOrEqualsFilter filter = new GreaterThanOrEqualsFilter("cn", "Some CN");
 * System.out.println(filter.ecode());
 * 
* * would result in: * *
 * (cn>=Some CN)
 * 
* * @author Mattias Hellborg Arthursson */ public class GreaterThanOrEqualsFilter extends CompareFilter { private static final String GREATER_THAN_OR_EQUALS = ">="; public GreaterThanOrEqualsFilter(String attribute, String value) { super(attribute, value); } public GreaterThanOrEqualsFilter(String attribute, int value) { super(attribute, value); } /* * @see org.springframework.ldap.filter.CompareFilter#getCompareString() */ protected String getCompareString() { return GREATER_THAN_OR_EQUALS; } } ././@LongLink0000000000000000000000000000017100000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000117711475313376030217 0ustar Utility classes for dynamically building LDAP filters. Filters can be nested and wrapped around each other:
AndFilter andFilter = new AndFilter();
andFilter.and(new EqualsFilter("objectclass", "person");
andFilter.and(new EqualsFilter("cn", "Some CN");
OrFilter orFilter = new OrFilter();
orFilter.or(andFilter);
orFilter.or(new EqualsFilter("objectclass", "organizationalUnit));
System.out.println(orFilter.encode());
would result in:
(|(&(objectclass=person)(cn=Some CN))(objectclass=organizationalUnit))
././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/PresentFilter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000445711475313376030223 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; /** * Filter that allows the user to check for the existence of a attribute. For an * attribute to be {@code 'present'} it must contain a value. Attributes that do * not contain a value are {@code 'NOT present'}. To filter on attributes that * are {@code 'NOT present'} use the {@link NotPresentFilter} or use this filter * in combination with a {@link NotFilter} . * *
 * PresentFilter filter = new PresentFilter("foo");
 * System.out.println(filter.encode());
 * 
* * would result in: * *
 *  (foo=*)
 * 
* @author Jordan Hein */ public class PresentFilter extends AbstractFilter { private String attribute; /** * Creates a new instance of a present filter for a particular attribute. * * @param attribute the attribute expected to be present (ie, contains a * value). */ public PresentFilter(String attribute) { this.attribute = attribute; } public StringBuffer encode(StringBuffer buff) { buff.append("("); buff.append(attribute); buff.append("=*)"); return buff; } /* * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object o) { if (o == null) { return false; } if (o == this) { return true; } if (o.getClass() != getClass()) { return false; } PresentFilter f = (PresentFilter) o; return new EqualsBuilder().append(this.attribute, f.attribute).isEquals(); } /* * @see java.lang.Object#hashCode() */ public int hashCode() { HashCodeBuilder builder = new HashCodeBuilder().append(attribute); return builder.toHashCode(); } }././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/HardcodedFilter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000563311475313376030220 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.springframework.util.StringUtils; /** * Allows hard coded parts to be included in a search filter. Particularly useful * if some filters are specified in configuration files and these should be * combined with other ones. * *
 * Filter filter = new HardcodedFilter("(&(objectClass=user)(!(objectClass=computer)))");
 * System.out.println(filter.toString());
 * 
* * would result in: * (&(objectClass=user)(!(objectClass=computer))) *

* Note 1: If the definition is in XML you will need to properly encode any special characters so that they are valid in an XML file, * e.g. "&" needs to be encoded as "&amp;", e.g. *

 * <bean class="MyClass">
 *   <property name="filter" value="(&amp;(objectClass=user)(!(objectClass=computer)))" />
 * </bean>
 * 
*

*

* Note 2: There will be no validation to ensure that the supplied filter is * valid. Using this implementation to build filters from user input is strongly * discouraged. *

* @author Justen Stepka * @author Mathieu Larchet */ public class HardcodedFilter extends AbstractFilter { private String filter; /** * The hardcoded string to be used for this filter. * @param filter the hardcoded filter string. */ public HardcodedFilter(String filter) { this.filter = filter; } /* * (non-Javadoc) * @see org.springframework.ldap.filter.AbstractFilter#encode(java.lang.StringBuffer) */ public StringBuffer encode(StringBuffer buff) { if (!StringUtils.hasLength(filter)) { return buff; } buff.append(filter); return buff; } /* * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object o) { if (o == null) { return false; } if (o == this) { return true; } if (o.getClass() != getClass()) { return false; } HardcodedFilter f = (HardcodedFilter) o; return new EqualsBuilder().append(this.filter, f.filter).isEquals(); } /* * @see java.lang.Object#hashCode() */ public int hashCode() { HashCodeBuilder builder = new HashCodeBuilder().append(filter); return builder.toHashCode(); } } ././@LongLink0000000000000000000000000000017600000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/FilterEditor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000176311475313376030220 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; import java.beans.PropertyEditorSupport; /** * Property editor for {@link Filter} instances. Creates {@link HardcodedFilter} * instances. * * @author Mathieu Larchet */ public class FilterEditor extends PropertyEditorSupport { public void setAsText(String text) throws IllegalArgumentException { setValue(new HardcodedFilter(text)); } } ././@LongLink0000000000000000000000000000021300000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/WhitespaceWildcardsFilter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000441511475313376030215 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.springframework.ldap.core.LdapEncoder; /** * This filter automatically converts all whitespace to wildcards (*). The * following code: * *
 * WhitespaceWildcardsFilter filter = new WhitespaceWildcardsFilter("cn", "Some CN");
 * System.out.println(filter.ecode());
 * 
* * would result in: (cn=*Some*CN*) * * @author Adam Skogman * @author Mattias Hellborg Arthursson */ public class WhitespaceWildcardsFilter extends EqualsFilter { private static Pattern starReplacePattern = Pattern.compile("\\s+"); public WhitespaceWildcardsFilter(String attribute, String value) { super(attribute, value); } /* * @see org.springframework.ldap.filter.CompareFilter#encodeValue(java.lang.String) */ protected String encodeValue(String value) { // blank string means just ONE star if (StringUtils.isBlank(value)) { return "*"; } // trim value, we will add in stars first and last anywhay value = value.trim(); // filter encode so that any stars etc. are preserved String filterEncoded = LdapEncoder.filterEncode(value); // Now replace all whitespace with stars Matcher m = starReplacePattern.matcher(filterEncoded); // possibly 2 longer (stars at ends) StringBuffer buff = new StringBuffer(value.length() + 2); buff.append('*'); while (m.find()) { m.appendReplacement(buff, "*"); } m.appendTail(buff); buff.append('*'); return buff.toString(); } } ././@LongLink0000000000000000000000000000021000000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/LessThanOrEqualsFilter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000301711475313376030212 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; /** * A filter to compare <=. LDAP RFC does not allow < comparison. The following * code: * *
 * LessThanOrEqualsFilter filter = new LessThanOrEqualsFilter("cn", "Some CN");
 * System.out.println(filter.ecode());
 * 
* * would result in: * *
 * (cn<=Some CN)
 * 
* * @author Mattias Hellborg Arthursson */ public class LessThanOrEqualsFilter extends CompareFilter { private static final String LESS_THAN_OR_EQUALS = "<="; public LessThanOrEqualsFilter(String attribute, String value) { super(attribute, value); } public LessThanOrEqualsFilter(String attribute, int value) { super(attribute, value); } /* * @see org.springframework.ldap.filter.CompareFilter#getCompareString() */ protected String getCompareString() { return LESS_THAN_OR_EQUALS; } } ././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/CompareFilter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000667211475313376030224 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.springframework.ldap.core.LdapEncoder; /** * Abstract superclass for filters that compare values. * * @author Mattias Hellborg Arthursson */ public abstract class CompareFilter extends AbstractFilter { private final String attribute; private final String value; private final String encodedValue; public CompareFilter(String attribute, String value) { this.attribute = attribute; this.value = value; this.encodedValue = encodeValue(value); } /** * For testing purposes. * * @return the encoded value. */ String getEncodedValue() { return encodedValue; } /** * Override to perform special encoding in subclass. * * @param value the value to encode. * @return properly escaped value. */ protected String encodeValue(String value) { return LdapEncoder.filterEncode(value); } /** * Convenience constructor for int values. * * @param attribute Name of attribute in filter. * @param value The value of the attribute in the filter. */ public CompareFilter(String attribute, int value) { this.attribute = attribute; this.value = String.valueOf(value); this.encodedValue = LdapEncoder.filterEncode(this.value); } /* * @see org.springframework.ldap.filter.AbstractFilter#encode(java.lang.StringBuffer) */ public StringBuffer encode(StringBuffer buff) { buff.append('('); buff.append(attribute).append(getCompareString()).append(encodedValue); buff.append(')'); return buff; } /** * Compares key and value before encoding. * * @see org.springframework.ldap.filter.Filter#equals(java.lang.Object) */ public boolean equals(Object o) { if (o == null) { return false; } if (o == this) { return true; } if (o.getClass() != getClass()) { return false; } CompareFilter f = (CompareFilter) o; EqualsBuilder builder = new EqualsBuilder(); return builder.append(this.attribute, f.attribute).append(this.value, f.value).isEquals(); } /** * Calculate the hash code for the attribute and the value. * * @see org.springframework.ldap.filter.Filter#hashCode() */ public int hashCode() { HashCodeBuilder builder = new HashCodeBuilder(); builder.append(attribute); builder.append(value); return builder.toHashCode(); } /** * Implement this method in subclass to return a String representing the * operator. The {@link EqualsFilter#getCompareString()} would for example * return an equals sign, "=". * * @return the String to use as operator in the comparison for the specific * subclass. */ protected abstract String getCompareString(); } ././@LongLink0000000000000000000000000000017600000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/EqualsFilter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000307511475313376030216 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; /** * A filter for 'equals'. The following code: * *
 * EqualsFilter filter = new EqualsFilter("cn", "Some CN");
 * System.out.println(filter.encode());
 * 
* * would result in: * *
 * (cn=Some CN)
 * 
* * @author Adam Skogman */ public class EqualsFilter extends CompareFilter { private static final String EQUALS_SIGN = "="; public EqualsFilter(String attribute, String value) { super(attribute, value); } /** * Convenience constructor for int values. * * @param attribute Name of attribute in filter. * @param value The value of the attribute in the filter. */ public EqualsFilter(String attribute, int value) { super(attribute, value); } /* * @see org.springframework.ldap.filter.CompareFilter#getCompareString() */ protected String getCompareString() { return EQUALS_SIGN; } } ././@LongLink0000000000000000000000000000017400000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/LikeFilter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000367211475313376030221 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; import org.springframework.ldap.core.LdapEncoder; /** * This filter allows the user to specify wildcards (*) by not escaping them in * the filter. The following code: * *
 * LikeFilter filter = new LikeFilter("cn", "foo*");
 * System.out.println(filter.ecode());
 * 
* * would result in: * *
 *  (cn=foo*)
 * 
* * @author Anders Henja * @author Mattias Hellborg Arthursson */ public class LikeFilter extends EqualsFilter { public LikeFilter(String attribute, String value) { super(attribute, value); } /* * @see org.springframework.ldap.filter.CompareFilter#encodeValue(java.lang.String) */ protected String encodeValue(String value) { // just return if blank string if (value == null) { return ""; } String[] substrings = value.split("\\*", -2); if (substrings.length == 1) { return LdapEncoder.filterEncode(substrings[0]); } StringBuffer buff = new StringBuffer(); for (int i = 0; i < substrings.length; i++) { buff.append(LdapEncoder.filterEncode(substrings[i])); if (i < substrings.length - 1) { buff.append("*"); } else { if (substrings[i].equals("")) { continue; } } } return buff.toString(); } } ././@LongLink0000000000000000000000000000020500000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/BinaryLogicalFilter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000536211475313376030217 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; /** * Abstract superclass for binary logical operations, that is "AND" * and "OR" operations. * * @author Mattias Hellborg Arthursson */ public abstract class BinaryLogicalFilter extends AbstractFilter { protected List queryList = new LinkedList(); /* * @see * org.springframework.ldap.filter.AbstractFilter#encode(java.lang.StringBuffer * ) */ public StringBuffer encode(StringBuffer buff) { if (queryList.size() <= 0) { // only output query if contains anything return buff; } else if (queryList.size() == 1) { // don't add the & Filter query = (Filter) queryList.get(0); return query.encode(buff); } else { buff.append("(" + getLogicalOperator()); for (Iterator i = queryList.iterator(); i.hasNext();) { Filter query = (Filter) i.next(); buff = query.encode(buff); } buff.append(")"); return buff; } } /** * Implement this in subclass to return the logical operator, for example * &qout;&&qout;. * * @return the logical operator. */ protected abstract String getLogicalOperator(); /** * Compares each filter in turn. * * @see org.springframework.ldap.filter.Filter#equals(java.lang.Object) */ public boolean equals(Object obj) { if (obj instanceof BinaryLogicalFilter && this.getClass() == obj.getClass()) { return EqualsBuilder.reflectionEquals(this, obj); } else { return false; } } /** * Hashes all contained data. * * @see org.springframework.ldap.filter.Filter#hashCode() */ public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } /** * Add a query to this logical operation. * * @param query the query to add. * @return This instance. */ public final BinaryLogicalFilter append(Filter query) { queryList.add(query); return this; } } ././@LongLink0000000000000000000000000000017000000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/filter/Filter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000305711475313376030216 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.filter; /** * Common interface for LDAP filters. * * @author Adam Skogman * @see RFC 1960: A String * Representation of LDAP Search Filters< /a> */ public interface Filter { /** * Encodes the filter to a String. * * @return The encoded filter in the standard String format */ String encode(); /** * Encodes the filter to a StringBuffer. * * @param buf The StringBuffer to encode the filter to * @return The same StringBuffer as was given */ StringBuffer encode(StringBuffer buf); /** * All filters must implement equals. * * @param o * @return true if the objects are equal. */ boolean equals(Object o); /** * All filters must implement hashCode. * * @return the hash code according to the contract in * {@link Object#hashCode()} */ int hashCode(); }././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/PartialResultException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000177411475313376030222 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI PartialResultException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.PartialResultException */ public class PartialResultException extends NamingException { public PartialResultException(javax.naming.PartialResultException cause) { super(cause); } } ././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/MalformedLinkException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000177211475313376030220 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI MalformedLinkException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.MalformedLinkException */ public class MalformedLinkException extends LinkException { public MalformedLinkException(javax.naming.MalformedLinkException cause) { super(cause); } } ././@LongLink0000000000000000000000000000017400000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap/ReferralException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/ldap0000644000000000000000000000175411475313376030220 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap; /** * Runtime exception mirroring the JNDI ReferralException. * * @author Ulrik Sandberg * @since 1.2 * @see javax.naming.ReferralException */ public abstract class ReferralException extends NamingException { public ReferralException(javax.naming.ReferralException cause) { super(cause); } } ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/transaction/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/tran0002755000000000000000000000000011475313376030235 5ustar ././@LongLink0000000000000000000000000000017200000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/transaction/compensating/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/tran0002755000000000000000000000000011475313376030235 5ustar ././@LongLink0000000000000000000000000000024700000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/transaction/compensating/CompensatingTransactionOperationRecorder.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/tran0000644000000000000000000000330311475313376030234 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.transaction.compensating; /** * An implementation of this interface is responsible for recording data and * supplying a {@link CompensatingTransactionOperationExecutor} to be invoked * for execution and compensating transaction management of the operation. * Recording of an operation should not fail (throwing an Exception), but * instead log the result. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public interface CompensatingTransactionOperationRecorder { /** * Record information about the operation performed and return a * corresponding {@link CompensatingTransactionOperationExecutor} to be used * if the operation would need to be rolled back. * * @param args * The arguments that have been sent to the operation. * @return A {@link CompensatingTransactionOperationExecutor} to be used if * the recorded operation should need to be rolled back. */ CompensatingTransactionOperationExecutor recordOperation( Object[] args); } ././@LongLink0000000000000000000000000000024600000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/transaction/compensating/CompensatingTransactionOperationManager.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/tran0000644000000000000000000000403411475313376030236 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.transaction.compensating; /** * A CompensatingTransactionOperationManager implementation records and performs * operations that are to be performed within a compensating transaction. It * keeps track of compensating actions necessary for rolling back each * individual operation. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public interface CompensatingTransactionOperationManager { /** * Indicates that the supplied operation (method name) is to be performed. * This method is responsible for recording the current state (prior to the * operation), performing the operation, and storing the necessary * information to roll back or commit the performed operation. * * @param resource * the target resource to perform the operation on. * @param operation * The method to be invoked. * @param args * Arguments supplied to the method. */ void performOperation(Object resource, String operation, Object[] args); /** * Rollback all recorded operations by performing each of the recorded * rollback operations. */ void rollback(); /** * Commit all recorded operations. In many cases this means doing nothing, * but in some cases some temporary data will need to be removed. */ void commit(); } ././@LongLink0000000000000000000000000000020200000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/transaction/compensating/support/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/tran0002755000000000000000000000000011475313376030235 5ustar ././@LongLink0000000000000000000000000000025300000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/transaction/compensating/support/CompensatingTransactionHolderSupport.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/tran0000644000000000000000000000526511475313376030245 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.transaction.compensating.support; import org.springframework.transaction.compensating.CompensatingTransactionOperationManager; import org.springframework.transaction.support.ResourceHolderSupport; /** * Base class for compensating transaction resource holders. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public abstract class CompensatingTransactionHolderSupport extends ResourceHolderSupport { private CompensatingTransactionOperationManager transactionOperationManager; /** * Constructor. * * @param manager * The {@link CompensatingTransactionOperationManager} to use for * creating Compensating operations. */ public CompensatingTransactionHolderSupport( CompensatingTransactionOperationManager manager) { this.transactionOperationManager = manager; } /** * Get the actual transacted resource. * * @return the transaction's target resource */ protected abstract Object getTransactedResource(); /* * @see org.springframework.transaction.support.ResourceHolderSupport#clear() */ public void clear() { super.clear(); transactionOperationManager = null; } /** * Get the CompensatingTransactionOperationManager to handle the data for * the current transaction. * * @return the CompensatingTransactionOperationManager. */ public CompensatingTransactionOperationManager getTransactionOperationManager() { return transactionOperationManager; } /** * Set the CompensatingTransactionOperationManager. For testing purposes * only. * * @param transactionOperationManager * the CompensatingTransactionOperationManager to use. */ public void setTransactionOperationManager( CompensatingTransactionOperationManager transactionOperationManager) { this.transactionOperationManager = transactionOperationManager; } }././@LongLink0000000000000000000000000000021600000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/transaction/compensating/support/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/tran0000644000000000000000000000030011475313376030226 0ustar Support package for general Compensating Transaction Framework. Contains default implementations of core interfaces as well as useful helper classes. ././@LongLink0000000000000000000000000000026500000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/transaction/compensating/support/AbstractCompensatingTransactionManagerDelegate.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/tran0000644000000000000000000001226111475313376030237 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.transaction.compensating.support; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.transaction.CannotCreateTransactionException; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.support.DefaultTransactionStatus; import org.springframework.transaction.support.TransactionSynchronizationManager; /** * Abstract superclass for Compensating TransactionManager delegates. The actual * transaction work is extracted to a delegate to enable composite Transaction * Managers. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public abstract class AbstractCompensatingTransactionManagerDelegate { private static Log log = LogFactory.getLog(AbstractCompensatingTransactionManagerDelegate.class); /** * Close the target resource - the implementation specific resource held in * the specified {@link CompensatingTransactionHolderSupport}. * * @param transactionHolderSupport the * {@link CompensatingTransactionHolderSupport} that holds the transaction * specific target resource. */ protected abstract void closeTargetResource(CompensatingTransactionHolderSupport transactionHolderSupport); /** * Get a new implementation specific * {@link CompensatingTransactionHolderSupport} instance. * * @return a new {@link CompensatingTransactionHolderSupport} instance. */ protected abstract CompensatingTransactionHolderSupport getNewHolder(); /** * Get the key (normally, a DataSource or similar) that should be used for * transaction synchronization. * * @return the transaction synchronization key */ protected abstract Object getTransactionSynchronizationKey(); /* * @seeorg.springframework.jdbc.datasource.DataSourceTransactionManager# * doGetTransaction() */ public Object doGetTransaction() throws TransactionException { CompensatingTransactionHolderSupport holder = (CompensatingTransactionHolderSupport) TransactionSynchronizationManager .getResource(getTransactionSynchronizationKey()); CompensatingTransactionObject txObject = new CompensatingTransactionObject(holder); return txObject; } /* * @see * org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin * (java.lang.Object, org.springframework.transaction.TransactionDefinition) */ public void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException { try { CompensatingTransactionObject txObject = (CompensatingTransactionObject) transaction; if (txObject.getHolder() == null) { CompensatingTransactionHolderSupport contextHolder = getNewHolder(); txObject.setHolder(contextHolder); TransactionSynchronizationManager.bindResource(getTransactionSynchronizationKey(), contextHolder); } } catch (Exception e) { throw new CannotCreateTransactionException("Could not create DirContext instance for transaction", e); } } /* * @see * org.springframework.jdbc.datasource.DataSourceTransactionManager#doCommit * (org.springframework.transaction.support.DefaultTransactionStatus) */ public void doCommit(DefaultTransactionStatus status) throws TransactionException { CompensatingTransactionObject txObject = (CompensatingTransactionObject) status.getTransaction(); txObject.getHolder().getTransactionOperationManager().commit(); } /* * @see * org.springframework.jdbc.datasource.DataSourceTransactionManager#doRollback * (org.springframework.transaction.support.DefaultTransactionStatus) */ public void doRollback(DefaultTransactionStatus status) throws TransactionException { CompensatingTransactionObject txObject = (CompensatingTransactionObject) status.getTransaction(); txObject.getHolder().getTransactionOperationManager().rollback(); } /* * @seeorg.springframework.jdbc.datasource.DataSourceTransactionManager# * doCleanupAfterCompletion(java.lang.Object) */ public void doCleanupAfterCompletion(Object transaction) { log.debug("Cleaning stored transaction synchronization"); TransactionSynchronizationManager.unbindResource(getTransactionSynchronizationKey()); CompensatingTransactionObject txObject = (CompensatingTransactionObject) transaction; CompensatingTransactionHolderSupport transactionHolderSupport = (CompensatingTransactionHolderSupport) txObject .getHolder(); closeTargetResource(transactionHolderSupport); txObject.getHolder().clear(); } }././@LongLink0000000000000000000000000000024300000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/transaction/compensating/support/CompensatingTransactionUtils.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/tran0000644000000000000000000000571611475313376030246 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.transaction.compensating.support; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.springframework.transaction.compensating.CompensatingTransactionOperationManager; import org.springframework.transaction.support.TransactionSynchronizationManager; /** * Common methods for use with compensating transactions. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class CompensatingTransactionUtils { /** * Not to be instantiated. */ private CompensatingTransactionUtils() { } /** * Perform the specified operation, storing the state prior to the operation * in order to enable commit/rollback later. If no transaction is currently * active, proceed with the original call on the target. * * @param synchronizationKey * the transaction synchronization key we are operating on * (typically something similar to a DataSource). * @param target * the actual target resource that should be used for invoking * the operation on should no transaction be active. * @param method * name of the method to be invoked. * @param args * arguments with which the operation is invoked. */ public static void performOperation(Object synchronizationKey, Object target, Method method, Object[] args) throws Throwable { CompensatingTransactionHolderSupport transactionResourceHolder = (CompensatingTransactionHolderSupport) TransactionSynchronizationManager .getResource(synchronizationKey); if (transactionResourceHolder != null) { CompensatingTransactionOperationManager transactionOperationManager = transactionResourceHolder .getTransactionOperationManager(); transactionOperationManager.performOperation( transactionResourceHolder.getTransactedResource(), method .getName(), args); } else { // Perform the target operation try { method.invoke(target, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } } } } ././@LongLink0000000000000000000000000000026500000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/transaction/compensating/support/DefaultCompensatingTransactionOperationManager.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/tran0000644000000000000000000001153511475313376030242 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.transaction.compensating.support; import java.util.Iterator; import java.util.Stack; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.transaction.TransactionSystemException; import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor; import org.springframework.transaction.compensating.CompensatingTransactionOperationFactory; import org.springframework.transaction.compensating.CompensatingTransactionOperationManager; import org.springframework.transaction.compensating.CompensatingTransactionOperationRecorder; /** * Default implementation of {@link CompensatingTransactionOperationManager}. * Manages a stack of {@link CompensatingTransactionOperationExecutor} objects * and performs rollback of these in the reverse order. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class DefaultCompensatingTransactionOperationManager implements CompensatingTransactionOperationManager { private static Log log = LogFactory .getLog(DefaultCompensatingTransactionOperationManager.class); private Stack operationExecutors = new Stack(); private CompensatingTransactionOperationFactory operationFactory; /** * Set the {@link CompensatingTransactionOperationFactory} to use. * * @param operationFactory * the {@link CompensatingTransactionOperationFactory}. */ public DefaultCompensatingTransactionOperationManager( CompensatingTransactionOperationFactory operationFactory) { this.operationFactory = operationFactory; } /* * @see org.springframework.transaction.compensating.CompensatingTransactionOperationManager#performOperation(java.lang.Object, * java.lang.String, java.lang.Object[]) */ public void performOperation(Object resource, String operation, Object[] args) { CompensatingTransactionOperationRecorder recorder = operationFactory .createRecordingOperation(resource, operation); CompensatingTransactionOperationExecutor executor = recorder .recordOperation(args); executor.performOperation(); // Don't push the executor until the actual operation passed. operationExecutors.push(executor); } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationManager#rollback() */ public void rollback() { log.debug("Performing rollback"); while (!operationExecutors.isEmpty()) { CompensatingTransactionOperationExecutor rollbackOperation = (CompensatingTransactionOperationExecutor) operationExecutors .pop(); try { rollbackOperation.rollback(); } catch (Exception e) { throw new TransactionSystemException( "Error occurred during rollback", e); } } } /** * Get the rollback operations. Used for testing purposes. * * @return the rollback operations. */ protected Stack getOperationExecutors() { return operationExecutors; } /** * Set the rollback operations. Package protected - for testing purposes * only. * * @param operationExecutors * the rollback operations. */ void setOperationExecutors(Stack operationExecutors) { this.operationExecutors = operationExecutors; } /* * @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationManager#commit() */ public void commit() { log.debug("Performing commit"); for (Iterator iter = operationExecutors.iterator(); iter.hasNext();) { CompensatingTransactionOperationExecutor operationExecutor = (CompensatingTransactionOperationExecutor) iter .next(); try { operationExecutor.commit(); } catch (Exception e) { throw new TransactionSystemException( "Error occurred during commit", e); } } } } ././@LongLink0000000000000000000000000000024400000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/transaction/compensating/support/CompensatingTransactionObject.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/tran0000644000000000000000000000374711475313376030250 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.transaction.compensating.support; /** * Transaction object used by * {@link AbstractCompensatingTransactionManagerDelegate}. Keeps a reference to * the {@link CompensatingTransactionHolderSupport} associated with the current * transaction. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public class CompensatingTransactionObject { private CompensatingTransactionHolderSupport holder; /** * Constructor. * * @param holder * the {@link CompensatingTransactionHolderSupport} associated * with the current transaction. */ public CompensatingTransactionObject( CompensatingTransactionHolderSupport holder) { this.holder = holder; } /** * Get the DirContextHolder. * * @return the DirContextHolder. */ public CompensatingTransactionHolderSupport getHolder() { return holder; } /** * Set the {@link CompensatingTransactionHolderSupport} associated with the * current transaction. * * @param holder * the {@link CompensatingTransactionHolderSupport} associated * with the current transaction. */ public void setHolder(CompensatingTransactionHolderSupport holder) { this.holder = holder; } }././@LongLink0000000000000000000000000000020600000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/transaction/compensating/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/tran0000644000000000000000000000022411475313376030233 0ustar Interface definitions for a general Compensating Transaction framework based on PlatformTransactionManager. ././@LongLink0000000000000000000000000000024600000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/transaction/compensating/CompensatingTransactionOperationFactory.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/tran0000644000000000000000000000326611475313376030244 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.transaction.compensating; import org.springframework.transaction.compensating.support.DefaultCompensatingTransactionOperationManager; /** * Factory interface for creating * {@link CompensatingTransactionOperationRecorder} objects based on operation * method names. * * @author Mattias Hellborg Arthursson * @see DefaultCompensatingTransactionOperationManager * @since 1.2 */ public interface CompensatingTransactionOperationFactory { /** * Create an appropriate {@link CompensatingTransactionOperationRecorder} * instance corresponding to the supplied method name. * * @param resource * The target transaction resource. * @param method * the method name to create a * {@link CompensatingTransactionOperationRecorder} for. * * @return a new {@link CompensatingTransactionOperationRecorder} instance. */ CompensatingTransactionOperationRecorder createRecordingOperation( Object resource, String method); } ././@LongLink0000000000000000000000000000024700000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/transaction/compensating/CompensatingTransactionOperationExecutor.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core/org/springframework/tran0000644000000000000000000000524511475313376030243 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.transaction.compensating; /** * Responsible for executing a single recorded operation as well as committing * or rolling it back, depending on the transaction outcome. Instances of this * interface are constructed by {@link CompensatingTransactionOperationRecorder} * objects, supplying them with the information necessary for the respective * operations. *

* The actual operations performed by the respective methods of this class might * not be what would originally be expected. E.g. one would expect that the * {@link #performOperation()} method of a * CompensatingTransactionOperationExecutor implementation would actually delete * the entry, leaving it for the {@link #rollback()} method to recreate it using * data from the original entry. However, this will not always be possible. In * an LDAP system, for instance, it might not be possible to retrieve all the * stored data from the original entry. In that case, the * {@link #performOperation()} method will instead move the entry to a temporary * location and leave it for the {@link #commit()} method to actually remove the * entry. * * @author Mattias Hellborg Arthursson * @since 1.2 */ public interface CompensatingTransactionOperationExecutor { /** * Rollback the operation, restoring state of the target as it was before * the operation was performed using the information supplied on creation of * this instance. */ void rollback(); /** * Commit the operation. In many cases, this will not require any work at * all to be performed. However, in some cases there will be interesting * stuff to do. See class description for elaboration on this. */ void commit(); /** * Perform the operation. This will most often require performing the * recorded operation, but in some cases the actual operation performed by * this method might be something else. See class description for * elaboration on this. */ void performOperation(); } libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/0002755000000000000000000000000011475313400024241 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/overview.html0000644000000000000000000000101211475313400026765 0ustar Insert title here This document is the API specification for the Spring LDAP LDIF Parser and its associated utilities.

This series of packages provides an LDIF parser utility compliant with "RFC 2849 : The LDAP Data Interchange Format (LDIF) - Technical Specification". libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/0002755000000000000000000000000011475313400025030 5ustar ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0002755000000000000000000000000011475313400030171 5ustar ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0002755000000000000000000000000011475313400030171 5ustar ././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/core/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0002755000000000000000000000000011475313400030171 5ustar ././@LongLink0000000000000000000000000000020200000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/core/LdapAttribute.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000001520311475313400030172 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import java.util.Collection; import java.util.HashSet; import java.util.Set; import javax.naming.directory.BasicAttribute; /** * Extends {@link javax.naming.directory.BasicAttribute} to add support for * options as defined in RFC2849. *

* While uncommon, options can be used to specify additional descriptors for * the attribute. Options are backed by a {@link java.util.HashSet} of * {@link java.lang.String}. * * @author Keith Barlow * */ public class LdapAttribute extends BasicAttribute { private static final long serialVersionUID = -5263905906016179429L; /** * Holds the attributes options. */ protected Set options = new HashSet(); /** * Creates an unordered attribute with the specified ID. * * @param id {@link java.lang.String} ID of the attribute. */ public LdapAttribute(String id) { super(id); } /** * Creates an unordered attribute with the specified ID and value. * * @param id {@link java.lang.String} ID of the attribute. * @param value Attribute value. */ public LdapAttribute(String id, Object value) { super(id, value); } /** * Creates an unordered attribute with the specified ID, value, and options. * * @param id {@link java.lang.String} ID of the attribute. * @param value Attribute value. * @param options {@link java.util.Collection} of {@link java.lang.String} attribute options. */ public LdapAttribute(String id, Object value, Collection options) { super(id, value); this.options.addAll(options); } /** * Creates an attribute with the specified ID whose values may be ordered. * * @param id {@link java.lang.String} ID of the attribute. * @param ordered boolean indicating whether or not the attributes values are ordered. */ public LdapAttribute(String id, boolean ordered) { super(id, ordered); } /** * Creates an attribute with the specified ID and options whose values may be ordered. * * @param id {@link java.lang.String} ID of the attribute. * @param options {@link java.util.Collection} of {@link java.lang.String} attribute options. * @param ordered boolean indicating whether or not the attributes values are ordered. */ public LdapAttribute(String id, Collection options, boolean ordered) { super(id, ordered); this.options.addAll(options); } /** * Creates an attribute with the specified ID and value whose values may be ordered. * * @param id {@link java.lang.String} ID of the attribute. * @param value Attribute value. * @param ordered boolean indicating whether or not the attributes values are ordered. */ public LdapAttribute(String id, Object value, boolean ordered) { super(id, value, ordered); } /** * Creates an attribute with the specified ID, value, and options whose values may be ordered. * * @param id {@link java.lang.String} ID of the attribute. * @param value Attribute value. * @param options {@link java.util.Collection} of {@link java.lang.String} attribute options. * @param ordered boolean indicating whether or not the attributes values are ordered. */ public LdapAttribute(String id, Object value, Collection options, boolean ordered) { super(id, value, ordered); this.options.addAll(options); } /** * Get options. * * @return returns a {@link java.util.Set} of {@link java.lang.String} */ public Set getOptions() { return this.options; } /** * Set options. * * @param options {@link java.util.Set} of {@link java.lang.String} */ public void setOptions(Set options) { this.options = options; } /** * Add an option. * * @param option {@link java.lang.String} option. * @return boolean indication successful addition of option. */ public boolean addOption(String option) { return this.options.add(option); } /** * Add all values in the collection to the options. * * @param options {@link java.util.Collection} of {@link java.lang.String} values. * @return boolean indication successful addition of options. */ public boolean addAllOptions(Collection options) { return this.options.addAll(options); } /** * Clears all stored options. */ public void clearOptions() { this.options.clear(); } /** * Checks for existence of a particular option on the set. * * @param option {@link java.lang.String} option. * @return boolean indicating result. */ public boolean contains(String option) { return this.options.contains(option); } /** * Checks for existence of a series of options on the set. * * @param options {@link java.util.Collection} of {@link java.lang.String} options. * @return boolean indicating result. */ public boolean containsAll(Collection options) { return this.options.containsAll(options); } /** * Tests for the presence of options. * * @return boolean indicating result. */ public boolean hasOptions() { return !options.isEmpty(); } /** * Removes an option from the the set. * * @param option {@link java.lang.String} option. * @return boolean indicating successful removal of option. */ public boolean removeOption(String option) { return this.options.remove(options); } /** * Removes all options listed in the supplied set. * * @param options {@link java.util.Collection} of {@link java.lang.String} options. * @return boolean indicating successful removal of options. */ public boolean removeAllOptions(Collection options) { return this.options.removeAll(options); } /** * Removes any options not on the set of supplied options. * * @param options {@link java.util.Collection} of {@link java.lang.String} options. * @return boolean indicating successful retention of options. */ public boolean retainAllOptions(Collection options) { return this.options.retainAll(options); } } ././@LongLink0000000000000000000000000000020300000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/core/LdapAttributes.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000001514211475313400030174 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core; import java.net.URI; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.BasicAttributes; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.core.DistinguishedName; import sun.misc.BASE64Encoder; /** * Extends {@link javax.naming.directory.BasicAttributes} to add specialized support * for DNs. *

* While DNs appear to be and can be treated as attributes, they have a special * meaning in that they define the address to which the object is bound. DNs must * conform to special formating rules and are typically required to be handled * separately from other attributes. *

* This class makes this distinction between the DN and other * attributes prominent and apparent. * * @author Keith Barlow * */ public class LdapAttributes extends BasicAttributes { private static final long serialVersionUID = 97903297123869138L; private static Log log = LogFactory.getLog(LdapAttributes.class); private static final String SAFE_CHAR = "[\\p{ASCII}&&[^\\x00\\x0A\\x0D]]"; //Any ASCII except NUL, LF, and CR private static final String SAFE_INIT_CHAR = "[\\p{ASCII}&&[^ \\x00\\x0A\\x0D\\x3A\\x3C]]"; //Any ASCII except NUL, LF, CR, SPACE, colon, and less-than /** * Distinguished name to which the object is bound. */ protected DistinguishedName dn = new DistinguishedName(); /** * Default constructor. */ public LdapAttributes() { } /** * Creates an LdapAttributes object with the specified DN. * * @param dn The {@link org.springframework.ldap.core.DistinguishedName} to which this object is bound. */ public LdapAttributes(DistinguishedName dn) { super(); this.dn = dn; } /** * Constructor for specifying whether or not the object is case sensitive. * * @param ignoreCase boolean indicator. */ public LdapAttributes(boolean ignoreCase) { super(ignoreCase); } /** * Creates an LdapAttributes object with the specified DN and case sensitivity setting. * * @param dn The {@link org.springframework.ldap.core.DistinguishedName} to which this object is bound. * @param ignoreCase boolean indicator. */ public LdapAttributes(DistinguishedName dn, boolean ignoreCase) { super(ignoreCase); this.dn = dn; } /** * Creates an LdapAttributes object with the specified attribute. * * @param attrID {@link java.lang.String} ID of the attribute. * @param val Value of the attribute. */ public LdapAttributes(String attrID, Object val) { put(new LdapAttribute(attrID, val)); } /** * Creates an LdapAttributes object with the specifying attribute and value and case sensitivity setting. * * @param dn The {@link org.springframework.ldap.core.DistinguishedName} to which this object is bound. * @param attrID {@link java.lang.String} ID of the attribute. * @param val Value of the attribute. */ public LdapAttributes(DistinguishedName dn, String attrID, Object val) { this.dn = dn; put(new LdapAttribute(attrID, val)); } /** * Creates an LdapAttributes object with the specifying attribute and value and case sensitivity setting. * * @param attrID {@link java.lang.String} ID of the attribute. * @param val Value of the attribute. * @param ignoreCase boolean indicator. */ public LdapAttributes(String attrID, Object val, boolean ignoreCase) { put(new LdapAttribute(attrID, val, ignoreCase)); } /** * Creates an LdapAttributes object for the supplied DN with the attribute specified. * * @param dn The {@link org.springframework.ldap.core.DistinguishedName} to which this object is bound. * @param attrID {@link java.lang.String} ID of the attribute. * @param val Value of the attribute. * @param ignoreCase boolean indicator. */ public LdapAttributes(DistinguishedName dn, String attrID, Object val, boolean ignoreCase) { this.dn = dn; put(new LdapAttribute(attrID, val, ignoreCase)); } /** * Returns the distinguished name to which the object is bound. * * @return {@link org.springframework.ldap.core.DistinguishedName} specifying the name to which the object is bound. */ public DistinguishedName getDN() { return dn; } /** * Sets the distinguished name of the object. * * @param dn {@link org.springframework.ldap.core.DistinguishedName} specifying the name to which the object is bound. */ public void setDN(DistinguishedName dn) { this.dn = dn; } /** * Returns a string representation of the object in LDIF format. * * @return {@link java.lang.String} formated to RFC2849 LDIF specifications. */ public String toString() { StringBuilder sb = new StringBuilder(); try { DistinguishedName dn = getDN(); if (!dn.toString().matches(SAFE_INIT_CHAR + SAFE_CHAR + "*")) { sb.append("dn:: " + new BASE64Encoder().encode(dn.toString().getBytes()) + "\n"); } else { sb.append("dn: " + getDN() + "\n"); } NamingEnumeration attributes = getAll(); while (attributes.hasMore()) { Attribute attribute = attributes.next(); NamingEnumeration values = attribute.getAll(); while (values.hasMore()) { Object value = values.next(); if (value instanceof String) sb.append(attribute.getID() + ": " + (String) value + "\n"); else if (value instanceof byte[]) sb.append(attribute.getID() + ":: " + new BASE64Encoder().encode((byte[]) value) + "\n"); else if (value instanceof URI) sb.append(attribute.getID() + ":< " + (URI) value + "\n"); else { sb.append(attribute.getID() + ": " + value + "\n"); } } } } catch (NamingException e) { log.error("Error formating attributes for output.", e); sb = new StringBuilder(); } return sb.toString(); } } ././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/ldif/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0002755000000000000000000000000011475313400030171 5ustar ././@LongLink0000000000000000000000000000022100000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/ldif/InvalidRecordFormatException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000000250711475313400030175 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.ldif; import org.springframework.ldap.NamingException; /** * Thrown whenever a parsed record does not conform to LDAP specifications. * * @author Keith Barlow * */ public class InvalidRecordFormatException extends NamingException { private static final long serialVersionUID = -5047874723621065139L; /** * @param msg */ public InvalidRecordFormatException(String msg) { super(msg); } /** * @param cause */ public InvalidRecordFormatException(Throwable cause) { super(cause); } /** * @param msg * @param cause */ public InvalidRecordFormatException(String msg, Throwable cause) { super(msg, cause); } } ././@LongLink0000000000000000000000000000017000000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/ldif/support/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0002755000000000000000000000000011475313400030171 5ustar ././@LongLink0000000000000000000000000000022600000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/ldif/support/AttributeValidationPolicy.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000000222211475313400030167 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.ldif.support; import javax.naming.directory.Attribute; /** * Interface defining the required methods for AttributeValidationPolicies. * * @author Keith Barlow * */ public interface AttributeValidationPolicy { /** * Validates attribute contained in the buffer and returns an LdapAttribute. * * @param buffer Buffer containing the line parsed from the resource. * @return LdapAttribute representing the attribute parsed. */ Attribute parse(String buffer); } ././@LongLink0000000000000000000000000000021300000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/ldif/support/LineIdentifier.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000000341011475313400030167 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.ldif.support; /** * Enumeration declaring possible event types when parsing LDIF files. * * @author Keith Barlow */ public enum LineIdentifier { /** * Every LDIF file may optionally start with a version identifier of the form 'version: 1'. */ VersionIdentifier, /** * Signifies the start of a new record in the file has been encountered: a DN declaration. */ NewRecord, /** * Signals the end of record has been reached. */ EndOfRecord, /** * Signifies the event when a new attribute is encountered. */ Attribute, /** * Indicates the current line parsed is a continuation of the previous line. */ Continuation, /** * The current line is a comment and should be ignored. */ Comment, /** * An LDAP changetype control was encountered. */ Control, /** * Record being parsed is a 'changetype' record. */ ChangeType, /** * Parsed line should be ignored - used to skip remaining lines in a 'changetype' record. */ Void } ././@LongLink0000000000000000000000000000020400000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/ldif/support/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000000054311475313400030173 0ustar Provides the necessary auxiliary classes utilized by the LDIFParser.

Notable classes in this package include:

  • AttributeValidationPolicy - specifies the proper format valid attributes must adhere to.
  • SeparatorPolicy - translates lines read from the resource into attributes.
././@LongLink0000000000000000000000000000021400000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/ldif/support/SeparatorPolicy.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000000652011475313400030174 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.ldif.support; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Policy object for enforcing LDIF record separation rules. Designed explicitly * for use in LdifParser. This default separator policy should really not be * required to be replaced but it is modular just in case. *

* This class applies the separation policy prescribed in RFC2849 for LDIF files * and identifies the line type from the input. * * @author Keith Barlow * */ public class SeparatorPolicy { private static Log log = LogFactory.getLog(SeparatorPolicy.class); /* * Line Identification Patterns. */ private static final String VERSION_IDENTIFIER = "^version: [0-9]+(\\.[0-9]*){0,1}$"; private static final String CONTROL = "control:"; private static final String CHANGE_TYPE = "changetype:"; private static final String CONTINUATION = " "; private static final String COMMENT = "#"; private static final String NewRecord = "^dn:.*$"; private boolean record = false; private boolean skip = false; public SeparatorPolicy() { } /** * Assess a read line. *

* In LDIF, lines must adhere to a particular format. A line can only contain one attribute * and its value. The value may span multiple lines. Continuation lines are marked by the presence * of a single space in the 1st position. Non-continuation lines must start in the first position. * */ public LineIdentifier assess(String line) { log.trace("Assessing --> [" + line + "]"); if (record) { if (StringUtils.isEmpty(line)) { record = false; skip = false; return LineIdentifier.EndOfRecord; } else if (skip) { return LineIdentifier.Void; } else { if (line.startsWith(CONTROL)) { skip = true; return LineIdentifier.Control; } else if (line.startsWith(CHANGE_TYPE)) { skip = true; return LineIdentifier.ChangeType; } else if (line.startsWith(COMMENT)) { return LineIdentifier.Comment; } else if (line.startsWith(CONTINUATION)) { return LineIdentifier.Continuation; } else { return LineIdentifier.Attribute; } } } else { if (StringUtils.isNotEmpty(line) && line.matches(VERSION_IDENTIFIER) && !skip) { //Version Identifiers are ignored by parser. return LineIdentifier.VersionIdentifier; } else if (StringUtils.isNotEmpty(line) && line.matches(NewRecord)) { record = true; skip = false; return LineIdentifier.NewRecord; } else { return LineIdentifier.Void; } } } } ././@LongLink0000000000000000000000000000023500000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/ldif/support/DefaultAttributeValidationPolicy.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000003336211475313400030200 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.ldif.support; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.naming.directory.Attribute; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.core.LdapAttribute; import org.springframework.ldap.ldif.InvalidAttributeFormatException; import sun.misc.BASE64Decoder; /** * Ensures the buffer represents a valid attribute as defined by RFC2849. * * Meets the standards imposed by RFC 2849 for the "LDAP Data Interchange Format (LDIF) * - Technical Specification". * * Special attention is called to URL support: RFC 2849 requires that * LDIFs support URLs as defined in 1738; however, RFC 1738 has been updated by several RFCs including * RFC 1808, RFC 2396, and RFC 3986 (which obsoleted the formers). Unsupported features of this * implementation of URL identification include query strings and fragments in HTTP URLs. * * @author Keith Barlow * */ @SuppressWarnings("unused") public class DefaultAttributeValidationPolicy implements AttributeValidationPolicy { private static Log log = LogFactory.getLog(DefaultAttributeValidationPolicy.class); /** * Pattern Declarations. */ //General Definitions private static final String DIGIT = "\\p{Digit}"; private static final String LOW_ALPHA = "\\p{Lower}"; private static final String HIGH_ALPHA = "\\p{Upper}"; private static final String ALPHA = "\\p{Alpha}"; private static final String ALPHANUM = "\\p{Alnum}"; private static final String HEX = "\\p{XDigit}"; private static final String SAFE = "[\\x24\\x2D\\x5F\\x2E\\x2B]"; //$|-|_|.|+ private static final String EXTRA = "[\\x21\\x2A\\x27\\x7B\\x7D\\x2C]"; //!|*|'|(|)|, private static final String PUNCTUATION = "[\\x3C\\x3E\\x23\\x25\\x22]"; //<|>|#|%|" private static final String ESCAPE = "%" + HEX + "{2}"; private static final String RESERVED = "[\\x3B\\x2F\\x3F\\x3A\\x40\\x26\\x3D]"; //;|/|?|:|@|&|= private static final String UNRESERVED = "[" + ALPHA + DIGIT + SAFE + EXTRA + "]"; private static final String UCHAR = "(?:" + UNRESERVED + "|" + ESCAPE + ")"; private static final String XCHAR = "(?:" + UNRESERVED + "|" + RESERVED + "|" + ESCAPE + ")"; private static final String DIGITS = DIGIT + "+"; //Standard LDAP Attribute Definitions private static final String ATTRIBUTE_SEPARATOR = ":"; private static final String OPTION_SEPARATOR = ";"; private static final String BASE64_INDICATOR = ":"; private static final String URL_INDICATOR = "<"; private static final String ATTRIBUTE_TYPE_CHARS = ALPHA + DIGIT + "-"; private static final String LDAP_OID = "[[0-9]|[1-9][0-9]+][\\.(?:[0-9]|[1-9][0-9]+)]+"; private static final String OPTION = "[" + ATTRIBUTE_TYPE_CHARS + "]+"; private static final String OPTIONS = "[" + OPTION_SEPARATOR + OPTION + "]*"; private static final String ATTRIBUTE_TYPE = LDAP_OID + "|" + ALPHANUM + "[" + ATTRIBUTE_TYPE_CHARS + "]*"; private static final String ATTRIBUTE_DESCRIPTION = "(" + ATTRIBUTE_TYPE + ")(" + OPTIONS + ")"; private static final String SAFE_CHAR = "[\\p{ASCII}&&[^\\x00\\x0A\\x0D]]"; //Any ASCII except NUL, LF, and CR private static final String SAFE_INIT_CHAR = "[\\p{ASCII}&&[^ \\x00\\x0A\\x0D\\x3A\\x3C]]"; //Any ASCII except NUL, LF, CR, SPACE, colon, and less-than private static final String SAFE_STRING = "(" + SAFE_INIT_CHAR + SAFE_CHAR + "*)"; private static final String FILL = "[ ]*"; //Any number of spaces //BASE64 Definitions private static final String BASE64_CHAR = "[\\x2B\\x2F\\x30-\\x39\\x3D\\x41-\\x5A\\x61-\\x7A]"; //+, /, 0-9, -, A-Z, a-z private static final String BASE64_STRING = "(" + BASE64_CHAR + "*)"; //URL Components private static final String USER = "[" + UCHAR + "\\x3B\\x3F\\x26\\x3D]*"; //UCHAR|;|?|&|= private static final String PASSWORD = "[" + UCHAR + "\\x3B\\x3F\\x26\\x3D]*"; //UCHAR|;|?|&|= private static final String DOMAINLABEL = ALPHANUM + "|" + ALPHANUM + "[" + ALPHANUM + "-]*" + ALPHANUM; private static final String TOPLABEL = ALPHA + "|" + ALPHA + "[" + ALPHANUM + "-]*" + ALPHANUM; private static final String HOSTNAME = "(?:" + DOMAINLABEL + "\\.)*" + TOPLABEL; private static final String IPADDRESS = "(?:" + DIGIT + "{1,3}\\.){3}" + DIGIT + "{1,3}"; private static final String HOST = "(?:" + HOSTNAME + "|" + IPADDRESS + ")"; private static final String PORT = DIGITS; private static final String HOSTPORT = HOST + "(?::" + PORT + ")?"; private static final String URLPATH = XCHAR + "*"; private static final String LOGIN = "(?:" + USER + "(?::" + PASSWORD + ")?@)?" + HOSTPORT; //URL Definitions private static final String SCHEME = "[" + LOW_ALPHA + DIGIT + "\\x2B\\x2D\\x2E]+"; private static final String IP_SCHEMEPART = "//" + LOGIN + "(?:/" + URLPATH + ")?"; private static final String SCHEMEPART = "(?:" + XCHAR + "*|" + IP_SCHEMEPART + ")"; private static final String GENERIC_URL = SCHEME + ":" + SCHEMEPART; //HTTP Definition private static final String HSEGMENT = "[" + UCHAR + "\\x3A\\x3B\\x26\\x3D\\x40]*"; //UCHAR|:|;|&|=|@ private static final String HPATH = HSEGMENT + "[/" + HSEGMENT + "]*"; private static final String SEARCH = HSEGMENT; private static final String HTTP_URL = "http://" + HOSTPORT + "(?:/" + HPATH + "(?:\\x3F" + SEARCH + ")?)?"; //FTP private static final String FSEGMENT = "[" + UCHAR + "\\x3F\\x3A\\x26\\x3D\\x40]*"; //UCHAR|?|:|&|=|@ private static final String FPATH = FSEGMENT + "[/" + FSEGMENT + "]*"; private static final String FTPTYPE = "[AIDaid]"; private static final String FTP_URL = "ftp://" + LOGIN + "(?:/" + FPATH + "(?:;type=" + FTPTYPE + ")?)?"; //NEWS private static final String GROUP = ALPHA + "[" + ALPHA + DIGIT + "\\x2D\\x2E\\x2B\\x5F]*"; //ALPHA [ALPHA|DIGIT|-|.|+|_]* private static final String ARTICLE = "[" + UCHAR + "\\x3A\\x3B\\x2F\\x3F\\x26\\x3D]@" + HOST; //[UCHAR|;|/|?|:|&|=]@HOST private static final String GROUPPART = "(?:\\x2A|" + GROUP + "|" + ARTICLE + ")"; private static final String NEWS_URL = "news:" + GROUPPART; //NNTP private static final String NNTP_URL = "nntp://" + HOSTPORT + "/" + GROUP + "/" + DIGITS; //TELNET private static final String TELNET_URL = "telnet://" + LOGIN + "[/]?"; //GOPHER private static final String GTYPE = XCHAR; private static final String SELECTOR = XCHAR + "*"; private static final String GOPHER_STRING = XCHAR + "*"; private static final String GOPHER_URL = "gopher://" + HOSTPORT + "(?:/(?:" + GTYPE + "(?:" + SELECTOR + "(?:%09" + SEARCH + "(?:%09" + GOPHER_STRING + ")?)?)?)?)?"; //WAIS private static final String WPATH = UCHAR + "*"; private static final String WTYPE = UCHAR + "*"; private static final String DATABASE = UCHAR + "*"; private static final String WAIS_DOC = "wais://" + HOSTPORT + "/" + DATABASE + "/" + WTYPE + "/" + WPATH; private static final String WAIS_INDEX = "wais://" + HOSTPORT + "/" + DATABASE + "\\?" + SEARCH; private static final String WAIS_DATABASE = "wais://" + HOSTPORT + "/" + DATABASE; private static final String WAIS_URL = WAIS_DATABASE + "|" + WAIS_INDEX + "|" + WAIS_DOC; //MAILTO private static final String ENCODED_822_ADDR = XCHAR + "+"; private static final String MAILTO_URL = "mailto:" + ENCODED_822_ADDR; //FILE private static final String FILE_URL = "file://(?:" + HOST + "|localhost)?/" + FPATH ; //PROPERO private static final String FIELD_VALUE = "[" + UCHAR + "\\x3F\\x3A\\x40\\x26]*"; //[UCHAR|?|:|@|&]* private static final String FIELD_NAME = "[" + UCHAR + "\\x3F\\x3A\\x40\\x26]*"; //[UCHAR|?|:|@|&]* private static final String FIELD_SPEC = ";" + FIELD_NAME + "=" + FIELD_VALUE; private static final String PSEGMENT = "[" + UCHAR + "\\x3F\\x3A\\x40\\x26\\x3D]*"; //[UCHAR|?|:|@|&|=]* private static final String PPATH = PSEGMENT + "(?:/" + PSEGMENT + ")*"; private static final String PROSPERO_URL = "prospero://" + HOSTPORT + "/" + PPATH + "(?:" + FIELD_SPEC + ")*"; //GENERIC private static final String OTHER_URL = GENERIC_URL; private static final String URL = "((?:" + HTTP_URL + ")|(?:" + FTP_URL + ")|(?:" + NEWS_URL + ")|(?:" + NNTP_URL + ")|(?:" + TELNET_URL + ")|(?:" + GOPHER_URL + ")|(?:" + WAIS_URL + ")|(?:" + MAILTO_URL + ")|(?:" + FILE_URL + ")|(?:" + PROSPERO_URL + ")|(?:" + OTHER_URL + "))"; //URL Pattern //Expression Definitions private static final String ATTRIBUTE_EXPRESSION = "^" + ATTRIBUTE_DESCRIPTION + ATTRIBUTE_SEPARATOR + FILL + SAFE_STRING + "{0,1}$"; //Regular Attribute private static final String BASE64_ATTRIBUTE_EXPRESSION = "^" + ATTRIBUTE_DESCRIPTION + ATTRIBUTE_SEPARATOR + BASE64_INDICATOR + FILL + BASE64_STRING + "$"; //Base 64 private static final String URL_ATTRIBUTE_EXPRESSION = "^" + ATTRIBUTE_DESCRIPTION + ATTRIBUTE_SEPARATOR + URL_INDICATOR + FILL + URL + "$"; //URL //Pattern Declarations private static final Pattern ATTRIBUTE_PATTERN = Pattern.compile(ATTRIBUTE_EXPRESSION); private static final Pattern BASE64_ATTRIBUTE_PATTERN = Pattern.compile(BASE64_ATTRIBUTE_EXPRESSION); private static final Pattern URL_ATTRIBUTE_PATTERN = Pattern.compile(URL_ATTRIBUTE_EXPRESSION); private boolean ordered = false; /** * Default constructor. */ public DefaultAttributeValidationPolicy() { } /** * Constructor for indicating whether or not attribute values should be ordered alphabetically. * * @param ordered value. */ public DefaultAttributeValidationPolicy(boolean ordered) { this.ordered = ordered; } /** * Indicates whether or not the attribute values should be ordered alphabetically. * * @param ordered value. */ public void setOrdered(boolean ordered) { this.ordered = ordered; } /** * Validates attribute contained in the buffer and returns an LdapAttribute. *

* Ensures attributes meets one of three prescribed patterns for valid attributes: *

    *
  1. A standard attribute pattern of the form: ATTR_ID[;options]: VALUE
  2. *
  3. A Base64 attribute pattern of the form: ATTR_ID[;options]:: BASE64_VALUE
  4. *
  5. A url attribute pattern of the form: ATTR_ID[;options]:< URL_VALUE
  6. *
*

* Upon success an LdapAttribute object is returned. * * @param buffer {@inheritDoc} * @return {@inheritDoc} * @throws InvalidAttributeFormatException if the attribute does not meet one of the three patterns above * or the attribute cannot be parsed. */ public Attribute parse(String buffer) { log.trace("Parsing --> [" + buffer + "]"); Matcher matcher = ATTRIBUTE_PATTERN.matcher(buffer); if (matcher.matches()) { //Is a regular attribute... return parseStringAttribute(matcher); } matcher = BASE64_ATTRIBUTE_PATTERN.matcher(buffer); if (matcher.matches()) { //Is a base64 attribute... return parseBase64Attribute(matcher); } matcher = URL_ATTRIBUTE_PATTERN.matcher(buffer); if (matcher.matches()) { //Is a URL attribute... return parseUrlAttribute(matcher); } //default: no match. throw new InvalidAttributeFormatException("Not a valid attribute: [" + buffer + "]"); } private LdapAttribute parseStringAttribute(Matcher matcher) { String id = matcher.group(1); String value = matcher.group(3); List options = Arrays.asList((StringUtils.isEmpty(matcher.group(2)) ? new String[] {} : matcher.group(2).replaceFirst(";","").split(OPTION_SEPARATOR))); if (options.isEmpty()) { return new LdapAttribute(id, value, ordered); } else { return new LdapAttribute(id, value, options, ordered); } } private LdapAttribute parseBase64Attribute(Matcher matcher) { try { String id = matcher.group(1); String value = matcher.group(3); List options = Arrays.asList((StringUtils.isEmpty(matcher.group(2)) ? new String[] {} : matcher.group(2).replaceFirst(";","").split(OPTION_SEPARATOR))); if (options.isEmpty()) { return new LdapAttribute(id, new BASE64Decoder().decodeBuffer(value), ordered); } else { return new LdapAttribute(id, new BASE64Decoder().decodeBuffer(value), options, ordered); } } catch (IOException e) { throw new InvalidAttributeFormatException(e); } } private LdapAttribute parseUrlAttribute(Matcher matcher) { try { String id = matcher.group(1); String value = matcher.group(3); List options = Arrays.asList((StringUtils.isEmpty(matcher.group(2)) ? new String[] {} : matcher.group(2).replaceFirst(";","").split(OPTION_SEPARATOR))); if (options.isEmpty()) { return new LdapAttribute(id, new URI(value), ordered); } else { return new LdapAttribute(id, new URI(value), options, ordered); } } catch (URISyntaxException e) { throw new InvalidAttributeFormatException(e); } } } ././@LongLink0000000000000000000000000000017400000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/ldif/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000000035311475313400030172 0ustar The base package for Spring LDAPs LDIF parser implementation.

Classes declared in this package include the new base types for LDAP objects as well as exception types for the LDIF parser. ././@LongLink0000000000000000000000000000016700000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/ldif/parser/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0002755000000000000000000000000011475313400030171 5ustar ././@LongLink0000000000000000000000000000020600000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/ldif/parser/LdifParser.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000003022011475313400030166 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.ldif.parser; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.util.NoSuchElementException; import javax.naming.NamingException; import javax.naming.directory.Attribute; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.LdapAttributes; import org.springframework.ldap.ldif.InvalidRecordFormatException; import org.springframework.ldap.ldif.support.AttributeValidationPolicy; import org.springframework.ldap.ldif.support.DefaultAttributeValidationPolicy; import org.springframework.ldap.ldif.support.LineIdentifier; import org.springframework.ldap.ldif.support.SeparatorPolicy; import org.springframework.ldap.schema.DefaultSchemaSpecification; import org.springframework.ldap.schema.Specification; import org.springframework.util.Assert; /** * The {@link LdifParser LdifParser} is the main class of the {@link org.springframework.ldap.ldif} package. * This class reads lines from a resource and assembles them into an {@link LdapAttributes LdapAttributes} object. * The {@link LdifParser LdifParser} does ignores changetype LDIF entries as their usefulness in the * context of an application has yet to be determined. *

* Design
* {@link LdifParser LdifParser} provides the main interface for operation but requires three supporting classes to * enable operation: *

    *
  • {@link SeparatorPolicy SeparatorPolicy} - establishes the mechanism by which lines are assembled into attributes.
  • *
  • {@link AttributeValidationPolicy AttributeValidationPolicy} - ensures that attributes are correctly structured prior to parsing.
  • *
  • {@link Specification Specification} - provides a mechanism by which object structure can be validated after assembly.
  • *
* Together, these 4 classes read from the resource line by line and translate the data into objects for use. *

* Usage
* {@link #getRecord() getRecord()} reads the next available record from the resource. Lines are read and * passed to the {@link SeparatorPolicy SeparatorPolicy} for interpretation. The parser continues to read * lines and appends them to the buffer until it encounters the start of a new attribute or an end of record * delimiter. When the new attribute or end of record is encountered, the buffer is passed to the * {@link AttributeValidationPolicy AttributeValidationPolicy} which ensures the buffer conforms to a valid * attribute definition as defined in RFC2849 and returns an {@link org.springframework.ldap.core.LdapAttribute LdapAttribute} object * which is then added to the record, an {@link LdapAttributes LdapAttributes} object. Upon encountering the * end of record, the record is validated by the {@link Specification Specification} policy and, * if valid, returned to the requester. *

* NOTE: By default, objects are not validated. If validation is required, * an appropriate specification object must be set. *

* The parser requires the resource to be {@link #open() open()} prior to an invocation of {@link #getRecord() getRecord()}. * {@link #hasMoreRecords() hasMoreRecords()} can be used to loop over the resource until all records have been * retrieved. Likewise, the {@link #reset() reset()} method will reset the resource. *

* Objects implementing the {@link javax.naming.directory.Attributes Attributes} interface are required to support a case sensitivity setting * which controls whether or not the attribute IDs of the object are case sensitive. The {@link #caseInsensitive caseInsensitive} * setting of the {@link LdifParser LdifParser} is passed to the constructor of any {@link javax.naming.directory.Attributes Attributes} created. The * default value for this setting is true so that case insensitive objects are created. * * @author Keith Barlow * */ public class LdifParser implements Parser, InitializingBean { private static final Log log = LogFactory.getLog(LdifParser.class); /** * The resource to parse. */ private Resource resource; /** * A BufferedReader to read the file. */ private BufferedReader reader; /** * The SeparatorPolicy to use for interpreting attributes from the lines of the resource. */ private SeparatorPolicy separatorPolicy = new SeparatorPolicy(); /** * The AttributeValidationPolicy to use to interpret attributes. */ private AttributeValidationPolicy attributePolicy = new DefaultAttributeValidationPolicy(); /** * The RecordSpecification for validating records produced. */ private Specification specification = new DefaultSchemaSpecification(); /** * This setting is used to control the case sensitivity of LdapAttribute objects returned by the parser. */ private boolean caseInsensitive = true; /** * Default constructor. */ public LdifParser() { } /** * Creates a LdifParser with the indicated case sensitivity setting. * * @param caseInsensitive Case sensitivity setting for LdapAttributes objects returned by the parser. */ public LdifParser(boolean caseInsensitive) { this.caseInsensitive = caseInsensitive; } /** * Creates an LdifParser for the specified resource with the provided case sensitivity setting. * * @param resource The resource to parse. * @param caseInsensitive Case sensitivity setting for LdapAttributes objects returned by the parser. */ public LdifParser(Resource resource, boolean caseInsensitive) { this.resource = resource; this.caseInsensitive = caseInsensitive; } /** * Convenience constructor for resource specification. * * @param resource The resource to parse. */ public LdifParser(Resource resource) { this.resource = resource; } /** * Convenience constructor: accepts a File object. * * @param file The file to parse. */ public LdifParser(File file) { this.resource = new FileSystemResource(file); } /** * Set the separator policy. * * The default separator policy should suffice for most needs. * * @param separatorPolicy Separator policy. */ public void setSeparatorPolicy(SeparatorPolicy separatorPolicy) { this.separatorPolicy = separatorPolicy; } /** * Policy object enforcing the rules for acceptable attributes. * * @param avPolicy Attribute validation policy. */ public void setAttributeValidationPolicy(AttributeValidationPolicy avPolicy) { this.attributePolicy = avPolicy; } /** * Policy object for enforcing rules to acceptable LDAP objects. * * This policy may be used to enforce schema restrictions. * @param specification */ public void setRecordSpecification(Specification specification) { this.specification = specification; } public void setResource(Resource resource) { this.resource = resource; } public void setCaseInsensitive(boolean caseInsensitive) { this.caseInsensitive = caseInsensitive; } public void open() throws IOException { Assert.notNull(resource, "Resource must be set."); reader = new BufferedReader(new InputStreamReader(resource.getInputStream())); } public boolean isReady() throws IOException { return reader.ready(); } public void close() throws IOException { if (resource.isOpen()) reader.close(); } public void reset() throws IOException { Assert.notNull(reader, "A reader has not been obtained."); reader.reset(); } public boolean hasMoreRecords() throws IOException { return reader.ready(); } public LdapAttributes getRecord() throws IOException { Assert.notNull(reader, "A reader must be obtained: parser not open."); if (!reader.ready()) { log.debug("Reader not ready!"); return null; } LdapAttributes record = new LdapAttributes(caseInsensitive); StringBuilder builder = new StringBuilder(); String line = reader.readLine(); while(true) { LineIdentifier identifier = separatorPolicy.assess(line); switch(identifier) { case NewRecord: log.trace("Starting new record."); //Start new record. builder = new StringBuilder(line); break; case Control: log.trace("'control' encountered."); //Log WARN and discard record. log.warn("LDIF change records have no implementation: record will be ignored."); builder = null; record = null; break; case ChangeType: log.trace("'changetype' encountered."); //Log WARN and discard record. log.warn("LDIF change records have no implementation: record will be ignored."); builder = null; record = null; break; case Attribute: //flush buffer. addAttributeToRecord(builder.toString(), record); log.trace("Starting new attribute."); //Start new attribute. builder = new StringBuilder(line); break; case Continuation: log.trace("...appending line to buffer."); //Append line to buffer. builder.append(line.replaceFirst(" ", "")); break; case EndOfRecord: log.trace("...done parsing record. (EndOfRecord)"); //Validate record and return. if (record == null) return null; else { try { //flush buffer. addAttributeToRecord(builder.toString(), record); if (specification.isSatisfiedBy(record)) { log.debug("record parsed:\n" + record); return record; } else { throw new InvalidRecordFormatException("Record [dn: " + record.getDN() + "] does not conform to specification."); } } catch(NamingException e) { log.error(e); return null; } } default: //Take no action -- applies to VersionIdentifier, Comments, and voided records. } line = reader.readLine(); } } private void addAttributeToRecord(String buffer, LdapAttributes record) { try { if (StringUtils.isNotEmpty(buffer) && record != null) { //Validate previous attribute and add to record. Attribute attribute = attributePolicy.parse(buffer); if (attribute.getID().equalsIgnoreCase("dn")) { log.trace("...adding DN to record."); String dn; if (attribute.get() instanceof byte[]) { dn = new String((byte[]) attribute.get()); } else { dn = (String) attribute.get(); } record.setDN(new DistinguishedName(dn)); } else { log.trace("...adding attribute to record."); Attribute attr = record.get(attribute.getID()); if (attr != null) { attr.add(attribute.get()); } else { record.put(attribute); } } } } catch (NamingException e) { log.error(e); } catch (NoSuchElementException e) { log.error(e); } } public void afterPropertiesSet() throws Exception { Assert.notNull(resource, "A resource to parse is required."); Assert.isTrue(resource.exists(), resource.getDescription() + ": resource does not exist!"); Assert.isTrue(resource.isReadable(), "Resource is not readable."); } } ././@LongLink0000000000000000000000000000020300000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/ldif/parser/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000000014111475313400030165 0ustar This package contains the parser classes and interfaces. ././@LongLink0000000000000000000000000000020200000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/ldif/parser/Parser.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000000551111475313400030173 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.ldif.parser; import java.io.IOException; import javax.naming.directory.Attributes; import org.springframework.core.io.Resource; /** * The Parser interface represents the required methods to be implemented by parser utilities. * These methods are the base set of methods needed to provide parsing ability. * * @author Keith Barlow */ public interface Parser { /** * Sets the resource to parse. * * @param resource The resource to parse. */ public void setResource(Resource resource); /** * Sets the control parameter for specifying case sensitivity on creation of the {@link Attributes} object. * * @param caseInsensitive The resource to parse. */ public void setCaseInsensitive(boolean caseInsensitive); /** * Opens the resource: the resource must be opened prior to parsing. * * @throws IOException if a problem is encountered while trying to open the resource. */ public void open() throws IOException; /** * Closes the resource after parsing. * * @throws IOException if a problem is encountered while trying to close the resource. */ public void close() throws IOException; /** * Resets the line read parser. * * @throws Exception if a problem is encountered while trying to reset the resource. */ public void reset() throws IOException; /** * True if the resource contains more records; false otherwise. * * @return boolean indicating whether or not the end of record has been reached. * @throws IOException if a problem is encountered while trying to validate the resource is ready. */ public boolean hasMoreRecords() throws IOException; /** * Parses the next record from the resource. * * @return LdapAttributes object representing the record parsed. * @throws IOException if a problem is encountered while trying to read from the resource. */ public Attributes getRecord() throws IOException; /** * Indicates whether or not the parser is ready to to return results. * * @return boolean indicator * @throws IOException if there is a problem with the underlying resource. */ public boolean isReady() throws IOException; } ././@LongLink0000000000000000000000000000022400000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/ldif/InvalidAttributeFormatException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000000252611475313400030176 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.ldif; import org.springframework.ldap.NamingException; /** * Thrown whenever a parsed attribute does not conform to LDAP specifications. * * @author Keith Barlow * */ public class InvalidAttributeFormatException extends NamingException { private static final long serialVersionUID = -4529380160785322985L; /** * @param msg */ public InvalidAttributeFormatException(String msg) { super(msg); } /** * @param cause */ public InvalidAttributeFormatException(Throwable cause) { super(cause); } /** * @param msg * @param cause */ public InvalidAttributeFormatException(String msg, Throwable cause) { super(msg, cause); } } ././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/schema/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0002755000000000000000000000000011475313400030171 5ustar ././@LongLink0000000000000000000000000000021700000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/schema/BasicSchemaSpecification.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000000371511475313400030177 0ustar package org.springframework.ldap.schema; import javax.naming.NamingException; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.LdapAttributes; import org.springframework.ldap.core.LdapRdn; import sun.misc.BASE64Encoder; /** * BasicSchemaSpecification establishes a minimal set of requirements for object classes. *

* This basic specification, which does not actually validate against any schema, deems objects * valid as long as they meet the following criteria: *

    *
  • the object has a non-null DN.
  • *
  • the object contains the naming attribute declared by the DN.
  • *
  • the object declares an objectClass.
  • *
* * @author Keith Barlow * */ public class BasicSchemaSpecification implements Specification { /** * Determines if the policy is satisfied by the supplied LdapAttributes object. * * @throws NamingException */ public boolean isSatisfiedBy(LdapAttributes record) throws NamingException { if (record != null) { //DN is required. DistinguishedName dn = record.getDN(); if (dn != null) { //objectClass definition is required. if (record.get("objectClass") != null) { //Naming attribute is required. LdapRdn rdn = dn.getLdapRdn(dn.size() - 1); if (record.get(rdn.getKey()) != null) { Object object = record.get(rdn.getKey()).get(); if (object instanceof String) { String value = (String) object; if (rdn.getValue().equalsIgnoreCase(value)) { return true; } } else if(object instanceof byte[]) { BASE64Encoder encoder = new BASE64Encoder(); String rdnValue = encoder.encode(rdn.getValue().getBytes()); String attributeValue = encoder.encode((byte[]) object); if (rdnValue.equals(attributeValue)) return true; } } } } } return false; } } ././@LongLink0000000000000000000000000000020400000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/schema/Specification.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000000206511475313400030174 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.schema; import javax.naming.NamingException; /** * The specification interface is implemented to declare rules that * a record must conform to. The motivation behind this class was * to provide a mechanism to enable schema validations. * * @author Keith Barlow * * @param */ public interface Specification { boolean isSatisfiedBy(T record) throws NamingException; } ././@LongLink0000000000000000000000000000017600000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/schema/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000000041211475313400030166 0ustar This package is aimed at providing a mechanism to implement LDAP schemas.

Utilized by the LDIFParser to validate object composition post assembly, these classes may also be referenced by other utilities where seen fit. ././@LongLink0000000000000000000000000000022100000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework/ldap/schema/DefaultSchemaSpecification.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-ldif-core/org/springframework0000644000000000000000000000250011475313400030166 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.schema; import javax.naming.NamingException; import org.springframework.ldap.core.LdapAttributes; /** * DefaultSchemaSpecification does not validate objects at all - it simply returns true. *

* This specification is intended for cases where validation of the parsed entries is not * required. * * @author Keith Barlow * */ public class DefaultSchemaSpecification implements Specification { /** * Determines if the policy is satisfied by the supplied LdapAttributes object. * * @throws NamingException */ public boolean isSatisfiedBy(LdapAttributes record) throws NamingException { return true; } } libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/0002755000000000000000000000000011475313400024435 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/overview.html0000644000000000000000000000016211475313400027166 0ustar This document is the API specification for the Java5-specific parts of the Spring LDAP Framework. libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/0002755000000000000000000000000011475313376025240 5ustar ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0002755000000000000000000000000011475313376030226 5ustar ././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/ldap/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0002755000000000000000000000000011475313400030212 5ustar ././@LongLink0000000000000000000000000000016100000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/ldap/core/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0002755000000000000000000000000011475313400030212 5ustar ././@LongLink0000000000000000000000000000017000000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/ldap/core/simple/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0002755000000000000000000000000011475313400030212 5ustar ././@LongLink0000000000000000000000000000024500000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/ldap/core/simple/ContextMapperCallbackHandlerWithControls.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0000644000000000000000000000500311475313400030210 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.simple; import javax.naming.Binding; import javax.naming.NameClassPair; import javax.naming.ldap.HasControls; import org.springframework.ldap.core.ContextMapperCallbackHandler; import org.springframework.ldap.core.ObjectRetrievalException; /** * Currently only per request controls can be inspected via the post process * method on a context processor. If a request control gives a different value * for each search result, then this cannot be inspected using the existing * support classes. An example control that requires this feature would be * 1.3.6.1.4.1.42.2.27.9.5.8 Account usability control, that can be used with * for example the Sun ONE or the OpenDS directory servers. * * The extended callback handler can pass hasControls to mapper. * * @author Tim Terry * @author Ulrik Sandberg */ public class ContextMapperCallbackHandlerWithControls extends ContextMapperCallbackHandler { private ParameterizedContextMapperWithControls mapper = null; public ContextMapperCallbackHandlerWithControls(final ParameterizedContextMapperWithControls mapper) { super(mapper); this.mapper = mapper; } /* * @see org.springframework.ldap.core.ContextMapperCallbackHandler# * getObjectFromNameClassPair(javax.naming.NameClassPair) */ public Object getObjectFromNameClassPair(final NameClassPair nameClassPair) { if (!(nameClassPair instanceof Binding)) { throw new IllegalArgumentException("Parameter must be an instance of Binding"); } Binding binding = (Binding) nameClassPair; Object object = binding.getObject(); if (object == null) { throw new ObjectRetrievalException("Binding did not contain any object."); } Object result = null; if (nameClassPair instanceof HasControls) { result = mapper.mapFromContextWithControls(object, (HasControls) nameClassPair); } else { result = mapper.mapFromContext(object); } return result; } } ././@LongLink0000000000000000000000000000020400000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/ldap/core/simple/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0000644000000000000000000000014411475313400030211 0ustar Simplification layer over LdapTemplate for Java 5 and above. ././@LongLink0000000000000000000000000000023700000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/ldap/core/simple/AbstractParameterizedContextMapper.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0000644000000000000000000000352311475313400030215 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.simple; import org.springframework.ldap.core.DirContextOperations; /** * Abstract superclass that may be used instead of implementing * {@link ParameterizedContextMapper} directly. Subclassing from this superclass, * the supplied context will be automatically cast to * DirContextOperations. Note that if you use your own * DirObjectFactory, this implementation will fail with a * ClassCastException. * * @author Mattias Hellborg Arthursson * */ public abstract class AbstractParameterizedContextMapper implements ParameterizedContextMapper { /* * (non-Javadoc) * * @see org.springframework.ldap.core.ContextMapper#mapFromContext(java.lang.Object) */ public final T mapFromContext(Object ctx) { return doMapFromContext((DirContextOperations) ctx); } /** * Map a single DirContextOperation to an object. The * supplied instance is the object supplied to * {@link #mapFromContext(Object)} cast to a * DirContextOperations. * * @param ctx the context to map to an object. * @return an object built from the data in the context. */ protected abstract T doMapFromContext(DirContextOperations ctx); } ././@LongLink0000000000000000000000000000022700000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/ldap/core/simple/ParameterizedContextMapper.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0000644000000000000000000000262511475313400030217 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.simple; import javax.naming.Binding; import javax.naming.directory.SearchResult; import org.springframework.ldap.core.ContextMapper; /** * Extension of the {@link ContextMapper} interface. Uses Java 5 covariant * return types to override the return type of the * {@link #mapFromContext(Object)} method to be the type parameter T. * * @param */ public interface ParameterizedContextMapper extends ContextMapper { /** * Map a single LDAP Context to an object. The supplied Object * ctx is the object from a single {@link SearchResult}, * {@link Binding}, or a lookup operation. * * @param ctx the context to map to an object. * @return an object built from the data in the context. */ public T mapFromContext(Object ctx); } ././@LongLink0000000000000000000000000000022100000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/ldap/core/simple/SimpleLdapOperations.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0000644000000000000000000002763111475313400030223 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.simple; import java.util.List; import javax.naming.Name; import javax.naming.directory.Attributes; import javax.naming.directory.SearchControls; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.ldap.NamingException; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DirContextProcessor; import org.springframework.ldap.core.LdapOperations; /** * LDAP operations interface usable on Java 5 and above, exposing a set of * common LDAP operations. * * @author Mattias Hellborg Arthursson */ public interface SimpleLdapOperations { /** * Get the wrapped LdapOperations instance. * * @return the wrapped LdapOperations instance. * @throws NamingException if any error occurs. */ LdapOperations getLdapOperations(); /** * Search for a List of type T using the supplied filter and link * ParameterizedContextMapper. * * @param base Base DN relative to the base of the ContextSource - where to * start the search. * @param filter Search filter. * @param mapper the Mapper to supply all results to. * @return a List of type T containing objects for all entries found, as * mapped by the ParameterizedContextMapper. * @throws NamingException if any error occurs. */ List search(String base, String filter, ParameterizedContextMapper mapper); /** * Search for a List of type T using the supplied filter and link * ParameterizedContextMapper. * * @param base Base DN relative to the base of the ContextSource - where to * start the search. * @param filter Search filter. * @param mapper the Mapper to supply all results to. * @return a List of type T containing objects for all entries found, as * mapped by the ParameterizedContextMapper. * @throws NamingException if any error occurs. * @since 1.3 */ List search(Name base, String filter, ParameterizedContextMapper mapper); /** * Search for a List of type T using the supplied filter, SearchControls, * DirContextProcessor and ParameterizedContextMapper. * * @param base Base DN relative to the base of the ContextSource - where to * start the search. * @param filter Search filter. * @param controls the SearchControls. Make sure that the returningObjFlag * is set to true. * @param mapper the Mapper to supply all results to. * @param processor the DirContextProcessor to be used for applying pre/post * processing on the DirContext instance. * @return a List of type T containing objects for all entries found, as * mapped by the ParameterizedContextMapper. * @throws NamingException if any error occurs. */ List search(String base, String filter, SearchControls controls, ParameterizedContextMapper mapper, DirContextProcessor processor); /** * Search for a List of type T using the supplied filter, SearchControls, * DirContextProcessor and ParameterizedContextMapper. * * @param base Base DN relative to the base of the ContextSource - where to * start the search. * @param filter Search filter. * @param controls the SearchControls. Make sure that the returningObjFlag * is set to true. * @param mapper the Mapper to supply all results to. * @param processor the DirContextProcessor to be used for applying pre/post * processing on the DirContext instance. * @return a List of type T containing objects for all entries found, as * mapped by the ParameterizedContextMapper. * @throws NamingException if any error occurs. * @since 1.3 */ List search(Name base, String filter, SearchControls controls, ParameterizedContextMapper mapper, DirContextProcessor processor); /** * Perform a lookup of the specified DN and map the result using the mapper. * * @param dn the Distinguished Name to look up. * @param mapper the mapper to use. * @return the mapped object, as received by the ParameterizedContextMapper. * @throws NamingException if any error occurs. */ T lookup(String dn, ParameterizedContextMapper mapper); /** * Perform a lookup of the specified DN and map the result using the mapper. * * @param dn the Distinguished Name to look up. * @param mapper the mapper to use. * @return the mapped object, as received by the ParameterizedContextMapper. * @throws NamingException if any error occurs. * @since 1.3 */ T lookup(Name dn, ParameterizedContextMapper mapper); /** * Perform a search for a unique entry matching the specified search * criteria and return the found object. If no entry is found or if there * are more than one matching entry, an * {@link IncorrectResultSizeDataAccessException} is thrown. * @param base the DN to use as the base of the search. * @param filter the search filter. * @param mapper the mapper to use for the search. * @return the single object returned by the mapper that matches the search * criteria. * @throws IncorrectResultSizeDataAccessException if the result is not one * unique entry * @since 1.3 */ T searchForObject(String base, String filter, ParameterizedContextMapper mapper); /** * Perform a search for a unique entry matching the specified search * criteria and return the found object. If no entry is found or if there * are more than one matching entry, an * {@link IncorrectResultSizeDataAccessException} is thrown. * @param base the DN to use as the base of the search. * @param filter the search filter. * @param mapper the mapper to use for the search. * @return the single object returned by the mapper that matches the search * criteria. * @throws IncorrectResultSizeDataAccessException if the result is not one * unique entry * @since 1.3 */ T searchForObject(Name base, String filter, ParameterizedContextMapper mapper); /** * Look up the specified DN, and automatically cast it to a * {@link DirContextOperations} instance. * * @param dn The Distinguished Name of the entry to look up. * @return A {@link DirContextOperations} instance constructed from the * found entry. * @throws NamingException if any error occurs. */ DirContextOperations lookupContext(String dn); /** * Look up the specified DN, and automatically cast it to a * {@link DirContextOperations} instance. * * @param dn The Distinguished Name of the entry to look up. * @return A {@link DirContextOperations} instance constructed from the * found entry. * @throws NamingException if any error occurs. * @since 1.3 */ DirContextOperations lookupContext(Name dn); /** * Create an entry in the LDAP tree. The attributes used to create the entry * are either retrieved from the obj parameter or the * attributes parameter (or both). One of these parameters may * be null but not both. * * @param dn The distinguished name to bind the object and attributes to. * @param obj The object to bind, may be null. Typically a DirContext * implementation. * @param attributes The attributes to bind, may be null. * @throws NamingException if any error occurs. */ void bind(String dn, Object obj, Attributes attributes); /** * Create an entry in the LDAP tree. The attributes used to create the entry * are either retrieved from the obj parameter or the * attributes parameter (or both). One of these parameters may * be null but not both. * * @param dn The distinguished name to bind the object and attributes to. * @param obj The object to bind, may be null. Typically a DirContext * implementation. * @param attributes The attributes to bind, may be null. * @throws NamingException if any error occurs. * @since 1.3 */ void bind(Name dn, Object obj, Attributes attributes); /** * Bind the data in the supplied context in the tree. All specified * Attributes in will be bound to the DN set on the instance. * * @param ctx the context to bind * @throws IllegalStateException if no DN is set or if the instance is in * update mode. * @since 1.3 */ void bind(DirContextOperations ctx); /** * Remove an entry from the LDAP tree. The entry must not have any children. * * @param dn The distinguished name to unbind. * @throws NamingException if any error occurs. */ void unbind(String dn); /** * Remove an entry from the LDAP tree. The entry must not have any children. * * @param dn The distinguished name to unbind. * @throws NamingException if any error occurs. * @since 1.3 */ void unbind(Name dn); /** * Modify the Attributes of the entry corresponding to the supplied * {@link DirContextOperations} instance. The instance should have been * received from the {@link #lookupContext(String)} operation, and then * modified to match the current state of the matching domain object, e.g.: * *

	 * public void update(Person person) {
	 * 	DirContextOperations ctx = simpleLdapOperations.lookup(person.getDn());
	 * 
	 * 	ctx.setAttributeValue("description", person.getDescription());
	 * 	ctx.setAttributeValue("telephoneNumber", person.getPhone());
	 * 	// More modifications here
	 * 
	 * 	simpleLdapOperations.modifyAttributes(ctx);
	 * }
	 * 
* * @param ctx the entry to update in the LDAP tree. * @throws NamingException if any error occurs. */ void modifyAttributes(DirContextOperations ctx); /** * Utility method to perform a simple LDAP 'bind' authentication. Search for * the LDAP entry to authenticate using the supplied base DN and filter; use * the DN of the found entry together with the password as input to * {@link ContextSource#getContext(String, String)}, thus authenticating the * entry. *

* Example:
* *

	 * AndFilter filter = new AndFilter();
	 * filter.and("objectclass", "person").and("uid", userId);
	 * boolean authenticated = ldapTemplate.authenticate(DistinguishedName.EMPTY_PATH,
	 * 		filter.toString(), password);
	 * 
* * @param base the DN to use as the base of the search. * @param filter the search filter - must result in a unique result. * @param password the password to use for authentication. * @return true if the authentication was successful, * false otherwise. * @since 1.3 */ boolean authenticate(String base, String filter, String password); /** * Utility method to perform a simple LDAP 'bind' authentication. Search for * the LDAP entry to authenticate using the supplied base DN and filter; use * the DN of the found entry together with the password as input to * {@link ContextSource#getContext(String, String)}, thus authenticating the * entry. *

* Example:
* *

	 * AndFilter filter = new AndFilter();
	 * filter.and("objectclass", "person").and("uid", userId);
	 * boolean authenticated = ldapTemplate.authenticate(DistinguishedName.EMPTY_PATH,
	 * 		filter.toString(), password);
	 * 
* * @param base the DN to use as the base of the search. * @param filter the search filter - must result in a unique result. * @param password the password to use for authentication. * @return true if the authentication was successful, * false otherwise. * @since 1.3 */ boolean authenticate(Name base, String filter, String password); } ././@LongLink0000000000000000000000000000024300000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/ldap/core/simple/ParameterizedContextMapperWithControls.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0000644000000000000000000000250711475313400030216 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.simple; import javax.naming.ldap.HasControls; /** * Extension of the {@link ParameterizedContextMapper} interface that allows * controls to be passed to the mapper implementation. Uses Java 5 covariant * return types to override the return type of the * {@link #mapFromContextWithControls(Object, HasControls)} method to be the * type parameter T. * * @author Tim Terry * @author Ulrik Sandberg * @param return type of the * {@link #mapFromContextWithControls(Object, HasControls)} method */ public interface ParameterizedContextMapperWithControls extends ParameterizedContextMapper { T mapFromContextWithControls(final Object ctx, final HasControls hasControls); } ././@LongLink0000000000000000000000000000021700000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/ldap/core/simple/SimpleLdapTemplate.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0000644000000000000000000002034411475313400030215 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.core.simple; import java.util.List; import javax.naming.Name; import javax.naming.directory.Attributes; import javax.naming.directory.SearchControls; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DirContextProcessor; import org.springframework.ldap.core.LdapOperations; import org.springframework.ldap.core.LdapTemplate; /** * Java-5-based convenience wrapper for the classic LdapTemplate, adding some * convenient shortcuts and taking advantage of Java 5 Generics. * * Use the {@link #getLdapOperations()} method if you need to invoke less * commonly used template methods. * * @author Mattias Hellborg Arthursson */ public class SimpleLdapTemplate implements SimpleLdapOperations { private LdapOperations ldapOperations; /** * Constructs a new SimpleLdapTemplate instance wrapping the supplied * LdapOperations instance. * * @param ldapOperations the LdapOperations instance to wrap. */ public SimpleLdapTemplate(LdapOperations ldapOperations) { this.ldapOperations = ldapOperations; } /** * Constructs a new SimpleLdapTemplate instance, automatically creating a * wrapped LdapTemplate instance to work with. * * @param contextSource */ public SimpleLdapTemplate(ContextSource contextSource) { this.ldapOperations = new LdapTemplate(contextSource); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#getLdapOperations * () */ public LdapOperations getLdapOperations() { return ldapOperations; } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#lookup(java * .lang.String, * org.springframework.ldap.core.simple.ParametrizedContextMapper) */ @SuppressWarnings("unchecked") public T lookup(String dn, ParameterizedContextMapper mapper) { return (T) ldapOperations.lookup(dn, mapper); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#search(java * .lang.String, java.lang.String, * org.springframework.ldap.core.simple.ParametrizedContextMapper) */ @SuppressWarnings("unchecked") public List search(String base, String filter, ParameterizedContextMapper mapper) { return ldapOperations.search(base, filter, mapper); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#search(java * .lang.String, java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.simple.ParametrizedContextMapper, * org.springframework.ldap.core.DirContextProcessor) */ @SuppressWarnings("unchecked") public List search(String base, String filter, SearchControls controls, ParameterizedContextMapper mapper, DirContextProcessor processor) { return ldapOperations.search(base, filter, controls, mapper, processor); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#lookup(java * .lang.String) */ public DirContextOperations lookupContext(String dn) { return ldapOperations.lookupContext(dn); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#modifyAttributes * (org.springframework.ldap.core.DirContextOperations) */ public void modifyAttributes(DirContextOperations ctx) { ldapOperations.modifyAttributes(ctx); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#bind(java.lang * .String, java.lang.Object, javax.naming.directory.Attributes) */ public void bind(String dn, Object obj, Attributes attributes) { ldapOperations.bind(dn, obj, attributes); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#unbind(java * .lang.String) */ public void unbind(String dn) { ldapOperations.unbind(dn); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#bind(javax. * naming.Name, java.lang.Object, javax.naming.directory.Attributes) */ public void bind(Name dn, Object obj, Attributes attributes) { ldapOperations.bind(dn, obj, attributes); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#lookup(javax * .naming.Name, * org.springframework.ldap.core.simple.ParameterizedContextMapper) */ @SuppressWarnings("unchecked") public T lookup(Name dn, ParameterizedContextMapper mapper) { return (T) ldapOperations.lookup(dn, mapper); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#lookupContext * (javax.naming.Name) */ public DirContextOperations lookupContext(Name dn) { return ldapOperations.lookupContext(dn); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#search(javax * .naming.Name, java.lang.String, * org.springframework.ldap.core.simple.ParameterizedContextMapper) */ @SuppressWarnings("unchecked") public List search(Name base, String filter, ParameterizedContextMapper mapper) { return ldapOperations.search(base, filter, mapper); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#search(javax * .naming.Name, java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.simple.ParameterizedContextMapper, * org.springframework.ldap.core.DirContextProcessor) */ @SuppressWarnings("unchecked") public List search(Name base, String filter, SearchControls controls, ParameterizedContextMapper mapper, DirContextProcessor processor) { return ldapOperations.search(base, filter, controls, mapper, processor); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#unbind(javax * .naming.Name) */ public void unbind(Name dn) { ldapOperations.unbind(dn); } /* * (non-Javadoc) * * @seeorg.springframework.ldap.core.simple.SimpleLdapOperations#bind(org. * springframework.ldap.core.DirContextOperations) */ public void bind(DirContextOperations ctx) { ldapOperations.bind(ctx); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#searchForObject * (java.lang.String, java.lang.String, * org.springframework.ldap.core.simple.ParameterizedContextMapper) */ @SuppressWarnings("unchecked") public T searchForObject(String base, String filter, ParameterizedContextMapper mapper) { return (T) ldapOperations.searchForObject(base, filter, mapper); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#searchForObject * (javax.naming.Name, java.lang.String, * org.springframework.ldap.core.simple.ParameterizedContextMapper) */ @SuppressWarnings("unchecked") public T searchForObject(Name base, String filter, ParameterizedContextMapper mapper) { return (T) ldapOperations.searchForObject(base, filter, mapper); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#authenticate * (java.lang.String, java.lang.String, java.lang.String) */ public boolean authenticate(String base, String filter, String password) { return ldapOperations.authenticate(base, filter, password); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.simple.SimpleLdapOperations#authenticate * (javax.naming.Name, java.lang.String, java.lang.String) */ public boolean authenticate(Name base, String filter, String password) { return ldapOperations.authenticate(base, filter, password); } } ././@LongLink0000000000000000000000000000016100000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/ldap/ldif/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0002755000000000000000000000000011475313400030212 5ustar ././@LongLink0000000000000000000000000000017100000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/ldap/ldif/support/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0002755000000000000000000000000011475313400030212 5ustar ././@LongLink0000000000000000000000000000017000000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/ldap/ldif/parser/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0002755000000000000000000000000011475313400030212 5ustar ././@LongLink0000000000000000000000000000016300000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframework/ldap/schema/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-core-tiger/org/springframewor0002755000000000000000000000000011475313400030212 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/0002755000000000000000000000000011475313376023170 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/0002755000000000000000000000000011475313376023757 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/0002755000000000000000000000000011475313376027177 5ustar ././@LongLink0000000000000000000000000000014500000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0002755000000000000000000000000011475313376030117 5ustar ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0002755000000000000000000000000011475313376030117 5ustar ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/core/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0002755000000000000000000000000011475313376030117 5ustar ././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/core/OdmException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000074211475313376030122 0ustar package org.springframework.ldap.odm.core; import org.springframework.ldap.NamingException; /** * The root of the Spring LDAP ODM exception hierarchy. * * @author Paul Harvey <paul.at.pauls-place.me.uk> * */ @SuppressWarnings("serial") public class OdmException extends NamingException { public OdmException(String message) { super(message); } public OdmException(String message, Throwable e) { super(message, e); } } ././@LongLink0000000000000000000000000000017500000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/core/OdmManager.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000700311475313376030117 0ustar package org.springframework.ldap.odm.core; import java.util.List; import javax.naming.Name; import javax.naming.directory.SearchControls; /** * The OdmManager interface provides generic CRUD (create/read/update/delete) * and searching operations against an LDAP directory. *

* Each managed Java class must be appropriately annotated using * {@link org.springframework.ldap.odm.annotations}. * * @author Paul Harvey <paul.at.pauls-place.me.uk> * * @see org.springframework.ldap.odm.annotations.Entry * @see org.springframework.ldap.odm.annotations.Attribute * @see org.springframework.ldap.odm.annotations.Id * @see org.springframework.ldap.odm.annotations.Transient */ public interface OdmManager { /** * Read a named entry from the LDAP directory. * * @param The Java type to return * @param clazz The Java type to return * @param dn The distinguished name of the entry to read from the LDAP directory. * @return The entry as read from the directory * * @exception org.springframework.ldap.NamingException on error. */ T read(Class clazz, Name dn); /** * Create the given entry in the LDAP directory. * * @param entry The entry to be create, it must not already exist in the directory. * * @exception org.springframework.ldap.NamingException on error. */ void create(Object entry); /** * Update the given entry in the LDAP directory. * * @param entry The entry to update, it must already exist in the directory. * * @exception org.springframework.ldap.NamingException on error. */ void update(Object entry); /** * Delete an entry from the LDAP directory. * * @param entry The entry to delete, it must already exist in the directory. * * @exception org.springframework.ldap.NamingException on error. */ void delete(Object entry); /** * Find all entries in the LDAP directory of a given type. * * @param The Java type to return * @param clazz The Java type to return * @param base The root of the sub-tree at which to begin the search. * @param searchControls The scope of the search. * @return All entries that are of the type represented by the given * Java class * * @exception org.springframework.ldap.NamingException on error. */ List findAll(Class clazz, Name base, SearchControls searchControls); /** * Search for entries in the LDAP directory. *

* Only those entries that both match the given search filter and * are represented by the given Java class are returned * * @param The Java type to return * @param clazz The Java type to return * @param base The root of the sub-tree at which to begin the search. * @param filter An LDAP search filter. * @param searchControls The scope of the search. * @return All matching entries. * * @exception org.springframework.ldap.NamingException on error. * * @see Sun's JNDI tutorial description of search filters. * @see LDAP: String Representation of Search Filters RFC. */ List search(Class clazz, Name base, String filter, SearchControls searchControls); } ././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/core/package-info.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000055011475313376030117 0ustar /** * Provides an OdmManager interface for interaction with an LDAP directory. *

* Implementations of this interface are intended to be used in conjunction with classes * annotated with {@link org.springframework.ldap.odm.annotations}. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ package org.springframework.ldap.odm.core;././@LongLink0000000000000000000000000000016300000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/core/impl/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0002755000000000000000000000000011475313376030117 5ustar ././@LongLink0000000000000000000000000000020600000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/core/impl/OdmManagerImpl.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000005423011475313376030123 0ustar package org.springframework.ldap.odm.core.impl; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.naming.Name; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.SearchControls; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.LdapOperations; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.simple.ParameterizedContextMapper; import org.springframework.ldap.filter.AndFilter; import org.springframework.ldap.filter.EqualsFilter; import org.springframework.ldap.odm.core.OdmException; import org.springframework.ldap.odm.core.OdmManager; import org.springframework.ldap.odm.typeconversion.ConverterManager; /** * An implementation of {@link org.springframework.ldap.odm.core.OdmManager} which * uses {@link org.springframework.ldap.odm.typeconversion.ConverterManager} to * convert between Java and LDAP representations of attribute values. * * @author Paul Harvey <paul.at.pauls-place.me.uk> * */ public final class OdmManagerImpl implements OdmManager { private static final Log LOG = LogFactory.getLog(OdmManagerImpl.class); // The link to the LDAP directory private final LdapOperations ldapTemplate; // The converter manager to use to translate values between LDAP and Java private final ConverterManager converterManager; private static String OBJECT_CLASS_ATTRIBUTE="objectclass"; private static CaseIgnoreString OBJECT_CLASS_ATTRIBUTE_CI=new CaseIgnoreString(OBJECT_CLASS_ATTRIBUTE); private static final class EntityData { private final ObjectMetaData metaData; private final String ocFilter; private EntityData(ObjectMetaData metaData, String ocFilter) { this.metaData=metaData; this.ocFilter=ocFilter; } } // A map of managed classes to to meta data about those classes private final Map, EntityData> metaDataMap=new HashMap, EntityData>(); public OdmManagerImpl(ConverterManager converterManager, ContextSource contextSource, Set> managedClasses) { this.converterManager=converterManager; this.ldapTemplate=new LdapTemplate(contextSource); if (managedClasses!=null) { for (Class managedClass: managedClasses) { addManagedClass(managedClass); } } } public OdmManagerImpl(ConverterManager converterManager, ContextSource contextSource) { this(converterManager, contextSource, null); } private EntityData getEntityData(Class managedClass) { EntityData result=metaDataMap.get(managedClass); if (result==null) { throw new UnmanagedClassException(String.format("The %1$s class is not managed by this OdmManager", managedClass)); } return result; } /** * Adds an {@link org.springframework.ldap.odm.annotations} annotated class to the set * managed by this OdmManager. * * @param managedClass The class to add to the managed set. */ public void addManagedClass(Class managedClass) { if (LOG.isDebugEnabled()) { LOG.debug(String.format("Adding class %1$s to managed set", managedClass)); } // Extract the meta-data from the class ObjectMetaData metaData=new ObjectMetaData(managedClass); // Check we can construct the target type - it must have a zero argument public constructor try { managedClass.getConstructor(); } catch (NoSuchMethodException e) { throw new InvalidEntryException(String.format( "The class %1$s must have a zero argument constructor to be an Entry", managedClass)); } // Check we have all of the necessary converters for the class for (Field field : metaData) { AttributeMetaData attributeInfo = metaData.getAttribute(field); if (!attributeInfo.isId() && !(attributeInfo.isObjectClass())) { Class jndiClass = (attributeInfo.isBinary()) ? byte[].class : String.class; Class javaClass = attributeInfo.getValueClass(); if (!converterManager.canConvert(jndiClass, attributeInfo.getSyntax(), javaClass)) { throw new InvalidEntryException(String.format( "Missing converter from %1$s to %2$s, this is needed for field %3$s on Entry %4$s", jndiClass, javaClass, field.getName(), managedClass)); } if (!converterManager.canConvert(javaClass, attributeInfo.getSyntax(), jndiClass)) { throw new InvalidEntryException(String.format( "Missing converter from %1$s to %2$s, this is needed for field %3$s on Entry %4$s", javaClass, jndiClass, field.getName(), managedClass)); } } } // Filter so we only read the object classes supported by the managedClass AndFilter ocFilter = new AndFilter(); for (CaseIgnoreString oc : metaData.getObjectClasses()) { ocFilter.and(new EqualsFilter(OBJECT_CLASS_ATTRIBUTE, oc.toString())); } metaDataMap.put(managedClass, new EntityData(metaData, ocFilter.encode())); } /* * (non-Javadoc) * * @see org.springframework.ldap.odm.core.OdmManager#create(java.lang.Object) */ public T read(Class clazz, Name dn) { if (LOG.isDebugEnabled()) { LOG.debug(String.format("Reading Entry at - %s$1", dn)); } getEntityData(clazz); T result = clazz.cast(ldapTemplate.lookup(dn, new GenericContextMapper(clazz))); if (result==null) { throw new OdmException(String.format("Entry %1$s has excess object classes", dn)); } if (LOG.isDebugEnabled()) { LOG.debug(String.format("Found entry - %s$1", result)); } return result; } /* * (non-Javadoc) * * @see org.springframework.ldap.odm.core.OdmManager#create(java.lang.Object) */ public void create(Object entry) { if (LOG.isDebugEnabled()) { LOG.debug(String.format("Creating entry - %s$1", entry)); } DirContextAdapter context = new DirContextAdapter(getId(entry)); mapToContext(entry, context); ldapTemplate.bind(context); } /* * (non-Javadoc) * * @see org.springframework.ldap.odm.core.OdmManager#update(java.lang.Object, boolean) */ public void update(Object entry) { if (LOG.isDebugEnabled()) { LOG.debug(String.format("Updating entry - %s$1", entry)); } DirContextAdapter context = new DirContextAdapter(getId(entry)); mapToContext(entry, context); ldapTemplate.rebind(context); } /* * (non-Javadoc) * * @see org.springframework.ldap.odm.core.OdmManager#delete(javax.naming.Name) */ public void delete(Object entry) { if (LOG.isDebugEnabled()) { LOG.debug(String.format("Deleting %s$1", entry)); } // Just to check that this is a managed class getEntityData(entry.getClass()); ldapTemplate.unbind(getId(entry)); } private Name getId(Object entry) { try { return (Name)getEntityData(entry.getClass()).metaData.getIdAttribute().getField().get(entry); } catch (Exception e) { throw new InvalidEntryException(String.format("Can't get Id field from Entry %1$s", entry), e); } } /* (non-Javadoc) * @see org.springframework.ldap.odm.core.OdmManager#search(java.lang.Class, javax.naming.Name, java.lang.String, javax.naming.directory.SearchControls) */ public List search(Class managedClass, Name base, String filter, SearchControls scope) { EntityData entityData=getEntityData(managedClass); // Add a filter so we only read the object class we can deal with String finalFilter = entityData.ocFilter; if (filter != null && filter.length() != 0) { StringBuilder fixedFilter = new StringBuilder(); fixedFilter.append("(&(").append(filter).append(")").append(entityData.ocFilter).append(")"); finalFilter = fixedFilter.toString(); } // Search from the root if we are not told where to search from Name localBase = base; if (base == null || base.size() == 0) { localBase = DistinguishedName.EMPTY_PATH; } if (LOG.isDebugEnabled()) { LOG.debug(String.format("Searching - base=%1$s, finalFilter=%2$s, scope=%3$s", base, finalFilter, scope)); } @SuppressWarnings("unchecked") List result = ldapTemplate.search(localBase, finalFilter, scope, new GenericContextMapper(managedClass)); result.remove(null); if (LOG.isDebugEnabled()) { LOG.debug(String.format("Found %1$s Entries - %2$s", result.size(), result)); } return result; } /* * (non-Javadoc) * @see org.springframework.ldap.odm.core.OdmManager#findAll(javax.naming.Name, javax.naming.directory.SearchControls) */ public List findAll(Class managedClass, Name base, SearchControls scope) { if (LOG.isDebugEnabled()) { LOG.debug(String.format("Searching for all Entries with objectClass=%1$s, with base=%2$s, scope=%3$s", getEntityData(managedClass).metaData.getObjectClasses(), base, scope)); } return search(managedClass, base, null, scope); } /** * Used to convert from Java representation of an Ldap Entry when writing to * the Ldap directory * * @param entry - The entry to convert. * @param context - The LDAP context to store the converted entry * @throws javax.naming.NamingEnumeration on error. */ private void mapToContext(Object entry, DirContextOperations context) { ObjectMetaData metaData=getEntityData(entry.getClass()).metaData; // Object classes are set from the metadata obtained from the @Entity annotation int numOcs=metaData.getObjectClasses().size(); CaseIgnoreString[] metaDataObjectClasses=metaData.getObjectClasses().toArray(new CaseIgnoreString[numOcs]); String[] stringOcs=new String[numOcs]; for (int ocIndex=0; ocIndex targetClass = (attributeInfo.isBinary()) ? byte[].class : String.class; // Multi valued? if (!attributeInfo.isList()) { // Single valued - get the value of the field Object fieldValue = field.get(entry); // Ignore null field values if (fieldValue != null) { // Convert the field value to the required type and write it into the JNDI context context.setAttributeValue(attributeInfo.getName().toString(), converterManager.convert(fieldValue, attributeInfo.getSyntax(), targetClass)); } } else { // Multi-valued // We need to build up a list of of the values List attributeValues = new ArrayList(); // Get the list of values Collection fieldValues = (Collection)field.get(entry); // Ignore null lists if (fieldValues != null) { for (final Object o : fieldValues) { // Ignore null values if (o != null) { attributeValues.add((String)converterManager.convert(o, attributeInfo.getSyntax(), targetClass)); } } context.setAttributeValues(attributeInfo.getName().toString(), attributeValues.toArray()); } } } catch (IllegalAccessException e) { throw new InvalidEntryException(String.format("Can't set attribute %1$s", attributeInfo.getName()), e); } } } } /** * Used to convert from the JNDI LDAP representation of an Entry to the Java representation when reading from LDAP */ private class GenericContextMapper implements ParameterizedContextMapper { private final Class managedClass; private GenericContextMapper(Class managedClass) { this.managedClass=managedClass; } // Called by Spring LDAP to do the conversion /* * (non-Javadoc) * * @see org.springframework.ldap.core.simple.ParameterizedContextMapper#mapFromContext(java.lang.Object) */ public T mapFromContext(Object object) { if (LOG.isDebugEnabled()) { LOG.debug(String.format("Converting to Java Entry class %1$s from %2$s", managedClass, object)); } // The Java representation of the LDAP entry T result = null; // This is guaranteed by Spring LDAP to be a DirContextOperations DirContextOperations context = (DirContextOperations)object; ObjectMetaData metaData=getEntityData(managedClass).metaData; try { // The result class must have a zero argument constructor result = managedClass.newInstance(); // Build a map of JNDI attribute names to values Map attributeValueMap = new HashMap(); // Get a NamingEnumeration to loop through the JNDI attributes in the entry Attributes attributes = context.getAttributes(); NamingEnumeration attributesEnumeration = attributes.getAll(); // Loop through all of the JNDI attributes while (attributesEnumeration.hasMoreElements()) { Attribute currentAttribute = (Attribute)attributesEnumeration.nextElement(); // Add the current attribute to the map keyed on the lowercased (case indep) id of the attribute attributeValueMap.put(new CaseIgnoreString(currentAttribute.getID()), currentAttribute); } // Now loop through all the fields in the Java representation populating it with values from the // attributeValueMap for (Field field : metaData) { // Get the current field AttributeMetaData attributeInfo = metaData.getAttribute(field); // We deal with the Id field specially if (!attributeInfo.isId()) { // Not the ID - but is is multi valued? if (!attributeInfo.isList()) { // No - its single valued, grab the JNDI attribute that corresponds to the metadata on the // current field Attribute attribute = attributeValueMap.get(attributeInfo.getName()); // There is no guarantee that this attribute is present in the directory - so ignore nulls if (attribute != null) { // Grab the JNDI value Object value = attribute.get(); // Check the value is not null if (value != null) { // Convert the JNDI value to its Java representation - this will throw if the // conversion fails Object convertedValue = converterManager.convert(value, attributeInfo.getSyntax(), attributeInfo.getValueClass()); // Set it in the Java version field.set(result, convertedValue); } } } else { // We are dealing with a multi valued attribute // We need to build up a list of values List fieldValues = new ArrayList(); // Grab the attribute from the JNDI representation Attribute currentAttribute = attributeValueMap.get(attributeInfo.getName()); // There is no guarantee that this attribute is present in the directory - so ignore nulls if (currentAttribute != null) { // Loop through the values of the JNDI attribute NamingEnumeration valuesEmumeration = currentAttribute.getAll(); while (valuesEmumeration.hasMore()) { // Get the current value Object value = valuesEmumeration.nextElement(); // Check the value is not null if (value != null) { // Convert the value to its Java representation and add it to our working list fieldValues.add(converterManager.convert(value, attributeInfo.getSyntax(), attributeInfo.getValueClass())); } } } // Now we need to set the List in to a Java object field.set(result, fieldValues); } } else { // The id field field.set(result, converterManager.convert(context.getDn(), attributeInfo.getSyntax(), attributeInfo.getValueClass())); } } // If this is the objectclass attribute then check that values correspond to the metadata we have // for the Java representation Attribute ocAttribute = attributeValueMap.get(OBJECT_CLASS_ATTRIBUTE_CI); if (ocAttribute != null) { // Get all object class values from the JNDI attribute Set objectClassesFromJndi = new HashSet(); NamingEnumeration objectClassesFromJndiEnum = ocAttribute.getAll(); while (objectClassesFromJndiEnum.hasMoreElements()) { objectClassesFromJndi.add(new CaseIgnoreString((String)objectClassesFromJndiEnum.nextElement())); } // OK - checks its the same as the meta-data we have if (!objectClassesFromJndi.equals(metaData.getObjectClasses())) { // The items found has classes in addition to those searched for - so ditch it return null; } } else { throw new InvalidEntryException(String.format("No object classes were returned for class %1$s", managedClass.getName())); } } catch (NamingException ne) { throw new InvalidEntryException(String.format("Problem creating %1$s from LDAP Entry %2$s", managedClass, object), ne); } catch (IllegalAccessException iae) { throw new InvalidEntryException(String.format( "Could not create an instance of %1$s could not access field", managedClass.getName()), iae); } catch (InstantiationException ie) { throw new InvalidEntryException(String.format("Could not instantiate %1$s", managedClass), ie); } if (LOG.isDebugEnabled()) { LOG.debug(String.format("Converted object - %1$s", result)); } return result; } } } ././@LongLink0000000000000000000000000000021700000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/core/impl/UnmanagedClassException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000111611475313376030116 0ustar package org.springframework.ldap.odm.core.impl; import org.springframework.ldap.odm.core.OdmException; /** * Thrown when an OdmManager method is called with a class * which is not being managed by the OdmManager. * * @author Paul Harvey <paul.at.pauls-place.me.uk> * */ @SuppressWarnings("serial") public class UnmanagedClassException extends OdmException { public UnmanagedClassException(String message, Throwable reason) { super(message, reason); } public UnmanagedClassException(String message) { super(message); } } ././@LongLink0000000000000000000000000000020400000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/core/impl/package-info.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000066111475313376030122 0ustar /** * Provides a single public class which implements {@link org.springframework.ldap.odm.core.OdmManager}. *

* The OdmManager implementation works in conjunction with {@link org.springframework.ldap.odm.typeconversion} to provide * conversion between the representation of attributes in LDAP and in Java. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ package org.springframework.ldap.odm.core.impl;././@LongLink0000000000000000000000000000021000000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/core/impl/CaseIgnoreString.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000171311475313376030121 0ustar package org.springframework.ldap.odm.core.impl; // A case independent String wrapper. /* package */ final class CaseIgnoreString implements Comparable { private final String string; private final int hashCode; public CaseIgnoreString(String string) { if (string == null) throw new NullPointerException(); this.string = string; hashCode = string.toUpperCase().hashCode(); } public boolean equals(Object other) { return other instanceof CaseIgnoreString && ((CaseIgnoreString)other).string.equalsIgnoreCase(string); } public int hashCode() { return hashCode; } public int compareTo(CaseIgnoreString other) { CaseIgnoreString cis = (CaseIgnoreString)other; return String.CASE_INSENSITIVE_ORDER.compare(string, cis.string); } public String toString() { return string; } } ././@LongLink0000000000000000000000000000021100000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/core/impl/AttributeMetaData.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000002073511475313376030126 0ustar package org.springframework.ldap.odm.core.impl; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Set; import javax.naming.Name; import org.springframework.ldap.odm.annotations.Attribute; import org.springframework.ldap.odm.annotations.Id; /* * Extract attribute meta-data from the @Attribute annotation, the @Id annotation * and via reflection. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ /* package */ final class AttributeMetaData { private static final CaseIgnoreString OBJECT_CLASS_ATTRIBUTE_CI=new CaseIgnoreString("objectclass"); // Name of the LDAP attribute from the @Attribute annotation private CaseIgnoreString name; // Syntax of the LDAP attribute from the @Attribute annotation private String syntax; // Whether this attribute is binary from the @Attribute annotation private boolean isBinary; // The Java field corresponding to this meta-data private final Field field; // The Java class of the field corresponding to this meta data // This is the actual scalar type meaning that if the field is // List then the valueClass will be String private Class valueClass; // Is this field annotated @Id private boolean isId; // Is this field multi-valued represented by a List private boolean isList; // Is this the objectClass attribute private boolean isObjectClass; // Extract information from the @Attribute annotation: // syntax, isBinary, isObjectClass and name. private boolean processAttributeAnnotation(Field field) { // Default to no syntax specified syntax = ""; // Default to a String based attribute isBinary = false; // Default name of attribute to the name of the field name = new CaseIgnoreString(field.getName()); // We have not yet found the @Attribute annotation boolean foundAnnotation=false; // Grab the @Attribute annotation Attribute attribute = field.getAnnotation(Attribute.class); // Did we find the annotation? if (attribute != null) { // Pull attribute name, syntax and whether attribute is binary // from the annotation foundAnnotation=true; String localAttributeName = attribute.name(); // Would be more efficient to use !isEmpty - but that then makes us Java 6 dependent if (localAttributeName != null && localAttributeName.length()>0) { name = new CaseIgnoreString(localAttributeName); } syntax = attribute.syntax(); isBinary = attribute.type() == Attribute.Type.BINARY; } isObjectClass=name.equals(OBJECT_CLASS_ATTRIBUTE_CI); return foundAnnotation; } // Extract reflection information from the field: // valueClass, isList private void determineFieldType(Field field) { // Determine the class of data stored in the field Class fieldType = field.getType(); // We support only lists for multi-valued attributes, as we must allow duplicate values if (Set.class.isAssignableFrom(fieldType)) { throw new MetaDataException(String.format("Only lists are allowed for multivlaued attributes, errpr in field %1$s in Entry class %2$s", field, field.getDeclaringClass())); } isList = List.class.isAssignableFrom(fieldType); valueClass=null; if (!isList) { // It's not a list so assume its single valued - so just take the field type valueClass = fieldType; } else { // It's multi-valued - so we need to look at the signature in // the class file to find the generic type - this is supported for class file // format 49 and greater which corresponds to java 5 and later. ParameterizedType paramType; try { paramType = (ParameterizedType)field.getGenericType(); } catch (ClassCastException e) { throw new MetaDataException(String.format("Can't determine destination type for field %1$s in Entry class %2$s", field, field.getDeclaringClass()), e); } Type[] actualParamArguments = paramType.getActualTypeArguments(); if (actualParamArguments.length == 1) { if (actualParamArguments[0] instanceof Class) { valueClass = (Class)actualParamArguments[0]; } else { if (actualParamArguments[0] instanceof GenericArrayType) { // Deal with arrays Type type=((GenericArrayType)actualParamArguments[0]).getGenericComponentType(); if (type instanceof Class) { valueClass=Array.newInstance((Class)type, 0).getClass(); } } } } } // Check we have been able to determine the value class if (valueClass==null) { throw new MetaDataException(String.format("Can't determine destination type for field %1$s in class %2$s", field, field.getDeclaringClass())); } } // Extract information from the @Id annotation: // isId private boolean processIdAnnotation(Field field, Class fieldType) { // Are we dealing with the Id field? isId=field.getAnnotation(Id.class)!=null; if (isId) { // It must be of type Name or a subclass of that of if (!Name.class.isAssignableFrom(fieldType)) { throw new MetaDataException( String.format("The id field must be of type javax.naming.Name or a subclass that of in Entry class %1$s", field.getDeclaringClass())); } } return isId; } // Extract meta-data from the given field public AttributeMetaData(Field field) { this.field=field; // Reflection data determineFieldType(field); // Data from the @Attribute annotation boolean foundAttributeAnnotation=processAttributeAnnotation(field); // Data from the @Id annotation boolean foundIdAnnoation=processIdAnnotation(field, valueClass); // Check that the field has not been annotated with both @Attribute and with @Id if (foundAttributeAnnotation && foundIdAnnoation) { throw new MetaDataException( String.format("You may not specifiy an %1$s annoation and an %2$s annotation on the same field, error in field %3$s in Entry class %4$s", Id.class, Attribute.class, field.getName(), field.getDeclaringClass())); } // If this is the objectclass attribute then it must be of type List if (isObjectClass() && (!isList() || valueClass!=String.class)) { throw new MetaDataException(String.format("The type of the objectclass attribute must be List in classs %1$s", field.getDeclaringClass())); } } public String getSyntax() { return syntax; } public boolean isBinary() { return isBinary; } public Field getField() { return field; } public CaseIgnoreString getName() { return name; } public boolean isList() { return isList; } public boolean isId() { return isId; } public boolean isObjectClass() { return isObjectClass; } public Class getValueClass() { return valueClass; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { return String.format("name=%1$s | field=%2$s | valueClass=%3$s | syntax=%4$s| isBinary=%5$s | isId=%6$s | isList=%7$s | isObjectClass=%8$s", getName(), getField(), getValueClass().getName(), getSyntax(), isBinary(), isId(), isList(), isObjectClass()); } } ././@LongLink0000000000000000000000000000020600000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/core/impl/ObjectMetaData.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000001103711475313376030121 0ustar package org.springframework.ldap.odm.core.impl; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.odm.annotations.Entry; import org.springframework.ldap.odm.annotations.Id; import org.springframework.ldap.odm.annotations.Transient; /* * An internal class to process the meta-data and reflection data for an entry. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ /* package */ final class ObjectMetaData implements Iterable { private static final Log LOG = LogFactory.getLog(ObjectMetaData.class); private AttributeMetaData idAttribute; private Map fieldToAttribute = new HashMap(); private Set objectClasses = new HashSet(); public Set getObjectClasses() { return objectClasses; } public AttributeMetaData getIdAttribute() { return idAttribute; } /* * (non-Javadoc) * * @see java.lang.Iterable#iterator() */ public Iterator iterator() { return fieldToAttribute.keySet().iterator(); } public AttributeMetaData getAttribute(Field field) { return fieldToAttribute.get(field); } public ObjectMetaData(Class clazz) { if (LOG.isDebugEnabled()) { LOG.debug(String.format("Extracting metadata from %1$s", clazz)); } // Get object class metadata - the @Entity annotation Entry entity = (Entry)clazz.getAnnotation(Entry.class); if (entity != null) { // Default objectclass name to the class name unless it's specified // in @Entity(name={objectclass1, objectclass2}); String[] localObjectClasses = entity.objectClasses(); if (localObjectClasses != null && localObjectClasses.length > 0 && localObjectClasses[0].length() > 0) { for (String localObjectClass:localObjectClasses) { objectClasses.add(new CaseIgnoreString(localObjectClass)); } } else { objectClasses.add(new CaseIgnoreString(clazz.getSimpleName())); } } else { throw new MetaDataException(String.format("Class %1$s must have a class level %2$s annotation", clazz, Entry.class)); } // Check the class is final if (!Modifier.isFinal(clazz.getModifiers())) { LOG.warn(String.format("The Entry class %1$s should be declared final", clazz.getSimpleName())); } // Get field meta-data - the @Attribute annotation Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { // So we can write to private fields field.setAccessible(true); // Skip transient and synthetic fields if (field.getAnnotation(Transient.class) != null || field.isSynthetic()) { continue; } AttributeMetaData currentAttributeMetaData=new AttributeMetaData(field); if (currentAttributeMetaData.isId()) { if (idAttribute!=null) { // There can be only one id field throw new MetaDataException( String.format("You man have only one field with the %1$s annotation in class %2$s", Id.class, clazz)); } idAttribute=currentAttributeMetaData; } fieldToAttribute.put(field, currentAttributeMetaData); } if (idAttribute == null) { throw new MetaDataException( String.format("All Entry classes must define a field with the %1$s annotation, error in class %2$s", Id.class, clazz)); } if (LOG.isDebugEnabled()) { LOG.debug(String.format("Extracted metadata from %1$s as %2$s", clazz, this)); } } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { return String.format("objectsClasses=%1$s | idField=%2$s | attributes=%3$s", objectClasses, idAttribute.getName(), fieldToAttribute); } } ././@LongLink0000000000000000000000000000021500000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/core/impl/InvalidEntryException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000106411475313376030120 0ustar package org.springframework.ldap.odm.core.impl; import org.springframework.ldap.odm.core.OdmException; /** * Thrown to indicate that an instance is not suitable for persisting in the LDAP directory. * * @author Paul Harvey <paul.at.pauls-place.me.uk> * */ @SuppressWarnings("serial") public class InvalidEntryException extends OdmException { public InvalidEntryException(String message) { super(message); } public InvalidEntryException(String message, Throwable reason) { super(message, reason); } } ././@LongLink0000000000000000000000000000022100000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/core/impl/OdmManagerImplFactoryBean.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000641211475313376030122 0ustar package org.springframework.ldap.odm.core.impl; import java.util.Set; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.FactoryBeanNotInitializedException; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.odm.typeconversion.ConverterManager; /** * A Spring Factory bean which creates {@link OdmManagerImpl} instances. *

* Typical configuration would appear as follows: *

 *   <bean id="odmManager" class="org.springframework.ldap.odm.core.impl.OdmManagerImplFactoryBean">
 *       <property name="converterManager" ref="converterManager" />
 *       <property name="contextSource" ref="contextSource" />
 *       <property name="managedClasses">
 *           <set>
 *               <value>org.myorg.myldapentries.Person</value>
 *               <value>org.myorg.myldapentries.OrganizationalUnit</value>
 *           </set>
 *       </property>
 *   </bean>
 * 
* * @author Paul Harvey <paul.at.pauls-place.me.uk> */ public final class OdmManagerImplFactoryBean implements FactoryBean { private ContextSource contextSource=null; private Set> managedClasses=null; private ConverterManager converterManager=null; /** * Set the ContextSource to use to interact with the LDAP directory. * @param contextSource The ContextSource to use. */ public void setContextSource(ContextSource contextSource) { this.contextSource=contextSource; } /** * Set the list of {@link org.springframework.ldap.odm.annotations} * annotated classes the OdmManager will process. * @param managedClasses The list of classes to manage. */ public void setManagedClasses(Set> managedClasses) { this.managedClasses=managedClasses; } /** * Set the ConverterManager to use to convert between LDAP * and Java representations of attributes. * @param converterManager The ConverterManager to use. */ public void setConverterManager(ConverterManager converterManager) { this.converterManager=converterManager; } /* (non-Javadoc) * @see org.springframework.beans.factory.FactoryBean#getObject() */ public Object getObject() throws Exception { if (contextSource==null) { throw new FactoryBeanNotInitializedException("contextSource property has not been set"); } if (managedClasses==null) { throw new FactoryBeanNotInitializedException("managedClasses property has not been set"); } if (converterManager==null) { throw new FactoryBeanNotInitializedException("converterManager property has not been set"); } return new OdmManagerImpl(converterManager, contextSource, managedClasses); } /* (non-Javadoc) * @see org.springframework.beans.factory.FactoryBean#getObjectType() */ public Class getObjectType() { return OdmManagerImpl.class; } /* (non-Javadoc) * @see org.springframework.beans.factory.FactoryBean#isSingleton() */ public boolean isSingleton() { return true; } } ././@LongLink0000000000000000000000000000021100000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/core/impl/MetaDataException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000100611475313376030114 0ustar package org.springframework.ldap.odm.core.impl; import org.springframework.ldap.odm.core.OdmException; /** * Thrown to indicate an error in the annotated meta-data. * * @author Paul Harvey <paul.at.pauls-place.me.uk> * */ @SuppressWarnings("serial") public class MetaDataException extends OdmException { public MetaDataException(String message) { super(message); } public MetaDataException(String message, Throwable reason) { super(message, reason); } } ././@LongLink0000000000000000000000000000017000000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/typeconversion/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0002755000000000000000000000000011475313376030117 5ustar ././@LongLink0000000000000000000000000000021100000000000011557 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/typeconversion/package-info.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000046011475313376030117 0ustar /** * Provides an interface to be implemented to create a type conversion framework. *

* This is used to convert between the LDAP and Java representations of attributes. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ package org.springframework.ldap.odm.typeconversion; ././@LongLink0000000000000000000000000000021500000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/typeconversion/ConverterManager.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000234111475313376030117 0ustar package org.springframework.ldap.odm.typeconversion; /** * A simple interface to be implemented to provide type conversion functionality. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ public interface ConverterManager { /** * Determine whether this converter manager is able to carry out a specified conversion. * * @param fromClass Convert from the fromClass. * @param syntax Using the LDAP syntax (may be null). * @param toClass To the toClass. * @return True if the conversion is supported, false otherwise. */ boolean canConvert(Class fromClass, String syntax, Class toClass); /** * Convert a given source object with an optional LDAP syntax to an instance of a given class. * * @param The class to convert to. * @param source The object to convert. * @param syntax The LDAP syntax to use (may be null). * @param toClass The class to convert to. * @return The converted object. * * @throws ConverterException If the conversion can not be successfully completed. */ T convert(Object source, String syntax, Class toClass); } ././@LongLink0000000000000000000000000000021700000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/typeconversion/ConverterException.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000110511475313376030114 0ustar package org.springframework.ldap.odm.typeconversion; import org.springframework.ldap.NamingException; /** * Thrown by the conversion framework to indicate an error condition - typically a failed type conversion. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ @SuppressWarnings("serial") public final class ConverterException extends NamingException { public ConverterException(final String message) { super(message); } public ConverterException(final String message, final Throwable e) { super(message, e); } } ././@LongLink0000000000000000000000000000017500000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/typeconversion/impl/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0002755000000000000000000000000011475313376030117 5ustar ././@LongLink0000000000000000000000000000022600000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/typeconversion/impl/ConverterManagerImpl.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000001475511475313376030133 0ustar package org.springframework.ldap.odm.typeconversion.impl; import java.util.HashMap; import java.util.Map; import org.springframework.ldap.odm.typeconversion.ConverterException; import org.springframework.ldap.odm.typeconversion.ConverterManager; /** * An implementation of {@link org.springframework.ldap.odm.typeconversion.ConverterManager}. *

* The algorithm used is to: *

    *
  1. Try to find and use a {@link Converter} registered for the * fromClass, syntax and toClass and use it.
  2. *
  3. If this fails, then if the toClass isAssignableFrom * the fromClass then just assign it.
  4. *
  5. If this fails try to find and use a {@link Converter} registered for the fromClass and * the toClass ignoring the syntax.
  6. *
  7. If this fails then throw a {@link org.springframework.ldap.odm.typeconversion.ConverterException}.
  8. *
* * @author Paul Harvey <paul.at.pauls-place.me.uk> */ public final class ConverterManagerImpl implements ConverterManager { /** * Separator used to form keys into the converters Map. */ private static final String KEY_SEP = ":"; /** * Map of keys created via makeConverterKey to Converter instances. */ private final Map converters = new HashMap(); /** * Make a key into the converters map - the keys is formed from the fromClass, syntax and toClass * * @param fromClass The class to convert from. * @param syntax The LDAP syntax. * @param toClass The class to convert to. * @return key */ private String makeConverterKey(Class fromClass, String syntax, Class toClass) { StringBuilder key = new StringBuilder(); if (syntax==null) { syntax=""; } key.append(fromClass.getName()).append(KEY_SEP).append(syntax).append(KEY_SEP).append(toClass.getName()); return key.toString(); } /** * Create an empty ConverterManagerImpl */ public ConverterManagerImpl() { } /** * Used to help in the process of dealing with primitive types by mapping them to * their equivalent boxed class. */ private static Map, Class> primitiveTypeMap = new HashMap, Class>(); static { primitiveTypeMap.put(Byte.TYPE, Byte.class); primitiveTypeMap.put(Short.TYPE, Short.class); primitiveTypeMap.put(Integer.TYPE, Integer.class); primitiveTypeMap.put(Long.TYPE, Long.class); primitiveTypeMap.put(Float.TYPE, Float.class); primitiveTypeMap.put(Double.TYPE, Double.class); primitiveTypeMap.put(Boolean.TYPE, Boolean.class); primitiveTypeMap.put(Character.TYPE, Character.class); } /* * (non-Javadoc) * @see org.springframework.ldap.odm.typeconversion.ConverterManager#canConvert(java.lang.Class, java.lang.String, java.lang.Class) */ public boolean canConvert(Class fromClass, String syntax, Class toClass) { Class fixedToClass = toClass; if (toClass.isPrimitive()) { fixedToClass = primitiveTypeMap.get(toClass); } Class fixedFromClass = fromClass; if (fromClass.isPrimitive()) { fixedFromClass = primitiveTypeMap.get(fromClass); } return fixedToClass.isAssignableFrom(fixedFromClass) || (converters.get(makeConverterKey(fixedFromClass, syntax, fixedToClass)) != null) || (converters.get(makeConverterKey(fixedFromClass, null, fixedToClass)) != null); } /* * (non-Javadoc) * @see org.springframework.ldap.odm.typeconversion.ConverterManager#convert(java.lang.Object, java.lang.String, java.lang.Class) */ @SuppressWarnings("unchecked") public T convert(Object source, String syntax, Class toClass) { Object result = null; // What are we converting form Class fromClass = source.getClass(); // Deal with primitives Class targetClass = toClass; if (toClass.isPrimitive()) { targetClass = primitiveTypeMap.get(toClass); } // Try to convert with any syntax we have been given Converter syntaxConverter = converters.get(makeConverterKey(fromClass, syntax, targetClass)); if (syntaxConverter != null) { try { result = syntaxConverter.convert(source, targetClass); } catch (Exception e) { // Ignore as we may still be able to convert successfully } } // Do we actually need to do any conversion? if (result == null && targetClass.isAssignableFrom(fromClass)) { result = source; } // If we were given a syntax and we failed to convert drop back to any mapping // that will work from class -> to class if (result == null && syntax != null) { Converter nullSyntaxConverter = converters.get(makeConverterKey(fromClass, null, targetClass)); if (nullSyntaxConverter != null) { try { result = nullSyntaxConverter.convert(source, targetClass); } catch (Exception e) { // Handled at the end of the method } } } if (result == null) { throw new ConverterException(String.format( "Cannot convert %1$s of class %2$s via syntax %3$s to class %4$s", source, source.getClass(), syntax, toClass)); } // We cannot do the safe thing of doing a .cast as we need to rely on auto-unboxing to deal with primitives! return (T)result; } /** * Add a {@link Converter} to this ConverterManager. * * @param fromClass The class the Converter should be used to convert from. * @param syntax The LDAP syntax that the Converter should be used for. * @param toClass The class the Converter should be used to convert to. * @param converter The Converter to add. */ public void addConverter(Class fromClass, String syntax, Class toClass, Converter converter) { converters.put(makeConverterKey(fromClass, syntax, toClass), converter); } } ././@LongLink0000000000000000000000000000021600000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/typeconversion/impl/package-info.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000037311475313376030122 0ustar /** * Provides an implementation of the {@link org.springframework.ldap.odm.typeconversion.ConverterManager} interface. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ package org.springframework.ldap.odm.typeconversion.impl; ././@LongLink0000000000000000000000000000023500000000000011565 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/typeconversion/impl/ConverterManagerFactoryBean.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000001671711475313376030133 0ustar package org.springframework.ldap.odm.typeconversion.impl; import java.util.HashSet; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.FactoryBeanNotInitializedException; /** * A utility class to allow {@link ConverterManagerImpl} instances to be easily configured via spring.xml. *

* The following shows a typical simple example which creates two {@link Converter} instances: *

    *
  • fromStringConverter
  • *
  • toStringConverter
  • *
* Configured in an {@link ConverterManagerImpl} to: *
    *
  • Use fromStringConverter to convert from String to Byte, Short, * Integer, Long, Float, Double, Boolean
  • *
  • Use toStringConverter to convert from Byte, Short, * Integer, Long, Float, Double, Boolean to String
  • *
*
 * <bean id="converterManager" class="org.springframework.ldap.odm.typeconversion.impl.ConverterManagerFactoryBean">
 *   <property name="converterConfig">
 *     <set>
 *       <bean class="org.springframework.ldap.odm.typeconversion.impl.ConverterManagerFactoryBean$ConverterConfig">
 *         <property name="fromClasses">
 *           <set> 
 *             <value>java.lang.String</value>
 *           </set>
 *         </property>
 *         <property name="toClasses">
 *           <set>
 *             <value>java.lang.Byte</value>
 *             <value>java.lang.Short</value>
 *             <value>java.lang.Integer</value>
 *             <value>java.lang.Long</value>
 *             <value>java.lang.Float</value>
 *             <value>java.lang.Double</value>
 *             <value>java.lang.Boolean</value>
 *           </set>
 *         </property>
 *         <property name="converter" ref="fromStringConverter" />
 *       </bean>
 *       <bean class="org.springframework.ldap.odm.typeconversion.impl.ConverterManagerFactoryBean$ConverterConfig">
 *         <property name="fromClasses">
 *           <set>
 *             <value>java.lang.Byte</value>
 *             <value>java.lang.Short</value>
 *             <value>java.lang.Integer</value>
 *             <value>java.lang.Long</value>
 *             <value>java.lang.Float</value>
 *             <value>java.lang.Double</value>
 *             <value>java.lang.Boolean</value>
 *           </set> 
 *         </property>
 *         <property name="toClasses">
 *           <set> 
 *             <value>java.lang.String</value>
 *           </set>
 *         </property>
 *         <property name="converter" ref="toStringConverter" />
 *       </bean>
 *     </set>
 *   </property>
 * </bean>
 * 
* {@link ConverterConfig} has a second constructor which takes an additional parameter to allow * an LDAP syntax to be defined. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ public final class ConverterManagerFactoryBean implements FactoryBean { private static Log LOG = LogFactory.getLog(ConverterManagerFactoryBean.class); /** * Configuration information for a single Converter instance. */ public final static class ConverterConfig { // The set of classes the Converter will convert from. private Set> fromClasses = new HashSet>(); // The (optional) LDAP syntax. private String syntax=null; // The set of classes the Converter will convert to. private Set> toClasses = new HashSet>(); // The Converter to use. private Converter converter=null; public ConverterConfig() { } /** * @param fromClasses Comma separated list of classes the {@link Converter} should can convert from. */ public void setFromClasses(Set> fromClasses) { this.fromClasses=fromClasses; } /** * @param toClasses Comma separated list of classes the {@link Converter} can convert to. */ public void setToClasses(Set> toClasses) { this.toClasses=toClasses; } /** * @param syntax An LDAP syntax supported by the {@link Converter}. */ public void setSyntax(String syntax) { this.syntax=syntax; } /** * @param converter The {@link Converter} to use. */ public void setConverter(Converter converter) { this.converter=converter; } @Override public String toString() { return String.format("fromClasses=%1$s, syntax=%2$s, toClasses=%3$s, converter=%4$s", fromClasses, syntax, toClasses, converter); } } private Set converterConfigList=null; /** * @param converterConfigList */ public void setConverterConfig(Set converterConfigList) { this.converterConfigList=converterConfigList; } /** * Creates a ConverterManagerImpl populating it with Converter instances from the converterConfigList property. * * @return The newly created {@link org.springframework.ldap.odm.typeconversion.ConverterManager}. * @throws ClassNotFoundException Thrown if any of the classes to be converted to or from cannot be found. * * @see org.springframework.beans.factory.FactoryBean#getObject() */ public Object getObject() throws Exception { if (converterConfigList==null) { throw new FactoryBeanNotInitializedException("converterConfigList has not been set"); } ConverterManagerImpl result = new ConverterManagerImpl(); for (ConverterConfig converterConfig : converterConfigList) { if (converterConfig.fromClasses==null || converterConfig.toClasses==null || converterConfig.converter==null) { throw new FactoryBeanNotInitializedException( String.format("All of fromClasses, toClasses and converter must be specified in bean %1$s", converterConfig.toString())); } for (Class fromClass : converterConfig.fromClasses) { for (Class toClass : converterConfig.toClasses) { if (LOG.isDebugEnabled()) { LOG.debug(String.format("Adding converter from %1$s to %2$s", fromClass, toClass)); } result.addConverter(fromClass, converterConfig.syntax, toClass, converterConfig.converter); } } } return result; } /* (non-Javadoc) * @see org.springframework.beans.factory.FactoryBean#getObjectType() */ public Class getObjectType() { return ConverterManagerImpl.class; } /* (non-Javadoc) * @see org.springframework.beans.factory.FactoryBean#isSingleton() */ public boolean isSingleton() { return true; } } ././@LongLink0000000000000000000000000000021300000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/typeconversion/impl/Converter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000124411475313376030120 0ustar package org.springframework.ldap.odm.typeconversion.impl; /** * Interface specifying the conversion between two classes * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ public interface Converter { /** * Attempt to convert a given object to a named class. * * @param The class to convert to. * @param source The object to convert. * @param toClass The class to convert to. * @return The converted class or null if the conversion was not possible. * @throws Exception Any exception may be throw by a Converter on error. */ T convert(Object source, Class toClass) throws Exception; } ././@LongLink0000000000000000000000000000021000000000000011556 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/typeconversion/impl/converters/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0002755000000000000000000000000011475313376030117 5ustar ././@LongLink0000000000000000000000000000023600000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/typeconversion/impl/converters/ToStringConverter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000132411475313376030117 0ustar package org.springframework.ldap.odm.typeconversion.impl.converters; import org.springframework.ldap.odm.typeconversion.impl.Converter; /** * A Converter from any class to a {@link java.lang.String} via the toString method. *

* This should only be used as a fall-back converter, as a last attempt. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ public final class ToStringConverter implements Converter { /* (non-Javadoc) * @see org.springframework.ldap.odm.typeconversion.impl.Converter#convert(java.lang.Object, java.lang.Class) */ public T convert(Object source, Class toClass) { return toClass.cast(source.toString()); } } ././@LongLink0000000000000000000000000000024000000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/typeconversion/impl/converters/FromStringConverter.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000162511475313376030123 0ustar package org.springframework.ldap.odm.typeconversion.impl.converters; import java.lang.reflect.Constructor; import org.springframework.ldap.odm.typeconversion.impl.Converter; /** * A Converter from a {@link java.lang.String} to any class which has a single argument * public constructor taking a {@link java.lang.String}. *

* This should only be used as a fall-back converter, as a last attempt. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ public final class FromStringConverter implements Converter { /* (non-Javadoc) * @see org.springframework.ldap.odm.typeconversion.impl.Converter#convert(java.lang.Object, java.lang.Class) */ public T convert(Object source, Class toClass) throws Exception { Constructor constructor = toClass.getConstructor(java.lang.String.class); return constructor.newInstance(source); } } ././@LongLink0000000000000000000000000000023100000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/typeconversion/impl/converters/package-info.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000041111475313376030113 0ustar /** * Provides some basic implementations of the {@link org.springframework.ldap.odm.typeconversion.impl.Converter} interface. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ package org.springframework.ldap.odm.typeconversion.impl.converters;././@LongLink0000000000000000000000000000016500000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/annotations/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0002755000000000000000000000000011475313376030117 5ustar ././@LongLink0000000000000000000000000000017400000000000011567 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/annotations/Id.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000122111475313376030113 0ustar package org.springframework.ldap.odm.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * This annotation marks a Java field as containing the Distinguished Name of an LDAP Entry. *

* The marked field must be of type {@link javax.naming.Name} and must not * be annotated {@link Attribute}. * * @author Paul Harvey <paul.at.pauls-place.me.uk> * * @see Attribute * @see javax.naming.Name */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Id { } ././@LongLink0000000000000000000000000000020300000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/annotations/Transient.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000102211475313376030112 0ustar package org.springframework.ldap.odm.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * This annotation identifies a field in an {@link Entry} annotated class that * should not be persisted to LDAP. * * @author Paul Harvey * * @see Entry */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Transient { } ././@LongLink0000000000000000000000000000020300000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/annotations/Attribute.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000420011475313376030113 0ustar package org.springframework.ldap.odm.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * This annotation describes the mapping of a Java field to an LDAP attribute. *

* The containing class must be annotated with {@link Entry}. * * @author Paul Harvey <paul.at.pauls-place.me.uk> * @see Entry */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Attribute { /** * The Type attribute indicates whether a field is regarded as binary based * or string based by the LDAP JNDI provider. */ enum Type { /** * A string field - returned by the JNDI LDAP provider as a {@link java.lang.String}. */ STRING, /** * A binary field - returned by the JNDI LDAP provider as a byte[]. */ BINARY } /** * The LDAP attribute name that this field represents. *

* Defaults to "" in which case the Java field name is used as the LDAP attribute name. * * @return The LDAP attribute name. * */ String name() default ""; /** * Indicates whether this field is returned by the LDAP JNDI provider as a * String (Type.STRING) or as a * byte[] (Type.BINARY). * * @return Either Type.STRING to indicate a string attribute * or Type.BINARY to indicate a binary attribute. */ Type type() default Type.STRING; /** * The LDAP syntax of the attribute that this field represents. *

* This optional value is typically used to affect the precision of conversion * of values between LDAP and Java, * see {@link org.springframework.ldap.odm.typeconversion.ConverterManager} * and {@link org.springframework.ldap.odm.typeconversion.impl.ConverterManagerImpl}. * * @return The LDAP syntax of this attribute. */ String syntax() default ""; } ././@LongLink0000000000000000000000000000020600000000000011563 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/annotations/package-info.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000047311475313376030123 0ustar /** * Provides a set of annotations to describe the mapping of a Java class to an LDAP entry. *

* These annotations are for use with {@link org.springframework.ldap.odm.core.OdmManager}. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ package org.springframework.ldap.odm.annotations;././@LongLink0000000000000000000000000000017700000000000011572 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/annotations/Entry.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000141311475313376030116 0ustar package org.springframework.ldap.odm.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * This annotation marks a Java class to be persisted in an LDAP directory. * * @author Paul Harvey <paul.at.pauls-place.me.uk> * */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Entry { /** * A list of LDAP object classes that the annotated Java class represents. *

* All fields will be persisted to LDAP unless annotated {@link Transient}. * * @return A list of LDAP classes which the annotated Java class represents. */ String[] objectClasses(); } ././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/tools/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0002755000000000000000000000000011475313376030117 5ustar ././@LongLink0000000000000000000000000000020300000000000011560 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/tools/AttributeSchema.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000716711475313376030132 0ustar package org.springframework.ldap.odm.tools; /** * Simple value class to hold the schema of an attribute. *

* It is only public to allow Freemarker access. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ public final class AttributeSchema { private final String name; private final String syntax; private final boolean isMultiValued; private final boolean isPrimitive; private final String scalarType; private final boolean isBinary; private final boolean isArray; public AttributeSchema(final String name, final String syntax, final boolean isMultiValued, final boolean isPrimitive, final boolean isBinary, final boolean isArray, final String scalarType) { this.name = name; this.syntax = syntax; this.isMultiValued = isMultiValued; this.isPrimitive = isPrimitive; this.scalarType = scalarType; this.isBinary = isBinary; this.isArray = isArray; } public boolean getIsArray() { return isArray; } public boolean getIsBinary() { return isBinary; } public boolean getIsPrimitive() { return isPrimitive; } public String getScalarType() { return scalarType; } public String getName() { return name; } public String getSyntax() { return syntax; } public boolean getIsMultiValued() { return isMultiValued; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { return String.format( "{ name=%1$s, syntax=%2$s, isMultiValued=%3$s, isPrimitive=%4$s, isBinary=%5$s, isArray=%6$s, scalarType=%7$s }", name, syntax, isMultiValued, isPrimitive, isBinary, isArray, scalarType); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (isArray ? 1231 : 1237); result = prime * result + (isBinary ? 1231 : 1237); result = prime * result + (isMultiValued ? 1231 : 1237); result = prime * result + (isPrimitive ? 1231 : 1237); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((scalarType == null) ? 0 : scalarType.hashCode()); result = prime * result + ((syntax == null) ? 0 : syntax.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; AttributeSchema other = (AttributeSchema) obj; if (isArray != other.isArray) return false; if (isBinary != other.isBinary) return false; if (isMultiValued != other.isMultiValued) return false; if (isPrimitive != other.isPrimitive) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (scalarType == null) { if (other.scalarType != null) return false; } else if (!scalarType.equals(other.scalarType)) return false; if (syntax == null) { if (other.syntax != null) return false; } else if (!syntax.equals(other.syntax)) return false; return true; } } ././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/tools/SchemaViewer.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000002166711475313376030133 0ustar package org.springframework.ldap.odm.tools; import java.io.PrintStream; import java.util.Hashtable; import javax.naming.AuthenticationException; import javax.naming.CommunicationException; import javax.naming.Context; import javax.naming.NameClassPair; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; /** * A simple utility to list LDAP directory schema. *

* SchemaViewer takes the following flags: *

    *
  • -h,--help< Print this help message
  • *
  • -l,--url <arg> Ldap url of directory to bind to (defaults to ldap://127.0.0.1:389)
  • *
  • -u,--username <arg> DN to bind with (defaults to "")
  • *
  • -p,--password <arg> Password to bind with (defaults to "")
  • *
  • -o,--objectclass <arg> Object class name or ? for all. Print object class schema
  • *
  • -a,--attribute <arg> Attribute name or ? for all. Print attribute schema
  • *
  • -s,--syntax <arg> Syntax or ? for all. Print syntax
  • *
* * Only one of -a, -o and -s should be specified. * * @author Paul Harvey <paul.at.pauls-place.me.uk> * */ public final class SchemaViewer { private static final String DEFAULT_URL="ldap://127.0.0.1:389"; private enum Flag { URL("l", "url"), USERNAME("u", "username"), PASSWORD("p", "password"), OBJECTCLASS("o", "objectclass"), ATTRIBUTE("a", "attribute"), SYNTAX("s", "syntax"), HELP("h", "help"), ERROR("e", "error"); private String shortName; private String longName; private Flag(String shortName, String longName) { this.shortName = shortName; this.longName = longName; } public String getShort() { return shortName; } public String getLong() { return longName; } @Override public String toString() { return String.format("short=%1$s, long=%2$s", shortName, longName); } } private enum SchemaContext { OBJECTCLASS("ClassDefinition"), ATTRIBUTE("AttributeDefinition"), SYNTAX("SyntaxDefinition"); private String value; private SchemaContext(String value) { this.value = value; } public String getValue() { return value; } @Override public String toString() { return String.format("value=%1$s", value); } } private static final Options options = new Options(); static { options.addOption(Flag.URL.getShort(), Flag.URL.getLong(), true, "Ldap url (defaults to "+DEFAULT_URL+")"); options.addOption(Flag.USERNAME.getShort(), Flag.USERNAME.getLong(), true, "DN to bind with (defaults to \"\")"); options.addOption(Flag.PASSWORD.getShort(), Flag.PASSWORD.getLong(), true, "Password to bind with defaults to \"\")"); options.addOption(Flag.OBJECTCLASS.getShort(), Flag.OBJECTCLASS.getLong(), true, "Object class name or ? for all. Print object class schema"); options.addOption(Flag.ATTRIBUTE.getShort(), Flag.ATTRIBUTE.getLong(), true, "Attribute name or ? for all. Print attribute schema"); options.addOption(Flag.SYNTAX.getShort(), Flag.SYNTAX.getLong(), true, "Syntax OID or ? for all. Print attribute syntax"); options.addOption(Flag.HELP.getShort(), Flag.HELP.getLong(), false, "Print this help message"); options.addOption(Flag.ERROR.getShort(), Flag.ERROR.getLong(), false, "Send output to standard error"); } private static void printAttrs(Attributes attrs) throws NamingException { NamingEnumeration attrsEnum = attrs.getAll(); while (attrsEnum.hasMore()) { Attribute currentAttr = attrsEnum.next(); outstream.print(String.format("%1$s:", currentAttr.getID())); NamingEnumeration valuesEnum = currentAttr.getAll(); while (valuesEnum.hasMoreElements()) { outstream.print(String.format("%1$s ", valuesEnum.nextElement().toString())); } outstream.println(); } } private static void printObject(String contextName, String schemaName, DirContext schemaContext) throws NameNotFoundException, NamingException { DirContext oContext = (DirContext)schemaContext.lookup(contextName + "/" + schemaName); outstream.println("NAME:" + schemaName); printAttrs(oContext.getAttributes("")); } private static void printSchema(String contextName, DirContext schemaContext) throws NameNotFoundException, NamingException { outstream.println(); NamingEnumeration schemaList = schemaContext.list(contextName); while (schemaList.hasMore()) { NameClassPair ncp = schemaList.nextElement(); printObject(contextName, ncp.getName(), schemaContext); outstream.println(); } outstream.println(); } private static void print(String optionValue, String contextName, DirContext schemaContext) throws NameNotFoundException, NamingException { if (optionValue.equals(WILDCARD)) { printSchema(contextName, schemaContext); } else { printObject(contextName, optionValue, schemaContext); } } private static PrintStream outstream=System.out; private static String WILDCARD = "?"; public static void main(String[] argv) { CommandLineParser parser = new PosixParser(); CommandLine cmd = null; try { cmd = parser.parse(options, argv); } catch (ParseException e) { System.out.println(e.getMessage()); System.exit(1); } if (cmd.hasOption(Flag.HELP.getShort())) { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp(120, SchemaViewer.class.getSimpleName(), null, options, null, true); System.exit(0); } if (cmd.hasOption(Flag.ERROR.getShort())) { outstream=System.err; } String url = cmd.getOptionValue(Flag.URL.getShort(), DEFAULT_URL); String user = cmd.getOptionValue(Flag.USERNAME.getShort(), ""); String pass = cmd.getOptionValue(Flag.PASSWORD.getShort(), ""); Hashtable env = new Hashtable(); env.put(Context.PROVIDER_URL, url); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); if (user != null) { env.put(Context.SECURITY_PRINCIPAL, user); } if (pass != null) { env.put(Context.SECURITY_CREDENTIALS, pass); if (user == null) { System.err.println("You must specify a user if you specify a password"); System.exit(1); } } try { DirContext context = new InitialDirContext(env); DirContext schemaContext = context.getSchema(""); if (cmd.hasOption(Flag.OBJECTCLASS.getShort())) { print(cmd.getOptionValue(Flag.OBJECTCLASS.getShort()), SchemaContext.OBJECTCLASS.getValue(), schemaContext); } if (cmd.hasOption(Flag.ATTRIBUTE.getShort())) { print(cmd.getOptionValue(Flag.ATTRIBUTE.getShort()), SchemaContext.ATTRIBUTE.getValue(), schemaContext); } if (cmd.hasOption(Flag.SYNTAX.getShort())) { print(cmd.getOptionValue(Flag.SYNTAX.getShort()), SchemaContext.SYNTAX.getValue(), schemaContext); } } catch (AuthenticationException e) { System.err.println(String.format("Failed to bind to ldap server at %1$s", url)); } catch (CommunicationException e) { System.err.println(String.format("Failed to contact ldap server at %1$s", url)); } catch (NameNotFoundException e) { System.err.println(String.format("Can't find object %1$s", e.getMessage())); } catch (NamingException e) { System.err.println(e.toString()); } } } ././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/tools/package-info.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000037011475313376030117 0ustar /** * Provides a tool to create a Java class representation of a set of LDAP object classes * and a simple tool to view LDAP schema. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ package org.springframework.ldap.odm.tools;././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/tools/ObjectSchema.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000512211475313376030117 0ustar package org.springframework.ldap.odm.tools; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** * Simple value class to hold the schema of an object class *

* It is public only to allow Freemarker access. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ public final class ObjectSchema { private final Set must = new HashSet(); private final Set may = new HashSet(); private final Set objectClass = new HashSet(); public void addMust(AttributeSchema must) { this.must.add(must); } public void addMay(AttributeSchema may) { this.may.add(may); } public void addObjectClass(String objectClass) { this.objectClass.add(objectClass); } public Set getMust() { return Collections.unmodifiableSet(must); } public Set getMay() { return Collections.unmodifiableSet(may); } public Set getObjectClass() { return Collections.unmodifiableSet(objectClass); } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { return String.format("objectClass=%1$s | must=%2$s | may=%3$s", objectClass, must, may); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((may == null) ? 0 : may.hashCode()); result = prime * result + ((must == null) ? 0 : must.hashCode()); result = prime * result + ((objectClass == null) ? 0 : objectClass.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ObjectSchema other = (ObjectSchema) obj; if (may == null) { if (other.may != null) return false; } else if (!may.equals(other.may)) return false; if (must == null) { if (other.must != null) return false; } else if (!must.equals(other.must)) return false; if (objectClass == null) { if (other.objectClass != null) return false; } else if (!objectClass.equals(other.objectClass)) return false; return true; } } ././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/tools/SchemaReader.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000001403711475313376030124 0ustar package org.springframework.ldap.odm.tools; import java.util.HashSet; import java.util.Set; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import org.springframework.ldap.odm.tools.SyntaxToJavaClass.ClassInfo; // Processes LDAP Schema /* package */ final class SchemaReader { private final DirContext schemaContext; private final SyntaxToJavaClass syntaxToJavaClass; private final Set binarySet; public SchemaReader(DirContext schemaContext, SyntaxToJavaClass syntaxToJavaClass, Set binarySet) { this.schemaContext = schemaContext; this.syntaxToJavaClass = syntaxToJavaClass; this.binarySet = binarySet; } // Get the object schema for the given object classes public ObjectSchema getObjectSchema(Set objectClasses) throws NamingException, ClassNotFoundException { ObjectSchema result = new ObjectSchema(); createObjectClass(objectClasses, schemaContext, result); return result; } private enum SchemaAttributeType { SUP, MUST, MAY, UNKNOWN } private SchemaAttributeType getSchemaAttributeType(String type) { SchemaAttributeType result = SchemaAttributeType.UNKNOWN; if (type.equals("SUP")) { result = SchemaAttributeType.SUP; } else { if (type.equals("MUST")) { result = SchemaAttributeType.MUST; } else { if (type.equals("MAY")) { result = SchemaAttributeType.MAY; } } } return result; } private AttributeSchema createAttributeSchema(String name, DirContext schemaContext) throws NamingException, ClassNotFoundException { // Get the schema definition Attributes attributeSchema = schemaContext.getAttributes("AttributeDefinition/" + name); // Get the syntax - ditching any trailing length value that { and whatever follows it String syntax = ((String)attributeSchema.get("SYNTAX").get()).split("\\{")[0]; // Is it binary? boolean isBinary=binarySet.contains(syntax); // Use it to look up the required Java class ClassInfo classInfo = syntaxToJavaClass.getClassInfo(syntax); // Now we can set the java class String javaClassName = null; boolean isPrimitive = false; boolean isArray = false; if (classInfo!=null) { javaClassName=classInfo.getClassName(); Class javaClass=Class.forName(classInfo.getFullClassName()); javaClassName=javaClass.getSimpleName(); isPrimitive=javaClass.isPrimitive(); isArray=javaClass.isArray(); } else { if (isBinary) { javaClassName="byte[]"; isPrimitive=false; isArray=true; } else { javaClassName="String"; isPrimitive=false; isArray=false; } } return new AttributeSchema(name, syntax, attributeSchema.get("SINGLE-VALUE") == null, isPrimitive, isBinary, isArray, javaClassName); } // Recursively extract schema from the directory and process it private void createObjectClass(Set objectClasses, DirContext schemaContext, ObjectSchema schema) throws NamingException, ClassNotFoundException { // Super classes Set supList = new HashSet(); // For each of the given object classes for (String objectClass : objectClasses) { // Add to set of included object classes schema.addObjectClass(objectClass); // Grab the LDAP schema of the object class Attributes attributes = schemaContext.getAttributes("ClassDefinition/" + objectClass); NamingEnumeration valuesEnumeration = attributes.getAll(); // Loop through each of the attributes while (valuesEnumeration.hasMoreElements()) { Attribute currentAttribute = valuesEnumeration.nextElement(); // Get the attribute name and lower case it (as this is all case indep) String currentId = currentAttribute.getID().toUpperCase(); // Is this a MUST, MAY or SUP attribute SchemaAttributeType type = getSchemaAttributeType(currentId); // Loop through all the values NamingEnumeration currentValues = currentAttribute.getAll(); while (currentValues.hasMoreElements()) { String currentValue = (String)currentValues.nextElement(); switch (type) { case SUP: // Its a super class String lowerCased=currentValue.toLowerCase(); if (!schema.getObjectClass().contains(lowerCased)) { supList.add(lowerCased); } break; case MUST: // Add must attribute schema.addMust(createAttributeSchema(currentValue, schemaContext)); break; case MAY: // Add may attribute schema.addMay(createAttributeSchema(currentValue, schemaContext)); break; default: // Nothing to do } } } // Recurse for super classes createObjectClass(supList, schemaContext, schema); } } } ././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/tools/SchemaToJava.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000004466211475313376030133 0ustar package org.springframework.ldap.odm.tools; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.URL; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.naming.Context; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.Template; import freemarker.template.TemplateException; /** * This tool creates a Java class representation of a set of LDAP object classes for use * with {@link org.springframework.ldap.odm.core.OdmManager}. *

* The schema of a named list of object classes is read from an LDAP directory and used * to generate a representative Java class. The Java class is automatically annotated with * {@link org.springframework.ldap.odm.annotations} for use with * {@link org.springframework.ldap.odm.core.OdmManager}. *

* The mapping of LDAP attributes to their Java representations may be configured by supplying the * -s flag or the equivalent --syntaxmap flag whose argument is * the name of a file with the following structure: *

 * # List of attribute syntax to java class mappings
 *
 * # Syntax                       Java class
 * # ------                       ----------
 *
 * 1.3.6.1.4.1.1466.115.121.1.50, java.lang.Integer
 * 1.3.6.1.4.1.1466.115.121.1.40, some.other.Class
 * 
*

* Syntaxes not included in this map will be represented as {@link java.lang.String} if they are returned as Strings by the * JNDI LDAP provider and will be represented as byte[] if they are returned by the provider as byte[]. *

* Command line flags are as follows: *

*

    *
  • -c,--class <class name> Name of the Java class to create. Mandatory.
  • *
  • -s,--syntaxmap <map file> Configuration file of LDAP syntaxes to Java classes mappings. Optional.
  • *
  • -h,--help Print this help message then exit.
  • *
  • -k,--package <package name> Package to create the Java class in. Mandatory.
  • *
  • -l,--url <ldap url> Ldap url of the directory service to bind to. Defaults to ldap://127.0.0.1:389. Optional.
  • *
  • -o,--objectclasses <LDAP object class lists> Comma separated list of LDAP object classes. Mandatory.
  • *
  • -u,--username <dn> DN to bind with. Defaults to "". Optional.
  • *
  • -p,--password <password> Password to bind with. Defaults to "". Optional.
  • *
  • -t,--outputdir <output directory> Base output directory, defaults to ".". Optional.
  • *
* * @author Paul Harvey <paul.at.pauls-place.me.uk> * */ public final class SchemaToJava { private static Log LOG = LogFactory.getLog(SchemaToJava.class); // Name of the FreeMarker template used to generate the Java code. private static String TEMPLATE_FILE = "oc-to-java.ftl"; // Name of file containing the list of attributes syntaxes to // returned as byte[] by the JNDI LDAP provider. private static String BINARY_FILE = "binary-attributes.txt"; // Class to use a base for loading resources private static final Class loaderClass=SchemaToJava.class; // Default LDAP Url to bind with private static final String DEFAULT_URL="ldap://127.0.0.1:389"; // Command line flags private enum Flag { URL("l", "url"), USERNAME("u", "username"), PASSWORD("p", "password"), OBJECTCLASS("o", "objectclasses"), CLASS("c", "class"), PACKAGE("k", "package"), SYNTAX_MAP("s", "syntaxmap"), OUTPUT_DIR("t", "outputdir"), HELP("h", "help"); private String shortName; private String longName; private Flag(String shortName, String longName) { this.shortName = shortName; this.longName = longName; } public String getShort() { return shortName; } public String getLong() { return longName; } @Override public String toString() { return String.format("short=%1$s, long=%2$s", shortName, longName); } } private static final Options options = new Options(); static { options.addOption(Flag.URL.getShort(), Flag.URL.getLong(), true, "Ldap url (defaults to "+DEFAULT_URL+")"); options.addOption(Flag.USERNAME.getShort(), Flag.USERNAME.getLong(), true, "DN to bind with (defaults to \"\""); options.addOption(Flag.PASSWORD.getShort(), Flag.PASSWORD.getLong(), true, "Password to bind with (defaults to \"\""); options.addOption(Flag.OBJECTCLASS.getShort(), Flag.OBJECTCLASS.getLong(), true, "Comma separated list of object classes"); options.addOption(Flag.CLASS.getShort(), Flag.CLASS.getLong(), true, "Name of the Java class to create"); options.addOption(Flag.PACKAGE.getShort(), Flag.PACKAGE.getLong(), true, "Package to create the Java class in"); options.addOption(Flag.SYNTAX_MAP.getShort(), Flag.SYNTAX_MAP.getLong(), true, "Syntax map file (optional)"); options.addOption(Flag.OUTPUT_DIR.getShort(), Flag.OUTPUT_DIR.getLong(), true, "Base output directory (defaults to .)"); options.addOption(Flag.HELP.getShort(), Flag.HELP.getLong(), false, "Print this help message"); } // Read list of LDAP syntaxes that are returned as byte[] private static Set readBinarySet(File binarySetFile) throws IOException { Set result = new HashSet(); BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(binarySetFile)); String line; while ((line = reader.readLine()) != null) { String trimmed = line.trim(); if (trimmed.length() > 0) { if (trimmed.charAt(0) != '#') { String[] parts = trimmed.split("\\s"); if (parts.length > 0) { result.add(parts[0]); } } } } } finally { if (reader != null) { reader.close(); } } return result; } // Read mappings of LDAP syntaxes to Java classes. private static Map readSyntaxMap(File syntaxMapFile) throws IOException { Map result = new HashMap(); BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(syntaxMapFile)); String line; while ((line = reader.readLine()) != null) { String trimmed = line.trim(); if (trimmed.length() > 0) { if (trimmed.charAt(0) != '#') { String[] parts = trimmed.split(","); if (parts.length != 2) { throw new IOException(String.format("Failed to parse line \"%1$s\"", trimmed)); } String partOne = parts[0].trim(); String partTwo = parts[1].trim(); if (partOne.length() == 0 || partTwo.length() == 0) { throw new IOException(String.format("Failed to parse line \"%1$s\"", trimmed)); } result.put(partOne, partTwo); } } } } finally { if (reader != null) { reader.close(); } } return result; } // Bind to the directory, read and process the schema private static ObjectSchema readSchema(String url, String user, String pass, SyntaxToJavaClass syntaxToJavaClass, Set binarySet, Set objectClasses) throws NamingException, ClassNotFoundException { // Set up environment Hashtable env = new Hashtable(); env.put(Context.PROVIDER_URL, url); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); if (user != null) { env.put(Context.SECURITY_PRINCIPAL, user); } if (pass != null) { env.put(Context.SECURITY_CREDENTIALS, pass); } DirContext context = new InitialDirContext(env); DirContext schemaContext = context.getSchema(""); SchemaReader reader = new SchemaReader(schemaContext, syntaxToJavaClass, binarySet); ObjectSchema schema = reader.getObjectSchema(objectClasses); if (LOG.isDebugEnabled()) { LOG.debug(String.format("Schema - %1$s", schema.toString())); } return schema; } // Create the Java private static void createCode(String packageName, String className, ObjectSchema schema, Set imports, File outputFile) throws IOException, TemplateException { Configuration freeMarkerConfiguration = new Configuration(); freeMarkerConfiguration.setClassForTemplateLoading(loaderClass, ""); freeMarkerConfiguration.setObjectWrapper(new DefaultObjectWrapper()); // Build the model for FreeMarker Map model = new HashMap(); model.put("package", packageName); model.put("class", className); model.put("schema", schema); model.put("imports", imports); // Have FreeMarker process the model with the template Template template = freeMarkerConfiguration.getTemplate(TEMPLATE_FILE); if (LOG.isDebugEnabled()) { Writer out = new OutputStreamWriter(System.out); template.process(model, out); out.flush(); } LOG.debug(String.format("Writing java to: %1$s", outputFile.getAbsolutePath())); FileOutputStream outputStream=new FileOutputStream(outputFile); Writer out = new OutputStreamWriter(outputStream); template.process(model, out); out.flush(); out.close(); } // Create the output file for the generated code along with all intervening directories private static File makeOutputFile(String outputDir, String packageName, String className) throws IOException { // Convert the package name to a path Pattern pattern=Pattern.compile("\\."); Matcher matcher=pattern.matcher(packageName); String sepToUse=File.separator; if (sepToUse.equals("\\")) { sepToUse="\\\\"; } // Try to create the necessary directories String directoryPath=outputDir+File.separator+matcher.replaceAll(sepToUse); File directory=new File(directoryPath); File outputFile=new File(directory, className+".java"); LOG.debug(String.format("Attempting to create output file at %1$s", outputFile.getAbsolutePath())); try { directory.mkdirs(); outputFile.createNewFile(); } catch (SecurityException se) { throw new IOException(String.format("Can't write to output file %1$s", outputFile.getAbsoluteFile())); } catch (IOException ioe) { throw new IOException(String.format("Can't write to output file %1$s", outputFile.getAbsoluteFile())); } return outputFile; } private static Set parseObjectClassesFlag(String objectClassesFlag) { Set objectClasses = new HashSet(); for (String objectClassFlag : objectClassesFlag.split(",")) { if (objectClassFlag.length() > 0) { objectClasses.add(objectClassFlag.toLowerCase().trim()); } } return objectClasses; } private static void error(String message) { System.err.println(String.format("%1$s: %2$s", SchemaToJava.class.getSimpleName(), message)); System.exit(1); } public static void main(String[] argv) { CommandLineParser parser = new PosixParser(); CommandLine cmd = null; // Parse out the command line options try { cmd = parser.parse(options, argv); } catch (ParseException e) { error(e.toString()); } // If the help flag is specified ignore other flags, print a usage message and exit if (cmd.hasOption(Flag.HELP.getShort())) { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp(120, SchemaToJava.class.getSimpleName(), null, options, null, true); System.exit(0); } // Class name flag String className = cmd.getOptionValue(Flag.CLASS.getShort()); if (className == null) { error("You must specify the name of a Java class to create"); } // Package name flag String packageName = cmd.getOptionValue(Flag.PACKAGE.getShort()); if (packageName == null) { error("You must specifiy a package name"); } // Output base directory String outputDir = cmd.getOptionValue(Flag.OUTPUT_DIR.getShort(), "."); File outputFile = null; try { outputFile = makeOutputFile(outputDir, packageName, className); } catch (IOException e) { error(e.toString()); } // Get the flags we need to bind to the directory String url = cmd.getOptionValue(Flag.URL.getShort(), DEFAULT_URL); String user = cmd.getOptionValue(Flag.USERNAME.getShort()); String pass = cmd.getOptionValue(Flag.PASSWORD.getShort()); // Parse out object classes String objectClassesFlag = cmd.getOptionValue(Flag.OBJECTCLASS.getShort()); if (objectClassesFlag==null) { error("You must specificy a package name"); } Set objectClasses = parseObjectClassesFlag(objectClassesFlag); if (objectClasses.size()==0) { error("You must specificy a package name"); } // Look for the optional syntax to Java class mapping file String syntaxMapFileName = cmd.getOptionValue(Flag.SYNTAX_MAP.getShort(), null); SyntaxToJavaClass syntaxToJavaClass=new SyntaxToJavaClass(new HashMap()); if (syntaxMapFileName!=null) { File syntaxMapFile=new File(syntaxMapFileName); if (syntaxMapFile.canRead()) { try { syntaxToJavaClass = new SyntaxToJavaClass(readSyntaxMap(syntaxMapFile)); } catch (IOException e) { error(String.format("Error reading syntax map file %1$s - %2$s", syntaxMapFile.getAbsolutePath(), e.toString())); } } else { error(String.format("Cannot read syntax map file %s$1", syntaxMapFile.getAbsolutePath())); } } // Read binary mapping file URL binarySetUrl=loaderClass.getResource(BINARY_FILE); if (binarySetUrl==null) { error(String.format("Can't locatate binary mappings file %1$s", BINARY_FILE)); } File binarySetFile=new File(binarySetUrl.getFile()); if (!binarySetFile.canRead()) { error(String.format("Can't read from binary mappings file %1$s", BINARY_FILE)); } Set binarySet = null; try { binarySet = readBinarySet(binarySetFile); } catch (IOException e) { error(String.format("Error reading binary set file %1$s - %2$s", binarySetFile.getAbsolutePath(), e)); } // Read schema from the directory ObjectSchema schema=null; try { schema=readSchema(url, user, pass, syntaxToJavaClass, binarySet, objectClasses); } catch (NamingException ne) { error(String.format("Error processing schema - %1$s", ne)); } catch (ClassNotFoundException cnfe) { error(String.format("Error processing schema - %1$s", cnfe)); } // Work out what imports we need Set imports = new HashSet(); for (AttributeSchema attributeSchema : schema.getMay()) { SyntaxToJavaClass.ClassInfo classInfo = syntaxToJavaClass.getClassInfo(attributeSchema.getSyntax()); if (classInfo != null) { String classPackageName = classInfo.getPackageName(); if (classPackageName != null && classPackageName.length() > 0) { imports.add(classInfo); } } } // Create the Java code try { createCode(packageName, className, schema, imports, outputFile); } catch (TemplateException te) { error(String.format("Error generating code - %1$s", te.toString())); } catch (IOException ioe) { error(String.format("Error generatign code - %1$s", ioe.toString())); } } } ././@LongLink0000000000000000000000000000020500000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/odm/tools/SyntaxToJavaClass.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-odm/org/springframework/ldap/0000644000000000000000000000407611475313376030126 0ustar package org.springframework.ldap.odm.tools; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; /** * A map from an LDAP syntax to the Java class used to represent it. * * @author Paul Harvey <paul.at.pauls-place.me.uk> */ /* package */ final class SyntaxToJavaClass { public final static class ClassInfo { private final String className; private final String packageName; private ClassInfo(String className, String packageName) { this.className = className; this.packageName = packageName; } public String getClassName() { return className; } public String getPackageName() { return packageName; } public String getFullClassName() { StringBuilder result=new StringBuilder(); if (packageName!=null) { result.append(packageName).append(".").append(className); } else { result.append(className); } return result.toString(); } } private final Map mapSyntaxToClassInfo = new HashMap(); public SyntaxToJavaClass(Map mapSyntaxToClass) { for (Entry syntaxAndClass : mapSyntaxToClass.entrySet()) { String fullClassName = syntaxAndClass.getValue().trim(); String packageName = null; String className = null; int lastDotIndex = fullClassName.lastIndexOf('.'); if (lastDotIndex != -1) { className = fullClassName.substring(lastDotIndex + 1); packageName = fullClassName.substring(0, lastDotIndex); } else { className = fullClassName; } mapSyntaxToClassInfo.put(syntaxAndClass.getKey(), new ClassInfo(className, packageName)); } } public ClassInfo getClassInfo(String syntax) { return mapSyntaxToClassInfo.get(syntax); } } libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/0002755000000000000000000000000011475313376023370 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/0002755000000000000000000000000011475313376024157 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/0002755000000000000000000000000011475313376027377 5ustar ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap0002755000000000000000000000000011475313376030240 5ustar ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap/test/libspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap0002755000000000000000000000000011475313376030240 5ustar ././@LongLink0000000000000000000000000000021400000000000011562 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap/test/TestContextSourceFactoryBean.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap0000644000000000000000000000772411475313376030252 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.test; import java.util.HashSet; import java.util.Set; import org.apache.directory.server.core.schema.bootstrap.NisSchema; import org.springframework.beans.factory.config.AbstractFactoryBean; import org.springframework.core.io.Resource; import org.springframework.ldap.core.AuthenticationSource; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.support.DefaultDirObjectFactory; import org.springframework.ldap.core.support.LdapContextSource; /** * @author Mattias Hellborg Arthursson */ public class TestContextSourceFactoryBean extends AbstractFactoryBean { private int port; private String defaultPartitionSuffix; private String defaultPartitionName; private String principal; private String password; private boolean baseOnTarget = true; private Resource ldifFile; private Class dirObjectFactory = DefaultDirObjectFactory.class; private boolean pooled = true; private AuthenticationSource authenticationSource; public void setAuthenticationSource(AuthenticationSource authenticationSource) { this.authenticationSource = authenticationSource; } public void setPooled(boolean pooled) { this.pooled = pooled; } public void setDirObjectFactory(Class dirObjectFactory) { this.dirObjectFactory = dirObjectFactory; } public void setLdifFile(Resource ldifFile) { this.ldifFile = ldifFile; } public void setBaseOnTarget(boolean baseOnTarget) { this.baseOnTarget = baseOnTarget; } public void setDefaultPartitionSuffix(String defaultPartitionSuffix) { this.defaultPartitionSuffix = defaultPartitionSuffix; } public void setPrincipal(String principal) { this.principal = principal; } public void setPassword(String password) { this.password = password; } public void setDefaultPartitionName(String defaultPartitionName) { this.defaultPartitionName = defaultPartitionName; } public void setPort(int port) { this.port = port; } protected Object createInstance() throws Exception { Set extraSchemas = new HashSet(); extraSchemas.add(new NisSchema()); LdapTestUtils.startApacheDirectoryServer(port, defaultPartitionSuffix, defaultPartitionName, principal, password, extraSchemas); LdapContextSource targetContextSource = new LdapContextSource(); if (baseOnTarget) { targetContextSource.setBase(defaultPartitionSuffix); } targetContextSource.setUrl("ldap://localhost:" + port); targetContextSource.setUserDn(principal); targetContextSource.setPassword(password); targetContextSource.setDirObjectFactory(dirObjectFactory); targetContextSource.setPooled(pooled); if (authenticationSource != null) { targetContextSource.setAuthenticationSource(authenticationSource); } targetContextSource.afterPropertiesSet(); if (baseOnTarget) { LdapTestUtils.clearSubContexts(targetContextSource, DistinguishedName.EMPTY_PATH); } else { LdapTestUtils.clearSubContexts(targetContextSource, new DistinguishedName(defaultPartitionSuffix)); } if (ldifFile != null) { LdapTestUtils.loadLdif(targetContextSource, ldifFile); } return targetContextSource; } public Class getObjectType() { return ContextSource.class; } protected void destroyInstance(Object instance) throws Exception { super.destroyInstance(instance); LdapTestUtils.destroyApacheDirectoryServer(principal, password); } } ././@LongLink0000000000000000000000000000017500000000000011570 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap/test/LdapTestUtils.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap0000644000000000000000000002237411475313376030250 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.test; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.Hashtable; import java.util.Properties; import java.util.Set; import javax.naming.Binding; import javax.naming.Context; import javax.naming.ContextNotEmptyException; import javax.naming.InitialContext; import javax.naming.Name; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import org.apache.commons.io.IOUtils; import org.apache.directory.server.configuration.MutableServerStartupConfiguration; import org.apache.directory.server.core.configuration.ShutdownConfiguration; import org.apache.directory.server.core.partition.impl.btree.MutableBTreePartitionConfiguration; import org.apache.directory.server.jndi.ServerContextFactory; import org.apache.directory.server.protocol.shared.store.LdifFileLoader; import org.springframework.core.io.Resource; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DistinguishedName; /** * Utilities for starting, stopping and populating an in-process Apache * Directory Server to use for integration testing purposes. * * @author Mattias Hellborg Arthursson */ public class LdapTestUtils { public static final String DEFAULT_PRINCIPAL = "uid=admin,ou=system"; public static final String DEFAULT_PASSWORD = "secret"; /** * Not to be instantiated. */ private LdapTestUtils() { } /** * Start an in-process Apache Directory Server. * * @param port the port on which the server will be listening. * @param defaultPartitionSuffix The default base suffix that will be used * for the LDAP server. * @param defaultPartitionName The name to use in the directory server * configuration for the default base suffix. * @param principal The principal to use when starting the directory server. * @param credentials The credentials to use when starting the directory * server. * @param extraSchemas Set of extra schemas to add to the bootstrap schemas * of ApacheDS. May be null. * @return A DirContext to be used for working against the started directory * server. * @throws NamingException If anything goes wrong when starting the server. */ public static DirContext startApacheDirectoryServer(int port, String defaultPartitionSuffix, String defaultPartitionName, String principal, String credentials, Set extraSchemas) throws NamingException { MutableServerStartupConfiguration cfg = new MutableServerStartupConfiguration(); // Determine an appropriate working directory String tempDir = System.getProperty("java.io.tmpdir"); cfg.setWorkingDirectory(new File(tempDir)); cfg.setLdapPort(port); if (extraSchemas != null) { Set schemas = cfg.getBootstrapSchemas(); schemas.addAll(extraSchemas); cfg.setBootstrapSchemas(schemas); } MutableBTreePartitionConfiguration partitionConfiguration = new MutableBTreePartitionConfiguration(); partitionConfiguration.setSuffix(defaultPartitionSuffix); partitionConfiguration.setContextEntry(getRootPartitionAttributes(defaultPartitionName)); partitionConfiguration.setName(defaultPartitionName); cfg.setContextPartitionConfigurations(Collections.singleton(partitionConfiguration)); // Start the Server Hashtable env = createEnv(principal, credentials); env.putAll(cfg.toJndiEnvironment()); return new InitialDirContext(env); } public static DirContext startApacheDirectoryServer(int port, String defaultPartitionSuffix, String defaultPartitionName, String principal, String credentials) throws NamingException { return LdapTestUtils.startApacheDirectoryServer(port, defaultPartitionSuffix, defaultPartitionName, principal, credentials, null); } /** * Shut down the in-process Apache Directory Server. * * @param principal the principal to be used for authentication. * @param credentials the credentials to be used for authentication. * @throws Exception If anything goes wrong when shutting down the server. */ public static void destroyApacheDirectoryServer(String principal, String credentials) throws Exception { Properties env = new Properties(); env.setProperty(Context.INITIAL_CONTEXT_FACTORY, ServerContextFactory.class.getName()); env.setProperty(Context.SECURITY_AUTHENTICATION, "simple"); env.setProperty(Context.SECURITY_PRINCIPAL, principal); env.setProperty(Context.SECURITY_CREDENTIALS, credentials); ShutdownConfiguration configuration = new ShutdownConfiguration(); env.putAll(configuration.toJndiEnvironment()); new InitialContext(env); } /** * Clear the directory sub-tree starting with the node represented by the * supplied distinguished name. * * @param contextSource the ContextSource to use for getting a DirContext. * @param name the distinguished name of the root node. * @throws NamingException if anything goes wrong removing the sub-tree. */ public static void clearSubContexts(ContextSource contextSource, Name name) throws NamingException { DirContext ctx = null; try { ctx = contextSource.getReadWriteContext(); clearSubContexts(ctx, name); } finally { try { ctx.close(); } catch (Exception e) { // Never mind this } } } /** * Clear the directory sub-tree starting with the node represented by the * supplied distinguished name. * * @param ctx The DirContext to use for cleaning the tree. * @param name the distinguished name of the root node. * @throws NamingException if anything goes wrong removing the sub-tree. */ public static void clearSubContexts(DirContext ctx, Name name) throws NamingException { NamingEnumeration enumeration = null; try { enumeration = ctx.listBindings(name); while (enumeration.hasMore()) { Binding element = (Binding) enumeration.next(); DistinguishedName childName = new DistinguishedName(element.getName()); childName.prepend((DistinguishedName) name); try { ctx.destroySubcontext(childName); } catch (ContextNotEmptyException e) { clearSubContexts(ctx, childName); ctx.destroySubcontext(childName); } } } catch (NamingException e) { e.printStackTrace(); } finally { try { enumeration.close(); } catch (Exception e) { // Never mind this } } } /** * Load an Ldif file into an LDAP server. * * @param contextSource ContextSource to use for getting a DirContext to * interact with the LDAP server. * @param ldifFile a Resource representing a valid LDIF file. * @throws IOException if the Resource cannot be read. */ public static void loadLdif(ContextSource contextSource, Resource ldifFile) throws IOException { DirContext context = contextSource.getReadWriteContext(); try { loadLdif(context, ldifFile); } finally { try { context.close(); } catch (Exception e) { // This is not the exception we are interested in. } } } public static void cleanAndSetup(ContextSource contextSource, DistinguishedName rootNode, Resource ldifFile) throws NamingException, IOException { clearSubContexts(contextSource, rootNode); loadLdif(contextSource, ldifFile); } private static void loadLdif(DirContext context, Resource ldifFile) throws IOException { File tempFile = File.createTempFile("spring_ldap_test", ".ldif"); try { InputStream inputStream = ldifFile.getInputStream(); IOUtils.copy(inputStream, new FileOutputStream(tempFile)); LdifFileLoader fileLoader = new LdifFileLoader(context, tempFile.getAbsolutePath()); fileLoader.execute(); } finally { try { tempFile.delete(); } catch (Exception e) { // Ignore this } } } private static Hashtable createEnv(String principal, String credentials) { Hashtable env = new Properties(); env.put(Context.PROVIDER_URL, ""); env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.directory.server.jndi.ServerContextFactory"); env.put(Context.SECURITY_PRINCIPAL, principal); env.put(Context.SECURITY_CREDENTIALS, credentials); env.put(Context.SECURITY_AUTHENTICATION, "simple"); return env; } private static Attributes getRootPartitionAttributes(String defaultPartitionName) { BasicAttributes attributes = new BasicAttributes(); BasicAttribute objectClassAttribute = new BasicAttribute("objectClass"); objectClassAttribute.add("top"); objectClassAttribute.add("domain"); objectClassAttribute.add("extensibleObject"); attributes.put(objectClassAttribute); attributes.put("dc", defaultPartitionName); return attributes; } } ././@LongLink0000000000000000000000000000016700000000000011571 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap/test/package.htmllibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap0000644000000000000000000000014711475313376030242 0ustar Utilities to simplify integration testing against LDAP targets. ././@LongLink0000000000000000000000000000021600000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap/test/AttributeCheckAttributesMapper.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap0000644000000000000000000000463511475313376030250 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.test; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import org.springframework.ldap.core.AttributesMapper; import junit.framework.Assert; /** * Dummy AttributesMapper for testing purposes to check that the received * Attributes are the expected ones. * * @author Mattias Hellborg Arthursson */ public class AttributeCheckAttributesMapper implements AttributesMapper { private String[] expectedAttributes = new String[0]; private String[] expectedValues = new String[0];; private String[] absentAttributes = new String[0];; public Object mapFromAttributes(Attributes attributes) throws NamingException { Assert.assertEquals("Values and attributes need to have the same length ", expectedAttributes.length, expectedValues.length); for (int i = 0; i < expectedAttributes.length; i++) { Attribute attribute = attributes.get(expectedAttributes[i]); Assert.assertNotNull("Attribute " + expectedAttributes[i] + " was not present", attribute); Assert.assertEquals(expectedValues[i], attribute.get()); } for (int i = 0; i < absentAttributes.length; i++) { Assert.assertNull(attributes.get(absentAttributes[i])); } return null; } public void setAbsentAttributes(String[] absentAttributes) { this.absentAttributes = absentAttributes; } public void setExpectedAttributes(String[] expectedAttributes) { this.expectedAttributes = expectedAttributes; } public void setExpectedValues(String[] expectedValues) { this.expectedValues = expectedValues; } }././@LongLink0000000000000000000000000000022700000000000011566 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap/test/AbstractEc2InstanceLaunchingFactoryBean.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap0000644000000000000000000001422711475313376030246 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.test; import java.util.Collections; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.config.AbstractFactoryBean; import org.springframework.util.Assert; import com.xerox.amazonws.ec2.Jec2; import com.xerox.amazonws.ec2.LaunchConfiguration; import com.xerox.amazonws.ec2.ReservationDescription; import com.xerox.amazonws.ec2.ReservationDescription.Instance; /** * Abstract FactoryBean superclass to use for automatically launching an EC2 instance before creating the actual target object. * This approach is particularly useful for integration testing purposes - the idea is to have particular EC2 images prepared * for running integration tests against certain server configurations, enabling integration tests aimed at e.g. a particluar * DB server to run transparently at the computer of each individual developer without having to have the actual server software * installed on their computers. *

* Public AMIs will need to be created, bundled and registered for each server setup. A subclass of this FactoryBean * is then added to create the actual target object (e.g. a DataSource), implementing the {link #doCreateInstance} method. * This method will be supplied the IP address of the instance that was created, enabling the subclass to configure the * created instance appropriately. * * @author Mattias Hellborg Arthursson */ public abstract class AbstractEc2InstanceLaunchingFactoryBean extends AbstractFactoryBean { private static final int INSTANCE_START_SLEEP_TIME = 1000; private static final long DEFAULT_PREPARATION_SLEEP_TIME = 30000; private static final Log log = LogFactory.getLog(AbstractEc2InstanceLaunchingFactoryBean.class); private String imageName; private String awsKey; private String awsSecretKey; private String keypairName; private String groupName; private Instance instance; private long preparationSleepTime = DEFAULT_PREPARATION_SLEEP_TIME; /** * Set the name of the AMI image to be launched. * * @param imageName the AMI image name. */ public void setImageName(String imageName) { this.imageName = imageName; } /** * Set the AWS key. * * @param awsKey the AWS key. */ public void setAwsKey(String awsKey) { this.awsKey = awsKey; } /** * Set the AWS secret key. * * @param awsSecretKey the aws secret key. */ public void setAwsSecretKey(String awsSecretKey) { this.awsSecretKey = awsSecretKey; } /** * Set the name of the keypair. * * @param keypairName The keypair name. */ public void setKeypairName(String keypairName) { this.keypairName = keypairName; } /** * Set the name of the access group. This group should be configured with the appropriate ports open for this test case to execute. * * @param groupName the group name. */ public void setGroupName(String groupName) { this.groupName = groupName; } @Override protected final Object createInstance() throws Exception { Assert.hasLength(imageName, "ImageName must be set"); Assert.hasLength(awsKey, "AwsKey must be set"); Assert.hasLength(awsSecretKey, "AwsSecretKey must be set"); Assert.hasLength(keypairName, "KeyName must be set"); Assert.hasLength(groupName, "GroupName must be set"); log.info("Launching EC2 instance for image: " + imageName); Jec2 jec2 = new Jec2(awsKey, awsSecretKey); LaunchConfiguration launchConfiguration = new LaunchConfiguration(imageName); launchConfiguration.setKeyName(keypairName); launchConfiguration.setSecurityGroup(Collections.singletonList(groupName)); ReservationDescription reservationDescription = jec2.runInstances(launchConfiguration); instance = reservationDescription.getInstances().get(0); while (!instance.isRunning() && !instance.isTerminated()) { log.info("Instance still starting up; sleeping " + INSTANCE_START_SLEEP_TIME + "ms"); Thread.sleep(INSTANCE_START_SLEEP_TIME); reservationDescription = jec2.describeInstances(Collections.singletonList(instance.getInstanceId())).get(0); instance = reservationDescription.getInstances().get(0); } if (instance.isRunning()) { log.info("EC2 instance is now running"); if (preparationSleepTime > 0) { log.info("Sleeping " + preparationSleepTime + "ms allowing instance services to start up properly."); Thread.sleep(preparationSleepTime); log.info("Instance prepared - proceeding"); } return doCreateInstance(instance.getDnsName()); } else { throw new IllegalStateException("Failed to start a new instance"); } } /** * Implement to create the actual target object. * * @param ip the ip address of the launched EC2 image. * @return the object to be returned by this FactoryBean. * @throws Exception if an error occurs during initialization. */ protected abstract Object doCreateInstance(String ip) throws Exception; @Override protected void destroyInstance(Object ignored) throws Exception { if (this.instance != null) { log.info("Shutting down instance"); Jec2 jec2 = new Jec2(awsKey, awsSecretKey); jec2.terminateInstances(Collections.singletonList(this.instance.getInstanceId())); } } }././@LongLink0000000000000000000000000000021300000000000011561 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap/test/AttributeCheckContextMapper.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap0000644000000000000000000000461611475313376030247 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.test; import junit.framework.Assert; import org.springframework.ldap.core.ContextMapper; import org.springframework.ldap.core.DirContextAdapter; /** * Dummy ContextMapper for testing purposes to check that the received * Attributes are the expected ones. * * @author Mattias Hellborg Arthursson */ public class AttributeCheckContextMapper implements ContextMapper { private String[] expectedAttributes = new String[0]; private String[] expectedValues = new String[0]; private String[] absentAttributes = new String[0]; public Object mapFromContext(Object ctx) { DirContextAdapter adapter = (DirContextAdapter) ctx; Assert.assertEquals("Values and attributes need to have the same length ", expectedAttributes.length, expectedValues.length); for (int i = 0; i < expectedAttributes.length; i++) { String attributeValue = adapter .getStringAttribute(expectedAttributes[i]); Assert.assertNotNull("Attribute " + expectedAttributes[i] + " was not present", attributeValue); Assert.assertEquals(expectedValues[i], attributeValue); } for (int i = 0; i < absentAttributes.length; i++) { Assert.assertNull(adapter.getStringAttribute(absentAttributes[i])); } return adapter; } public void setAbsentAttributes(String[] absentAttributes) { this.absentAttributes = absentAttributes; } public void setExpectedAttributes(String[] expectedAttributes) { this.expectedAttributes = expectedAttributes; } public void setExpectedValues(String[] expectedValues) { this.expectedValues = expectedValues; } }././@LongLink0000000000000000000000000000023400000000000011564 Lustar rootrootlibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap/test/ContextSourceEc2InstanceLaunchingFactoryBean.javalibspring-ldap-java-1.3.1.RELEASE.orig/dist/module-sources/spring-ldap-test/org/springframework/ldap0000644000000000000000000000442611475313376030246 0ustar /* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ldap.test; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.support.LdapContextSource; import org.springframework.ldap.test.AbstractEc2InstanceLaunchingFactoryBean; import org.springframework.util.Assert; /** * FactoryBean to create a ContextSource using the EC2 instance created by * superclass. */ public class ContextSourceEc2InstanceLaunchingFactoryBean extends AbstractEc2InstanceLaunchingFactoryBean { private String base; private String userDn; private String password; private boolean pooled = false; @Override public final Class getObjectType() { return ContextSource.class; } @Override protected final Object doCreateInstance(final String dnsName) throws Exception { Assert.hasText(userDn); LdapContextSource instance = new LdapContextSource(); instance.setUrl("ldap://" + dnsName); instance.setUserDn(userDn); instance.setPassword(password); instance.setBase(base); instance.setPooled(pooled); setAdditionalContextSourceProperties(instance, dnsName); instance.afterPropertiesSet(); return instance; } public void setPooled(boolean pooled) { this.pooled = pooled; } /** * Override to set additional properties on the ContextSource. * * @param ctx The created instance. * @param dnsName The dns name of the created Ec2 instance. */ protected void setAdditionalContextSourceProperties(LdapContextSource ctx, final String dnsName) { // Nothing to do here } public void setBase(String base) { this.base = base; } public void setUserDn(String userDn) { this.userDn = userDn; } public void setPassword(String password) { this.password = password; } } libspring-ldap-java-1.3.1.RELEASE.orig/dist/modules/0002777000000000000000000000000011475315324016674 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/lib/0002777000000000000000000000000011475315320015023 5ustar libspring-ldap-java-1.3.1.RELEASE.orig/license.txt0000644000000000000000000002646511475315306016453 0ustar Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2005-2010 Mattias Arthursson and Ulrik Sandberg Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. libspring-ldap-java-1.3.1.RELEASE.orig/notice.txt0000644000000000000000000000144111475315306016275 0ustar ====================================================================== == NOTICE file corresponding to section 4 d of the Apache License, == == Version 2.0, for the Spring LDAP distribution. == ====================================================================== This product includes software developed by the Apache Software Foundation (http://www.apache.org). The end-user documentation included with a redistribution, if any, must include the following acknowledgement: "This product includes software developed by the Spring LDAP Project (http://www.springframework.org/ldap)." Alternately, this acknowledgement may appear in the software itself, if and wherever such third-party acknowledgements normally appear. libspring-ldap-java-1.3.1.RELEASE.orig/changelog.txt0000644000000000000000000006260411475315306016753 0ustar Spring LDAP CHANGELOG ===================== http://www.springframework.org/ldap http://www.ietf.org/rfc/rfc1960.txt http://www.ietf.org/rfc/rfc2251.txt http://www.ietf.org/rfc/rfc2252.txt http://www.ietf.org/rfc/rfc2253.txt http://www.ietf.org/rfc/rfc2254.txt http://www.ietf.org/rfc/rfc2255.txt http://www.ietf.org/rfc/rfc2256.txt http://www.ietf.org/rfc/rfc2696.txt http://www.ietf.org/rfc/rfc2829.txt Changes in version 1.3.1 (November 2010) ------------------------------------------- * Added an object-directory mapping framework (ODM). Contributed by Paul Harvey. * Added an LDIF parsing framework. Contributed by Keith Barlow. * Added an extension to ContextMapperCallbackHandler that can provide the associated mapper with an indication that the response is different for each search result. (LDAP-185) * AbstractTlsDirContextAuthenticationStrategy now provides a setter for customizing SSLSocketFactory used for TLS negotiation. (LDAP-180) * DirContextAdapter.getObjectAttribute now returns null if the attribute exists but with no value. Added method attributeExists for cases where it has to be detected whether it was one or the other. (LDAP-215) * Added LookupAttemptingCallback for performing operation in authenticated context. (LDAP-203) * Added utility methods for converting a Windows security identifier (SID) between a binary format and a slightly more readable string format. http://msdn.microsoft.com/en-us/library/aa379571%28VS.85%29.aspx (LDAP-187) * Added authentication methods that provide a possible authentication exception through an AuthenticationErrorCallback. (LDAP-192) * Authentication methods now treat a search result of more than one user as an error and throw IncorrectResultSizeDataAccessException. (LDAP-170) * Authentication methods now log problems at level INFO rather than ERROR. (LDAP-170) * It's now possible to control the case folding of attribute keys in DistinguishedName by setting the system property DistinguishedName.KEY_CASE_FOLD_PROPERTY to one of "lower", "upper", or "none". (LDAP-188) * DIGEST-MD5 SASL authentication mechanism is now supported, as specified by RFC 2829 (see http://www.ietf.org/rfc/rfc2829.txt, section 4). (LDAP-173) Contributed by Marvin S. Addison. * DefaultDirObjectFactory calls a Java5 version of the IllegalArgumentException constructor. (LDAP 196) * DirContextAdapter JavaDoc now states clearly that several methods are not implemented on purpose. (LDAP-208) * Class-level JavaDoc for OrFilter no longer uses AndFilter in sample code. (LDAP-217) * Upgraded Spring to 2.5.6.SEC02 and 3.0.3.RELEASE. (LDAP-210) * Upgraded Spring to 2.5.6.SEC01. (LDAP-194) * Build is no longer using the default platform encoding, but UTF-8. (LDAP-201) Changes in version 1.3.0 (Jan 2009) ------------------------------------------- * Added methods for simple LDAP 'bind' authentication in LdapOperations and SimpleLdapOperations. The methods will perform a search given a supplied filter, call ContextSource#getContext(dn, password), and optionally callback to a supplied instance to perform an LDAP operation on the context. * Re-used the same fix for LDAP-109 and LDAP-50 that was used in DefaultDirObjectFactory to secure the DirContextAdapter constructors from invalid CompositeNames. * Made sure DirContextOperations#addAttributeValue(String, Object) does not add any duplicate values per default; added alternate method: DirContextOperations#addAttributeValue(String, Object, boolean) to enable behavior other than the default (i.e. allowing duplicates). * Made sure that DirContextAdapter#setDn() throws exception if in update mode (The value is not set anyway, and this was previously silently ignored). * Improved more search methods that take handlers so that they will work with handlers that use ContextMappers, e.g. ContextMapperCallbackHandler. (LDAP-162) * Made sure article sample tests are possible to run without running web application (i.e. tests automatically start internal LDAP server). (LDAP-143) * SortControlDirContextProcessor no longer has hard dependencies to controls in LDAP Booster Pack. (LDAP-159) * Common code in DirContextProcessor implementations has been pulled up to a base class called AbstractFallbackRequestAndResponseControlDirContextProcessor. (LDAP-161) * PagedResultsRequestControl has been deprecated in favor of PagedResultsDirContextProcessor, which takes advantage of the new AbstractFallbackRequestAndResponseControlDirContextProcessor. (LDAP-160) * Added spring-tx as required dependency (the DataAccessExceptions require this). * Added demo projects to simplify refactoring demonstrations. (LDAP-154) * Added LdapEntryIdentification, a simple bean containing the DNs of an LDAP entry, relative to the base context as well as absolute. Also added special ContextMapper implementation producing these entries; LdapEntryIdentificationContextMapper. (LDAP-149) * Added LdapTemplate#searchForObject(base, filter, mapper) and SimpleLdapTemplate#searchForObject(base, filter, mapper); methods to search for a single object, analogous to JdbcTemplate#queryForObject(). (LDAP-150) * DistinguishedName (LdapRdnComponent really) now correctly calculates the hashCode for names where case differs, and now correctly adheres to the equals/hashCode contract. (LDAP-151) * Various improvements to immutability of DistinguishedNames throughout the framework. DistinguishedName#immutableDistinguishedName now produces a truly immutable copy of the original. Also made sure that it is not possible to accidentally alter the internal state of e.g. DirContextAdapter by modifying its DistinguishedName - copies are now returned in DirContextAdapter#getDn() and DirContextAdapter#getBase(). (LDAP-146) * Added LdapTemplate#rebind(DirContextOperations). (LDAP-144) * Added PresentFilter and NotPresentFilter to simplify searching for presence or absence of an attribute. (LDAP-152) * Added DirContextAdapter constructor that takes its DN as a String. (LDAP-145) Changes in version 1.3.0.RC1 (Oct 2008) ------------------------------------------- * TLS connections are now supported using the DefaultTlsDirContextAuthenticationStrategy and ExternalTlsDirContextAuthenticationStrategy. (LDAP-8) * NameNotFound is no longer silently ignored in searches. It is possible to use the old behavior by setting the ignoreNameNotFoundException property to true in LdapTemplate. (LDAP-134) * Referrals can now be handled by setting the property 'Context.REFERRAL' to 'follow' in the base context supplied to AbstractContextSource, provided that name servers are set up properly. Any DirContextAdapter instances resulting from referrals will provide the URL of the referred server in getReferralUrl(). (LDAP-136, LDAP-9) * The hard dependency on LDAP Booster Pack has now been completely removed, preventing NoClassDefFoundErrors when using Paged Results without that library on the classpath. (LDAP-110, LDAP-118) * The dreaded problem with '\' in Distinguished Names is now resolved. (LDAP-50, LDAP-109) * Added bind method that takes a DirContextOperations instance as parameter, performing the bind using the DN and Attributes from the DirContextOperations instance. (LDAP-140) * DistinguishedName now returns compactly formatted String representations from toString, e.g.: cn=John Doe,ou=Company,c=Sweden rather than cn=John Doe, ou=Company, c=Sweden To keep using the old formatting (for backward compatibility) set the system property org.springframework.ldap.core.spacedDnFormat to true. (LDAP-138, LDAP-112, LDAP-91) * Changed default of 'pooling' flag in AbstractContextSource. This now defaults to false; consider the Spring LDAP PoolingContextSource as the preferred alternative to using the built-in Java Connection Pooling. * Added configuration property to AbstractContextSource to specify referral behavior. Setting this property to 'follow' will enable referrals to be automatically followed, provided that the name server environment is properly set up. * Now using Maven for building internally. (LDAP-80, LDAP-82, LDAP-95) * Added HardcodedFilter class and corresponding PropertyEditor FilterEditor, to allow for easily working with pre-encoded search filters e.g. in configuration files. (LDAP-28) * Added ContextSourceAndHibernateTransactionManager to enable integration of client-side LDAP Transactions in a Hibernate environment. (LDAP-115) * Added append method to BinaryLogicalFilter allowing client code to use and/or filters from the same code. (LDAP-116) * Introduced DirContextAuthenticationStrategy to AbstractContextSource to enable more flexible context authentication strategies, e.g. TLS and Proxy Auth. (LDAP-124) * Corrected reference doc claiming DataAccessException hierarchy. (LDAP-106) * Probably the most requested feature of all - a plain method for simple authentication is now provided in the ContextSource interface. (LDAP-39, LDAP-103) * The order of multi-valued attributes is now properly preserved by DirContextAdapter#getModificationItems(). (LDAP-96) * ContextSourceTransactionManager now properly throws a CannotCreateTransactionException if anything goes wrong in doBegin(). (LDAP-122) * It is now possible to set the criticality on PagedResultsControl. (LDAP-126) * DirContextAdapter now has a getObjectAttributes method, as stated in reference docs. (LDAP-137) * DirContextAdapter#getStringAttributes, getObjectAttributes, and getAttributeSortedStringSet now all return null if the requested Attribute is not present, and an empty result (array or set) if present but empty. (LDAP-130) * SimpleLdapOperations/SimpleLdapTemplate now has mirrored methods that take Name parameters. (LDAP-139) * Fixed documentation glitch regarding ContextSourceAndDataSourceTransactionManager. (LDAP-99) * Added the possibility to configure the search scope on DefaultDirContextValidator. Changed the default to OBJECT_SCOPE. (LDAP-121) * Fixed DistinguishedName parsing error; \r is now allowed in Distinguished Names, complying with LDAP v3 DN RFC. (LDAP-97) * Moved SingleContextSource from an obscure inner class to a top-level class. This class doesn't close the DirContext, but reuses the same. Useful for scenarios like Paged Results. (LDAP-114) * Removed deprecated method setUserName() in AbstractContextSource. * Added a method DistinguishedName.toCompactString that returns a more compact String representation without blanks. (LDAP-91) * Improved search methods that take handlers so that they will work with handlers that use ContextMappers, eg ContextMapperCallbackHandler. (LDAP-107) * Fixed a problem where the narrowest possible exception subclass was not always found in the exception translation. (LDAP-100) * Made changes required for paged results to work when using Spring LDAP connection pool with a single connection. (LDAP-114) * Removed AcegiAuthenticationSource - use SpringSecurityAuthenticationSource (included with Spring Security) instead. * Upgraded commons-lang to 2.3. * Upgraded Spring to 2.5.6. (LDAP-125) Changes in version 1.2.1 (Dec 2007) ------------------------------------------- * Added pooling library which features flexible connection validation and better configuration than the built-in pooling. (LDAP-85) * Fixed a problem in AbstractContextSource which led to an unnecessary reference to the LDAP Booster Pack (ldapbp). (LDAP-88, LDAP-89) * Added missing package description and updated copyright. (LDAP-92) * Added build instructions. (LDAP-27) * Fixed bug in SimpleLdapTemplate where the wrong target method was being called. (LDAP-93) * Made createContext in AbstractContextSource protected rather than package private. (LDAP-94) Changes in version 1.2 (Oct 2007) ------------------------------------------- A number of API-breaking changes have been made in the 1.2 release compared to version 1.1.2. Consequently this is NOT a drop-in replacement for Spring LDAP 1.1.2, though upgrading should not present all that much work. Please see the supplied upgrade guide for details. * Added getContextSource on LdapTemplate. * The following getters on AbstractContextSource have been added: getContextFactory getDirObjectFactory getAuthenticationSource getUrls (was protected) isPooled isAnonymousReadOnly * Upgraded to Spring 2.0.6 internally. Spring 1.2.x is still supported. * Reviewed all javadoc. * Revised reference manual. * AbstractConnection source now actively removes pooling flag from context environment if pooling is set to 'false'. (LDAP-83) * AcegiAuthenticationSource now supports anonymous authentication. (LDAP-67) * Added BaseLdapPathSource, BaseLdapPathAware and BaseLdapNameBeanPostProcessor to be used if the ContextSource base path is needed by beans. There is now also a DistinguishedNameEditor available for directly injecting DistinguishedName instances to beans. (LDAP-86) * Added immutableDistinguishedName() method in DistinguishedName to get an immutable copy of the instance. (LDAP-87) * Added easier access methods for RDN attributes and values. (LDAP-71) * Added lookupContext() and alternate modifyAttributes() in LdapOperations/LdapTemplate to simplify updates. (LDAP-78) * Modified append() method in DistinguishedName. This method now returns the instance, to enable more fluent building of DistinguishedNames. (LDAP-74) * Added SimpleLdapTemplate providing Java 5 generics support. (LDAP-72) * Added AbstractContextMapper implementation. (LDAP-76) Changes in version 1.2-RC1 (5.12.2007) ------------------------------------------- A number of API-breaking changes have been made in this release, mainly package restructuring stuff (LDAP-33). Consequently this is NOT a drop-in replacement for Spring LDAP 1.1.2, though upgrading should not present all that much work. Please see the supplied upgrade guide for details. * Restructured packages (LDAP-33): - Moved the core classes into the package ldap.core. - Moved subpackages of ldap.support to top level. - Moved most classes in ldap.support to ldap.core or ldap.core.support. - Moved classes in ldap.utils to ldap.support and removed ldap.utils. * Changed the exception hierarchy to be an unchecked mirror of the JNDI NamingException hierarchy (LDAP-4). * Deprecated the userName property in AbstractContextSource and changed it to the more correct userDn (LDAP-18). * Fixed bug causing PagedResultsRequestControl processing to fail against AD in the case of a PartialResultsException (LDAP-32). * Fixed bug causing NullPointerException in some environments when performing PagedResultsRequestControl search (LDAP-37). * Implemented client-side transaction support for Spring LDAP. See reference documentation for further information (LDAP-29). * DirContextAdapter.setAttribute() now properly updates updatedAttrs in update mode (resulting in ModificationItems if applicable) (LDAP-15). * Exceptions thrown by Spring LDAP are now always Serializable, regardless of whether the wrapped NamingException is (which is not always the case) (LDAP-14). * LdapRdnComponent now implements Serializable (LDAP-45). * Rewrote LdapEncoder.nameDecode() to solve problem with national characters and remove regular expression used in parsing, drastically improving Distinguished Name parsing performance as a bonus (LDAP-30). * The DefaultDirObjectFactory.JNDI_ENV_BASE_PATH_KEY has been deprecated. If the base property needs to be accessed from a subclass to AbstractContextSource, use the new protected method getBase (LDAP-55). * LdapContextSource.getAnonymousEnv no longer sets a broken ResponseControlFactory in the environment (LDAP-64). * Upgraded ApacheDS to 1.0.0 (LDAP-32). * Upgraded to Acegi Security 1.0.3 (LDAP-61). * Upgraded to ApacheDS 1.0.0 (LDAP-32). * Upgraded to Spring 2.0.4 internally. Spring 1.2.x is still supported (LDAP-35, LDAP-51). * Upgraded to Spring WebFlow 1.0.2 in the Person sample (LDAP-60). * Fixed a number of documentation errors and typos (LDAP-41, LDAP-40, LDAP-47, LDAP-48). * Extracted useful inner classes from LdapTemplate to top-level classes (LDAP-42). * Implemented addAttributeValue and removeAttributeValue in DirContextAdapter (LDAP-5). * Modified DirContextOperations interface so that getNameInNamespace doesn't throw NamingException. * Fixed NullPointerException when getting PagedResultsRequestControl response (LDAP-66). * Rewrote logic i DirContextAdapter.getModificationItems(). The JNDI provider's Attribute comparison logic is now used internally. Also, REMOVE_ATTRIBUTE items are placed first in the ModificationItem array, in order to prevent ATTRIBUTE_ALREADY_EXIST errors (LDAP-13, LDAP-46). * In internal integration tests, each test now runs on a clean LDAP database (LDAP-43). * DirContextProcessor#postProcess() is now called in searches regardless of whether an exception is thrown (LDAP-26). * Moved SortControlDirContextProcessor to spring-ldap from sandbox (LDAP-68). Changes in version 1.1.2 (1.12.2006) ------------------------------------------- * Fixed problem with DirContextAdapter.getNameInNameSpace. Now it really returns the full DN. * There is now a wrapper class called PagedResult, which can be used to wrap the resulting list and the PagedResultsCookie after using PagedResultsRequestControl. * The actual cookie in PagedResultsCookie is now immutable. * The person sample is now a Spring WebFlow application, where the user can manage persons and standard LDAP access groups. * Improved javadoc for DefaultDirObjectFactory and DistinguishedName. * Upgraded Spring to 2.0.1 internally. Spring 1.2.8 is still supported. Changes in version 1.1.1 (18.11.2006) ------------------------------------------- * Added capability to use server-side controls in search by leveraging DirContextProcessor. * Added generic DirContextProcessor that is run before and after a search. * Added paged search result functionality in PagedResultsRequestControl, which is an implementation of DirContextProcessor. * Fixed problem with DirContextAdapter, where the wrong change was applied when a change was followed by a reset to the original values. * DirContextAdapter.getNameInNamespace() now returns the full DN, as per the documentation for javax.naming.Context. * The parsing of DistinguishedName has been changed from using regexp to a JavaCC parser, which means improved performance (5-6 times faster) and better error messages. * DistinguishedName now supports multi-valued RDNs separated by a '+' sign, like "cn=Rod+sn=Johnson", for example. All according to spec 2253. * LdapRdn is now Serializable. * Added lookup methods that take an array of return attribute names. * Made DistinguishedName.EMPTY_NAME an immutable DistinguishedName instance. * Separated integration tests that require OpenLDAP from the other integration tests that run the in-JVM Apache DS server. * Changed the spring-ldap-person sample application to authenticate and authorize against groups rather than role attributes. * Upgraded Spring to 2.0 internally. Spring 1.2.8 is still supported. Changes in version 1.1 (28.8.2006) ------------------------------------------- * Changed base package from net.sf.ldaptemplate to org.springframework.ldap * Changed package ...support.acegi to ...support.authentication * Replaced SearchResultCallbackHandler with NameClassCallbackHandler to enable its use in all search operations (search, list, listBindings). Changed all references and implementing classes accordingly, including name changes where applicable: ** CollectingSearchResultCallbackHandler was replaced by CollectingNameClassPairCallbackHandler. ** CountSearchResultCallbackHandler was replaced by CountNameClassPairCallbackHandler * Added NameClassPairMapper for use with list operations * Added DefaultNameClassPairCallbackHandler. * Added DefaultValuesAuthenticationSourceDecorator to enable default authentication information when AuthenticationSource returns empty values. * ContextSource implementations now creates authenticated Contexts by default, since the previous behaviour has proven to be confusing. The authenticatedReadOnly flag was replaced by an anonymousReadOnly flag. * AbstractContextSource now defaults the dirObjectFactory property to DefaultDirObjectFactory. * Added search methods to LdapTemplate for specifying return attributes. * Added list and listBindings methods to LdapTemplate. * Fixed bug in AbstractContextSource regarding java version number and base path. * Improved javadocs. * Upgraded Spring to 2.0-rc3. * Added full reference documentation. Changes in version 1.0.2 (LdapTemplate) (26.6.2006) ------------------------------------ * Added methods in LdapTemplate to unbind recursively. * Added rename() method to LdapTemplate. * Fixed bug in getPrefix() of DistinguishedName. * Fixed bug in getModificationItems() of DirContextAdapter. The method now correctly handles changes of individual vales in multi-value attributes. * Introduced AbstractContextSource, moved the code from LdapContextSource there and made LdapContextSource and DirContextSource inherit from this. * Upgraded to Acegi 1.0.0. Removed classes no longer needed: LdapTemplateLdapAuthenticationProvider LdapTemplateUserDetails *NOTE*: This means that configuration needs to be changed if using Acegi, since the API and package structure has changed in Acegi between versions 1.0.0-RC2 and 1.0.0 final. Changes in version 1.0.1 (LdapTemplate) (5.5.2006) ----------------------------------- * Now checking whether the first argument to getObjectInstance in DefaultDirObjectFactory is a Context, and if so, closing it properly. * Fixed reference to non-existent ContextSourceImpl in ldaptemplate-person. * Upgraded Spring to 2.0-m4. * Upgraded DDSteps to 1.1-rc1 and EasyMock to 1.2. Changes in version 1.0 (LdapTemplate) (24.4.2006) ---------------------------------- * Introduced the AuthenticationSource interface to enable other strategies for retrieving principal and credentials than a hard-coded username/password. * Added the AcegiAuthenticationSource implementation for retrieving a previously authenticated principal and credentials using Acegi. * Added a 'cacheEnvironmentProperties' property that enables the user to choose whether to cache the environment HashMap or to re-create it each time a new Context is created. * Added an ignorePartialResultException to LdapTemplate which causes all PartialResultExceptions to be ignored during searches, for use when working against Active Directory, which cannot handle referrals correctly. * Added search methods in LdapOperations (and LdapTemplate) that take a parameter for SearchControls. * The methods getNamesOfModifiedAttributes, update, and getAttributeSortedStringSet in DirContextOperations (and DirContextAdapter) no longer throw NamingException. Instead, they throw unchecked DataAccessExceptions. * The method getModificationItems in AttributeModificationsAware no longer throws NamingException. Instead, it throws unchecked DataAccessExceptions. * Removed the (unused) 'task' parameter to NamingExceptionTranslator.translate. * Removed the deprecated ContextSourceImpl class. * Integration tests now run using an in-memory version of Apache Directory Server, rather than requiring a working installation of a directory server. * Integration tests now run together with pure unit tests under the 'tests' Ant target. * The ldaptemplate-person sample web application now uses an in-memory version of Apache Directory Server, rather than requiring a working installation of a directory server. * Upgraded Spring to 2.0-m3. * The build now uses Ivy 1.3.1. Changes in version 1.0-RC2 (LdapTemplate) (22.2.2006) -------------------------------------- * LdapV2 is now supported. ContextSourceImpl has been deprecated. In stead the new LdapContextSource should be used for LdapV3 and a DirContextSource has been added for LdapV2 compatibility. * Ability has been added in LdapContextSource and DirContextSource to specify that an authenticated context should be used for read-only operations as well. Use property 'authenticatedReadOnly' in LdapContextSource/DirContextSource. * The Filter classes have been cleaned up. * DirContextAdapter has been cleaned up. Most important to note is that in this operation the 'setStringAttribute/setStringAttributes' methods have been removed and replaced by 'setAttributeValue/setAttributeValues'. * Base DNs are now correctly URL encoded when building the connection String. This means that spaces and other 'unsafe' characters in base DNs should no longer be manually URL encoded. * An AttributesIntegrityViolationException has been added and is thrown when an InvalidAttributesException is encountered. * More unit tests have been added. Changes in version 1.0-RC1 (LdapTemplate) (27.1.2006) -------------------------------------- * First public release candidate.