1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.jndi;
21  
22  
23  import org.apache.directory.server.core.DirectoryService;
24  import org.apache.directory.server.core.entry.DefaultServerEntry;
25  import org.apache.directory.server.core.integ.CiRunner;
26  import static org.apache.directory.server.core.integ.IntegrationUtils.getSystemContext;
27  import static org.apache.directory.server.core.integ.IntegrationUtils.getUserAddLdif;
28  import org.apache.directory.shared.ldap.util.ArrayUtils;
29  import org.apache.directory.shared.ldap.util.StringTools;
30  import org.apache.directory.shared.ldap.ldif.LdifEntry;
31  import static org.junit.Assert.assertEquals;
32  import static org.junit.Assert.assertTrue;
33  import static org.junit.Assert.assertNull;
34  import org.junit.Test;
35  import org.junit.runner.RunWith;
36  
37  import javax.naming.Context;
38  import javax.naming.Name;
39  import javax.naming.NamingException;
40  import javax.naming.directory.Attribute;
41  import javax.naming.directory.Attributes;
42  import javax.naming.directory.BasicAttribute;
43  import javax.naming.directory.BasicAttributes;
44  import javax.naming.directory.SchemaViolationException;
45  import javax.naming.ldap.LdapContext;
46  import javax.naming.spi.DirObjectFactory;
47  import javax.naming.spi.DirStateFactory;
48  import java.util.Hashtable;
49  
50  
51  /**
52   * Tests to make sure that object and state factories work.
53   *
54   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
55   * @version $Rev: 691024 $
56   */
57  @RunWith ( CiRunner.class )
58  public class ObjStateFactoryIT
59  {
60      public static DirectoryService service;
61  
62  
63      @Test
64      public void testObjectFactory() throws Exception
65      {
66          LdifEntry akarasulu = getUserAddLdif();
67          service.getAdminSession().add( 
68              new DefaultServerEntry( service.getRegistries(), akarasulu.getEntry() ) ); 
69  
70  
71          LdapContext sysRoot = getSystemContext( service );
72          sysRoot.addToEnvironment( Context.OBJECT_FACTORIES, PersonObjectFactory.class.getName() );
73          Object obj = sysRoot.lookup( "uid=akarasulu, ou=users" );
74          Attributes attrs = sysRoot.getAttributes( "uid=akarasulu, ou=users" );
75          assertEquals( Person.class, obj.getClass() );
76          Person me = ( Person ) obj;
77          assertEquals( attrs.get( "sn" ).get(), me.getLastname() );
78          assertEquals( attrs.get( "cn" ).get(), me.getCn() );
79          assertTrue( ArrayUtils.isEquals( attrs.get( "userPassword" ).get(), StringTools.getBytesUtf8( "test" ) ) );
80          assertEquals( attrs.get( "telephonenumber" ).get(), me.getTelephoneNumber() );
81          assertNull( me.getSeealso() );
82          assertNull( me.getDescription() );
83      }
84  
85  
86      @Test
87      public void testStateFactory() throws Exception
88      {
89          LdapContext sysRoot = getSystemContext( service );
90  
91          sysRoot.addToEnvironment( Context.STATE_FACTORIES, PersonStateFactory.class.getName() );
92          Person p = new Person( "Rodriguez", "Mr. Kerberos", "noices", "555-1212", "sn=erodriguez", "committer" );
93          sysRoot.bind( "sn=Rodriguez, ou=users", p );
94          Attributes attrs = sysRoot.getAttributes( "sn=Rodriguez, ou=users" );
95          assertEquals( "Rodriguez", attrs.get( "sn" ).get() );
96          assertEquals( "Mr. Kerberos", attrs.get( "cn" ).get() );
97          assertTrue( ArrayUtils.isEquals( attrs.get( "userPassword" ).get(), StringTools.getBytesUtf8( "noices" ) ) );
98          assertEquals( "555-1212", attrs.get( "telephonenumber" ).get() );
99          assertEquals( "sn=erodriguez", attrs.get( "seealso" ).get() );
100         assertEquals( "committer", attrs.get( "description" ).get() );
101     }
102 
103     
104     public static class PersonStateFactory implements DirStateFactory
105     {
106         public Result getStateToBind( Object obj, Name name, Context nameCtx, Hashtable environment, Attributes inAttrs )
107             throws NamingException
108         {
109             // Only interested in Person objects
110             if ( obj instanceof Person )
111             {
112 
113                 Attributes outAttrs;
114 
115                 if ( inAttrs == null )
116                 {
117                     outAttrs = new BasicAttributes( true );
118                 }
119                 else
120                 {
121                     outAttrs = ( Attributes ) inAttrs.clone();
122                 }
123 
124                 // Set up object class
125                 if ( outAttrs.get( "objectclass" ) == null )
126                 {
127                     Attribute oc = new BasicAttribute( "objectclass", "person" );
128                     oc.add( "top" );
129                     outAttrs.put( oc );
130                 }
131 
132                 Person per = ( Person ) obj;
133 
134                 // mandatory attributes
135                 if ( per.getLastname() != null )
136                 {
137                     outAttrs.put( "sn", per.getLastname() );
138                 }
139                 else
140                 {
141                     throw new SchemaViolationException( "Person must have surname" );
142                 }
143 
144                 if ( per.getCn() != null )
145                 {
146                     outAttrs.put( "cn", per.getCn() );
147                 }
148                 else
149                 {
150                     throw new SchemaViolationException( "Person must have common name" );
151                 }
152 
153                 // optional attributes
154                 if ( per.getPassword() != null )
155                 {
156                     outAttrs.put( "userPassword", per.getPassword() );
157                 }
158                 if ( per.getTelephoneNumber() != null )
159                 {
160                     outAttrs.put( "telephoneNumber", per.getTelephoneNumber() );
161                 }
162                 if ( per.getSeealso() != null )
163                 {
164                     outAttrs.put( "seeAlso", per.getSeealso() );
165                 }
166                 if ( per.getDescription() != null )
167                 {
168                     outAttrs.put( "description", per.getDescription() );
169                 }
170 
171                 return new DirStateFactory.Result( null, outAttrs );
172             }
173 
174             return null;
175         }
176 
177 
178         public Object getStateToBind( Object obj, Name name, Context nameCtx, Hashtable environment )
179             throws NamingException
180         {
181             throw new UnsupportedOperationException( "Please use directory support overload with Attributes argument." );
182         }
183     }
184 
185 
186     public static class PersonObjectFactory implements DirObjectFactory
187     {
188         public Object getObjectInstance( Object obj, Name name, Context nameCtx, Hashtable environment, Attributes attrs )
189             throws Exception
190         {
191             // Only interested in Attributes with "person" objectclass
192             Attribute oc = ( attrs != null ? attrs.get( "objectclass" ) : null );
193             if ( oc != null && oc.contains( "person" ) )
194             {
195                 Attribute attr;
196                 String passwd = null;
197 
198                 // Extract the password
199                 attr = attrs.get( "userPassword" );
200                 if ( attr != null )
201                 {
202                     Object pw = attr.get();
203 
204                     if ( pw instanceof String )
205                         passwd = ( String ) pw;
206                     else
207                         passwd = new String( ( byte[] ) pw );
208                 }
209 
210                 return new Person( ( String ) attrs.get( "sn" ).get(), ( String ) attrs.get( "cn" ).get(), passwd,
211                     ( attr = attrs.get( "telephoneNumber" ) ) != null ? ( String ) attr.get() : null, ( attr = attrs
212                         .get( "seealso" ) ) != null ? ( String ) attr.get() : null,
213                     ( attr = attrs.get( "description" ) ) != null ? ( String ) attr.get() : null );
214             }
215             return null;
216         }
217 
218 
219         public Object getObjectInstance( Object obj, Name name, Context nameCtx, Hashtable environment )
220             throws Exception
221         {
222             throw new UnsupportedOperationException( "Please use directory support overload with Attributes argument." );
223         }
224     }
225 
226     public static class Person
227     {
228         private String sn, cn, pwd, tele, seealso, desc;
229 
230 
231         public Person(String sn, String cn, String pwd, String tele, String seealso, String desc)
232         {
233             this.sn = sn;
234             this.cn = cn;
235             this.pwd = pwd;
236             this.tele = tele;
237             this.seealso = seealso;
238             this.desc = desc;
239         }
240 
241 
242         public String getLastname()
243         {
244             return sn;
245         }
246 
247 
248         public String getCn()
249         {
250             return cn;
251         }
252 
253 
254         public String getPassword()
255         {
256             return pwd;
257         }
258 
259 
260         public String getTelephoneNumber()
261         {
262             return tele;
263         }
264 
265 
266         public String getSeealso()
267         {
268             return seealso;
269         }
270 
271 
272         public String getDescription()
273         {
274             return desc;
275         }
276     }
277 }