View Javadoc

1   // 
2   //Copyright (c) 2003, Caltha - Gajda, Krzewski, Mach, Potempski Sp.J. 
3   //All rights reserved. 
4   //   
5   //Redistribution and use in source and binary forms, with or without modification,  
6   //are permitted provided that the following conditions are met: 
7   //   
8   //* Redistributions of source code must retain the above copyright notice,  
9   //this list of conditions and the following disclaimer. 
10  //* Redistributions in binary form must reproduce the above copyright notice,  
11  //this list of conditions and the following disclaimer in the documentation  
12  //and/or other materials provided with the distribution. 
13  //* Neither the name of the Caltha - Gajda, Krzewski, Mach, Potempski Sp.J.  
14  //nor the names of its contributors may be used to endorse or promote products  
15  //derived from this software without specific prior written permission. 
16  // 
17  //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
18  //AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED  
19  //WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
20  //IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,  
21  //INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,  
22  //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
23  //OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
24  //WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  
25  //ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  
26  //POSSIBILITY OF SUCH DAMAGE. 
27  //
28  
29  package org.objectledge.naming.db;
30  
31  import java.util.ArrayList;
32  import java.util.Hashtable;
33  import java.util.List;
34  
35  import javax.naming.CompositeName;
36  import javax.naming.Context;
37  import javax.naming.InvalidNameException;
38  import javax.naming.Name;
39  import javax.naming.NameAlreadyBoundException;
40  import javax.naming.NameClassPair;
41  import javax.naming.NameParser;
42  import javax.naming.NamingEnumeration;
43  import javax.naming.NamingException;
44  
45  import org.objectledge.database.persistence.Persistence;
46  import org.objectledge.database.persistence.PersistenceException;
47  
48  /**
49   * Database implementation of java.naming.Context interface.
50   *  
51   * @author <a href="mailto:pablo@caltha.pl">Pawel Potempski</a>
52   */
53  public class DatabaseContext implements Context
54  {
55      /*** Environment entry for persistence component. */
56      public static final String PERSISTENCE = "org.objectledge.database.persistence.Persistence";
57  
58      /*** the persistence component. */
59      protected Persistence persistence;
60      
61      /*** The enviroment. */
62      protected Hashtable env;
63  
64      /*** The default parser. */
65      protected static NameParser parser = new DefaultNameParser();
66      
67      /*** The context persistent delegate. */
68      protected PersistentContext context;
69      
70      /***
71       * The context constructor used by initial context factory.
72       * 
73       * @param env the environment 
74       */
75      public DatabaseContext(Hashtable env)
76      {
77          this.env = env;
78          persistence = (Persistence)env.get(PERSISTENCE);
79          if(persistence == null)
80          {
81              throw new RuntimeException("failed to retrieve the persistence " +
82                                          "component from environment");
83          }
84          String dn = (String)env.get(Context.PROVIDER_URL);
85          List list = null;
86          try
87          {
88              list = persistence.load("dn = '"+dn+"'", PersistentContext.FACTORY);
89          }
90          catch(PersistenceException e)
91          {
92              throw new RuntimeException("failed to load '"+dn+"' context from database", e);
93          }
94          if(list.size() == 0)
95          {
96              throw new RuntimeException("failed to lookup the context in database");
97          }
98          if(list.size() > 1)
99          {
100             throw new RuntimeException("ambiguous context '"+dn+"' in database");
101         }
102         context = (PersistentContext)list.get(0);
103     }
104 
105     /***
106      * The context constructor.
107      * 
108      * @param env the environment.
109      * @param context the persistent context delegate.
110      * @param persistence the persistence.
111      * @throws NamingException if operation failed.
112      */
113     protected DatabaseContext(Hashtable env, PersistentContext context, Persistence persistence)
114         throws NamingException
115     {
116         
117         this.env = env;
118         this.persistence = persistence;
119         this.context = context;
120     }
121 
122     /***
123      * {@inheritDoc}
124      */
125     public Object lookup(Name name) throws NamingException
126     {
127         if (name.isEmpty())
128         {
129             return new DatabaseContext(env, context, persistence);
130         }
131         String dn = getDN(name);
132         List list = lookupContext(dn);
133         if(list.size() == 0)
134         {
135             throw new NamingException("faled to retrieve context '"+dn+"' form database");
136         }
137         if(list.size() > 1)
138         {
139             throw new NamingException("ambigious context '"+dn+"' in database");
140         }
141         return new DatabaseContext(env, (PersistentContext)list.get(0), persistence);
142     }
143 
144     /***
145      * {@inheritDoc}
146      */
147     public Object lookup(String name) throws NamingException
148     {
149         return lookup(new CompositeName(name));
150     }
151 
152     /***
153      * {@inheritDoc}
154      */
155     public void bind(Name name, Object obj) throws NamingException
156     {
157         throw new UnsupportedOperationException();
158     }
159 
160     /***
161      * {@inheritDoc}
162      */
163     public void bind(String name, Object obj) throws NamingException
164     {
165         bind(new CompositeName(name),obj);
166     }
167 
168     /***
169      * {@inheritDoc}
170      */
171     public void rebind(Name name, Object obj) throws NamingException
172     {
173         throw new UnsupportedOperationException();        
174     }
175 
176     /***
177      * {@inheritDoc}
178      */
179     public void rebind(String name, Object obj) throws NamingException
180     {
181         rebind(new CompositeName(name),obj);
182     }
183 
184     /***
185      * {@inheritDoc}
186      */
187     public void unbind(Name name) throws NamingException
188     {
189         throw new UnsupportedOperationException();        
190     }
191 
192     /***
193      * {@inheritDoc}
194      */
195     public void unbind(String name) throws NamingException
196     {
197         unbind(new CompositeName(name));
198     }
199 
200     /***
201      * {@inheritDoc}
202      */
203     public void rename(Name oldName, Name newName) throws NamingException
204     {
205         if (oldName.isEmpty())
206         {
207             throw new InvalidNameException("Invalid source name");
208         }
209         if (newName.isEmpty())
210         {
211             throw new InvalidNameException("Invalid target name");
212         }
213         String dn = getDN(oldName);
214         List list = lookupContext(dn);
215         if(list.size() == 0)
216         {
217             throw new NamingException("faled to retrieve context '"+dn+"' form database");
218         }
219         if(list.size() > 1)
220         {
221             throw new NamingException("ambigious context '"+dn+"' in database");
222         }
223         PersistentContext delegate = (PersistentContext)list.get(0);
224         String newDn = getDN(newName);
225         delegate.setDN(newDn);
226         try
227         {
228             persistence.save(delegate);
229         }
230         catch(PersistenceException e)
231         {
232             throw new DatabaseNamingException("failed to rename the context name",e);        
233         }
234     }
235 
236     /***
237      * {@inheritDoc}
238      */
239     public void rename(String oldName, String newName) throws NamingException
240     {
241         rename(new CompositeName(oldName), new CompositeName(newName));
242     }
243 
244     /***
245      * {@inheritDoc}
246      */
247     public NamingEnumeration list(Name name) throws NamingException
248     {
249         DatabaseContext ctx = (DatabaseContext)lookup(name);
250         long parentId = ctx.getDelegate().getContextId();
251         try
252         {
253             List list = persistence.load("parent = "+parentId, PersistentContext.FACTORY);
254             List target = new ArrayList();
255             for(int i = 0; i < list.size(); i++)
256             {
257                 PersistentContext delegate = (PersistentContext)list.get(0);
258                 target.add(new NameClassPair(delegate.getDN(), this.getClass().getName()));
259             }
260             return new DefaultEnumeration(target);            
261         }
262         catch(PersistenceException e)
263         {
264             throw new DatabaseNamingException("failed to retrieve child contexts from database",e);
265         }        
266     }
267 
268     /***
269      * {@inheritDoc}
270      */
271     public NamingEnumeration list(String name) throws NamingException
272     {
273         return list(new CompositeName(name));
274     }
275 
276     /***
277      * {@inheritDoc}
278      */
279     public NamingEnumeration listBindings(Name name) throws NamingException
280     {
281         throw new UnsupportedOperationException();
282     }
283 
284     /***
285      * {@inheritDoc}
286      */
287     public NamingEnumeration listBindings(String name) throws NamingException
288     {
289         return listBindings(new CompositeName(name));
290     }
291 
292     /***
293      * {@inheritDoc}
294      */
295     public void destroySubcontext(Name name) throws NamingException
296     {
297         if (name.isEmpty())
298         {
299             throw new InvalidNameException("Cannot perform self destroy");
300         }
301         DatabaseContext ctx = (DatabaseContext)lookup(name);
302         long parentId = ctx.getDelegate().getContextId();
303         try
304         {
305             List list = persistence.load("parent = "+parentId, PersistentContext.FACTORY);
306             if(list.size()>0)
307             {
308                 throw new NamingException("failed to destroy not empty subcontext");
309             }
310             persistence.delete(ctx.getDelegate());
311         }
312         catch(PersistenceException e)
313         {
314             throw new DatabaseNamingException("failed to delete '"+ctx.getDelegate().getDN()+
315                                                "' context from database",e);
316         }        
317     }
318 
319     /***
320      * {@inheritDoc}
321      */
322     public void destroySubcontext(String name) throws NamingException
323     {
324         destroySubcontext(new CompositeName(name));
325     }
326 
327     /***
328      * {@inheritDoc}
329      */
330     public Context createSubcontext(Name name) throws NamingException
331     {
332         PersistentContext delegate = createContextDelegate(name);
333         return new DatabaseContext(env, delegate, persistence);
334     }
335 
336     /***
337      * {@inheritDoc}
338      */
339     public Context createSubcontext(String name) throws NamingException
340     {
341         return createSubcontext(new CompositeName(name));
342     }
343 
344     /***
345      * {@inheritDoc}
346      */
347     public Object lookupLink(Name name) throws NamingException
348     {
349         throw new UnsupportedOperationException();        
350     }
351 
352     /***
353      * {@inheritDoc}
354      */
355     public Object lookupLink(String name) throws NamingException
356     {
357         return lookupLink(new CompositeName(name));
358     }
359 
360     /***
361      * {@inheritDoc}
362      */
363     public NameParser getNameParser(Name name) throws NamingException
364     {
365         return parser;
366     }
367 
368     /***
369      * {@inheritDoc}
370      */
371     public NameParser getNameParser(String name) throws NamingException
372     {
373         return parser;
374     }
375 
376     /***
377      * {@inheritDoc}
378      */
379     public Name composeName(Name name, Name prefix) throws NamingException
380     {
381         Name compoundName = name;
382         if(compoundName instanceof CompositeName)
383         {
384             compoundName = parser.parse(compoundName.toString());
385         }
386         Name compoundPrefix = prefix;
387         if(compoundPrefix instanceof CompositeName)
388         {
389             compoundPrefix = parser.parse(compoundPrefix.toString());
390         }
391         compoundPrefix.addAll(compoundName);
392         return new CompositeName(compoundPrefix.toString());
393     }
394 
395     /***
396      * {@inheritDoc}
397      */
398     public String composeName(String name, String prefix) throws NamingException
399     {
400         Name compoundName = parser.parse(name);
401         Name compoundPrefix = parser.parse(prefix);
402         compoundPrefix.addAll(compoundName);
403         return compoundPrefix.toString();        
404     }
405 
406     /***
407      * {@inheritDoc}
408      */
409     public Object addToEnvironment(String propName, Object propVal) throws NamingException
410     {
411         if (env == null) 
412         {
413             env = new Hashtable();
414         } 
415         return env.put(propName, propVal);
416     }
417 
418     /***
419      * {@inheritDoc}
420      */
421     public Object removeFromEnvironment(String propName) throws NamingException
422     {
423         if(env == null)
424         {
425             return null;
426         }
427         return env.remove(propName);        
428     }
429 
430     /***
431      * {@inheritDoc}
432      */
433     public Hashtable getEnvironment() throws NamingException
434     {
435         return new Hashtable(env);
436     }
437 
438     /***
439      * {@inheritDoc}
440      */
441     public void close() throws NamingException
442     {
443         // does nothing
444     }
445 
446     /***
447      * {@inheritDoc}
448      */
449     public String getNameInNamespace() throws NamingException
450     {
451         return context.getDN();
452     }
453 
454 
455     // private helper methods
456 
457     /***
458      * Lookup the context with given dn.
459      * 
460      * @param dn the dn of the context.
461      * @return the list of contexts with given dn.
462      * @throws NamingException if operation fails.
463      */
464     protected List lookupContext(String dn)
465         throws NamingException
466     {
467         try
468         {
469             return persistence.load("dn = '"+dn+"'", PersistentContext.FACTORY);
470         }
471         catch(PersistenceException e)
472         {
473             throw new DatabaseNamingException("failed to retrieve context from database",e);
474         }        
475     }
476 
477     /***
478      * Get the dn from relative name.
479      * 
480      * @param relativeName the relative name of the context.
481      * @return the dn of the context.
482      * @throws NamingException if operation fails.
483      */    
484     protected String getDN(Name relativeName)
485         throws NamingException
486     {
487         Name base = parser.parse(new CompositeName(this.getNameInNamespace()).get(0));
488         return base.add(relativeName.get(0)).toString();
489     }
490 
491     /***
492      * Create the context delegate.
493      * 
494      * @param name the name of the context.
495      * @return the persistent delegate.
496      * @throws NamingException if operation fails.
497      */    
498     protected PersistentContext createContextDelegate(Name name)
499         throws NamingException
500     {
501         String dn = getDN(name);
502         List list = lookupContext(dn);
503         if(list.size() > 0)
504         {
505             throw new NameAlreadyBoundException("context '"+dn+"' already exists");
506         }
507         PersistentContext subContext = new PersistentContext(dn, context.getContextId());
508         try
509         {
510             persistence.save(subContext);
511         }
512         catch(PersistenceException e)
513         {
514             throw new DatabaseNamingException("failed to add the subcontext with name = '"+
515                                                     dn+"'",e);        
516         }
517         return subContext;
518     }
519     
520     /***
521      * Access to delegate object.
522      * 
523      * @return the delegate context.
524      */
525     PersistentContext getDelegate()
526     {
527         return context;
528     }
529 }