KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > users > MemoryUserDatabase


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18
19 package org.apache.catalina.users;
20
21
22 import java.io.File JavaDoc;
23 import java.io.FileInputStream JavaDoc;
24 import java.io.FileOutputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.OutputStreamWriter JavaDoc;
27 import java.io.PrintWriter JavaDoc;
28 import java.util.HashMap JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import org.apache.catalina.Group;
31 import org.apache.catalina.Role;
32 import org.apache.catalina.User;
33 import org.apache.catalina.UserDatabase;
34 import org.apache.catalina.util.StringManager;
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.apache.tomcat.util.digester.Digester;
38 import org.apache.tomcat.util.digester.ObjectCreationFactory;
39 import org.xml.sax.Attributes JavaDoc;
40
41
42 /**
43  * <p>Concrete implementation of {@link UserDatabase} that loads all
44  * defined users, groups, and roles into an in-memory data structure,
45  * and uses a specified XML file for its persistent storage.</p>
46  *
47  * @author Craig R. McClanahan
48  * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
49  * @since 4.1
50  */

51
52 public class MemoryUserDatabase implements UserDatabase {
53
54
55     private static Log log = LogFactory.getLog(MemoryUserDatabase.class);
56
57     // ----------------------------------------------------------- Constructors
58

59
60     /**
61      * Create a new instance with default values.
62      */

63     public MemoryUserDatabase() {
64
65         super();
66
67     }
68
69
70     /**
71      * Create a new instance with the specified values.
72      *
73      * @param id Unique global identifier of this user database
74      */

75     public MemoryUserDatabase(String JavaDoc id) {
76
77         super();
78         this.id = id;
79
80     }
81
82
83     // ----------------------------------------------------- Instance Variables
84

85
86     /**
87      * The set of {@link Group}s defined in this database, keyed by
88      * group name.
89      */

90     protected HashMap JavaDoc groups = new HashMap JavaDoc();
91
92
93     /**
94      * The unique global identifier of this user database.
95      */

96     protected String JavaDoc id = null;
97
98
99     /**
100      * The relative (to <code>catalina.base</code>) or absolute pathname to
101      * the XML file in which we will save our persistent information.
102      */

103     protected String JavaDoc pathname = "conf/tomcat-users.xml";
104
105
106     /**
107      * The relative or absolute pathname to the file in which our old
108      * information is stored while renaming is in progress.
109      */

110     protected String JavaDoc pathnameOld = pathname + ".old";
111
112
113     /**
114      * The relative or absolute pathname ot the file in which we write
115      * our new information prior to renaming.
116      */

117     protected String JavaDoc pathnameNew = pathname + ".new";
118
119
120     /**
121      * A flag, indicating if the user database is read only.
122      */

123     protected boolean readonly = false;
124
125     /**
126      * The set of {@link Role}s defined in this database, keyed by
127      * role name.
128      */

129     protected HashMap JavaDoc roles = new HashMap JavaDoc();
130
131
132     /**
133      * The string manager for this package.
134      */

135     private static StringManager sm =
136         StringManager.getManager(Constants.Package);
137
138
139     /**
140      * The set of {@link User}s defined in this database, keyed by
141      * user name.
142      */

143     protected HashMap JavaDoc users = new HashMap JavaDoc();
144
145
146     // ------------------------------------------------------------- Properties
147

148
149     /**
150      * Return the set of {@link Group}s defined in this user database.
151      */

152     public Iterator JavaDoc getGroups() {
153
154         synchronized (groups) {
155             return (groups.values().iterator());
156         }
157
158     }
159
160
161     /**
162      * Return the unique global identifier of this user database.
163      */

164     public String JavaDoc getId() {
165
166         return (this.id);
167
168     }
169
170
171     /**
172      * Return the relative or absolute pathname to the persistent storage file.
173      */

174     public String JavaDoc getPathname() {
175
176         return (this.pathname);
177
178     }
179
180
181     /**
182      * Set the relative or absolute pathname to the persistent storage file.
183      *
184      * @param pathname The new pathname
185      */

186     public void setPathname(String JavaDoc pathname) {
187
188         this.pathname = pathname;
189         this.pathnameOld = pathname + ".old";
190         this.pathnameNew = pathname + ".new";
191
192     }
193
194
195     /**
196      * Returning the readonly status of the user database
197      */

198     public boolean getReadonly() {
199
200         return (this.readonly);
201
202     }
203
204
205     /**
206      * Setting the readonly status of the user database
207      *
208      * @param pathname The new pathname
209      */

210     public void setReadonly(boolean readonly) {
211
212         this.readonly = readonly;
213
214     }
215
216
217     /**
218      * Return the set of {@link Role}s defined in this user database.
219      */

220     public Iterator JavaDoc getRoles() {
221
222         synchronized (roles) {
223             return (roles.values().iterator());
224         }
225
226     }
227
228
229     /**
230      * Return the set of {@link User}s defined in this user database.
231      */

232     public Iterator JavaDoc getUsers() {
233
234         synchronized (users) {
235             return (users.values().iterator());
236         }
237
238     }
239
240
241
242     // --------------------------------------------------------- Public Methods
243

244
245     /**
246      * Finalize access to this user database.
247      *
248      * @exception Exception if any exception is thrown during closing
249      */

250     public void close() throws Exception JavaDoc {
251
252         save();
253
254         synchronized (groups) {
255             synchronized (users) {
256                 users.clear();
257                 groups.clear();
258             }
259         }
260
261     }
262
263
264     /**
265      * Create and return a new {@link Group} defined in this user database.
266      *
267      * @param groupname The group name of the new group (must be unique)
268      * @param description The description of this group
269      */

270     public Group createGroup(String JavaDoc groupname, String JavaDoc description) {
271
272         MemoryGroup group = new MemoryGroup(this, groupname, description);
273         synchronized (groups) {
274             groups.put(group.getGroupname(), group);
275         }
276         return (group);
277
278     }
279
280
281     /**
282      * Create and return a new {@link Role} defined in this user database.
283      *
284      * @param rolename The role name of the new group (must be unique)
285      * @param description The description of this group
286      */

287     public Role createRole(String JavaDoc rolename, String JavaDoc description) {
288
289         MemoryRole role = new MemoryRole(this, rolename, description);
290         synchronized (roles) {
291             roles.put(role.getRolename(), role);
292         }
293         return (role);
294
295     }
296
297
298     /**
299      * Create and return a new {@link User} defined in this user database.
300      *
301      * @param username The logon username of the new user (must be unique)
302      * @param password The logon password of the new user
303      * @param fullName The full name of the new user
304      */

305     public User createUser(String JavaDoc username, String JavaDoc password,
306                            String JavaDoc fullName) {
307
308         MemoryUser user = new MemoryUser(this, username, password, fullName);
309         synchronized (users) {
310             users.put(user.getUsername(), user);
311         }
312         return (user);
313
314     }
315
316
317     /**
318      * Return the {@link Group} with the specified group name, if any;
319      * otherwise return <code>null</code>.
320      *
321      * @param groupname Name of the group to return
322      */

323     public Group findGroup(String JavaDoc groupname) {
324
325         synchronized (groups) {
326             return ((Group) groups.get(groupname));
327         }
328
329     }
330
331
332     /**
333      * Return the {@link Role} with the specified role name, if any;
334      * otherwise return <code>null</code>.
335      *
336      * @param rolename Name of the role to return
337      */

338     public Role findRole(String JavaDoc rolename) {
339
340         synchronized (roles) {
341             return ((Role) roles.get(rolename));
342         }
343
344     }
345
346
347     /**
348      * Return the {@link User} with the specified user name, if any;
349      * otherwise return <code>null</code>.
350      *
351      * @param username Name of the user to return
352      */

353     public User findUser(String JavaDoc username) {
354
355         synchronized (users) {
356             return ((User) users.get(username));
357         }
358
359     }
360
361
362     /**
363      * Initialize access to this user database.
364      *
365      * @exception Exception if any exception is thrown during opening
366      */

367     public void open() throws Exception JavaDoc {
368
369         synchronized (groups) {
370             synchronized (users) {
371
372                 // Erase any previous groups and users
373
users.clear();
374                 groups.clear();
375                 roles.clear();
376
377                 // Construct a reader for the XML input file (if it exists)
378
File JavaDoc file = new File JavaDoc(pathname);
379                 if (!file.isAbsolute()) {
380                     file = new File JavaDoc(System.getProperty("catalina.base"),
381                                     pathname);
382                 }
383                 if (!file.exists()) {
384                     return;
385                 }
386                 FileInputStream JavaDoc fis = new FileInputStream JavaDoc(file);
387
388                 // Construct a digester to read the XML input file
389
Digester digester = new Digester();
390                 digester.addFactoryCreate
391                     ("tomcat-users/group",
392                      new MemoryGroupCreationFactory(this));
393                 digester.addFactoryCreate
394                     ("tomcat-users/role",
395                      new MemoryRoleCreationFactory(this));
396                 digester.addFactoryCreate
397                     ("tomcat-users/user",
398                      new MemoryUserCreationFactory(this));
399
400                 // Parse the XML input file to load this database
401
try {
402                     digester.parse(fis);
403                     fis.close();
404                 } catch (Exception JavaDoc e) {
405                     try {
406                         fis.close();
407                     } catch (Throwable JavaDoc t) {
408                         ;
409                     }
410                     throw e;
411                 }
412
413             }
414         }
415
416     }
417
418
419     /**
420      * Remove the specified {@link Group} from this user database.
421      *
422      * @param group The group to be removed
423      */

424     public void removeGroup(Group group) {
425
426         synchronized (groups) {
427             Iterator JavaDoc users = getUsers();
428             while (users.hasNext()) {
429                 User user = (User) users.next();
430                 user.removeGroup(group);
431             }
432             groups.remove(group.getGroupname());
433         }
434
435     }
436
437
438     /**
439      * Remove the specified {@link Role} from this user database.
440      *
441      * @param role The role to be removed
442      */

443     public void removeRole(Role role) {
444
445         synchronized (roles) {
446             Iterator JavaDoc groups = getGroups();
447             while (groups.hasNext()) {
448                 Group group = (Group) groups.next();
449                 group.removeRole(role);
450             }
451             Iterator JavaDoc users = getUsers();
452             while (users.hasNext()) {
453                 User user = (User) users.next();
454                 user.removeRole(role);
455             }
456             roles.remove(role.getRolename());
457         }
458
459     }
460
461
462     /**
463      * Remove the specified {@link User} from this user database.
464      *
465      * @param user The user to be removed
466      */

467     public void removeUser(User user) {
468
469         synchronized (users) {
470             users.remove(user.getUsername());
471         }
472
473     }
474
475
476     /**
477      * Check for permissions to save this user database
478      * to persistent storage location
479      *
480      */

481     public boolean isWriteable() {
482
483         File JavaDoc file = new File JavaDoc(pathname);
484         if (!file.isAbsolute()) {
485             file = new File JavaDoc(System.getProperty("catalina.base"),
486                             pathname);
487         }
488         File JavaDoc dir = file.getParentFile();
489         return dir.exists() && dir.isDirectory() && dir.canWrite();
490
491     }
492
493
494     /**
495      * Save any updated information to the persistent storage location for
496      * this user database.
497      *
498      * @exception Exception if any exception is thrown during saving
499      */

500     public void save() throws Exception JavaDoc {
501
502         if (getReadonly()) {
503             return;
504         }
505
506         if (!isWriteable()) {
507             log.warn(sm.getString("memoryUserDatabase.notPersistable"));
508             return;
509         }
510
511         // Write out contents to a temporary file
512
File JavaDoc fileNew = new File JavaDoc(pathnameNew);
513         if (!fileNew.isAbsolute()) {
514             fileNew =
515                 new File JavaDoc(System.getProperty("catalina.base"), pathnameNew);
516         }
517         PrintWriter JavaDoc writer = null;
518         try {
519
520             // Configure our PrintWriter
521
FileOutputStream JavaDoc fos = new FileOutputStream JavaDoc(fileNew);
522             OutputStreamWriter JavaDoc osw = new OutputStreamWriter JavaDoc(fos, "UTF8");
523             writer = new PrintWriter JavaDoc(osw);
524
525             // Print the file prolog
526
writer.println("<?xml version='1.0' encoding='utf-8'?>");
527             writer.println("<tomcat-users>");
528
529             // Print entries for each defined role, group, and user
530
Iterator JavaDoc values = null;
531             values = getRoles();
532             while (values.hasNext()) {
533                 writer.print(" ");
534                 writer.println(values.next());
535             }
536             values = getGroups();
537             while (values.hasNext()) {
538                 writer.print(" ");
539                 writer.println(values.next());
540             }
541             values = getUsers();
542             while (values.hasNext()) {
543                 writer.print(" ");
544                 writer.println(values.next());
545             }
546
547             // Print the file epilog
548
writer.println("</tomcat-users>");
549
550             // Check for errors that occurred while printing
551
if (writer.checkError()) {
552                 writer.close();
553                 fileNew.delete();
554                 throw new IOException JavaDoc
555                     (sm.getString("memoryUserDatabase.writeException",
556                                   fileNew.getAbsolutePath()));
557             }
558             writer.close();
559         } catch (IOException JavaDoc e) {
560             if (writer != null) {
561                 writer.close();
562             }
563             fileNew.delete();
564             throw e;
565         }
566
567         // Perform the required renames to permanently save this file
568
File JavaDoc fileOld = new File JavaDoc(pathnameOld);
569         if (!fileOld.isAbsolute()) {
570             fileOld =
571                 new File JavaDoc(System.getProperty("catalina.base"), pathnameOld);
572         }
573         fileOld.delete();
574         File JavaDoc fileOrig = new File JavaDoc(pathname);
575         if (!fileOrig.isAbsolute()) {
576             fileOrig =
577                 new File JavaDoc(System.getProperty("catalina.base"), pathname);
578         }
579         if (fileOrig.exists()) {
580             fileOld.delete();
581             if (!fileOrig.renameTo(fileOld)) {
582                 throw new IOException JavaDoc
583                     (sm.getString("memoryUserDatabase.renameOld",
584                                   fileOld.getAbsolutePath()));
585             }
586         }
587         if (!fileNew.renameTo(fileOrig)) {
588             if (fileOld.exists()) {
589                 fileOld.renameTo(fileOrig);
590             }
591             throw new IOException JavaDoc
592                 (sm.getString("memoryUserDatabase.renameNew",
593                               fileOrig.getAbsolutePath()));
594         }
595         fileOld.delete();
596
597     }
598
599
600     /**
601      * Return a String representation of this UserDatabase.
602      */

603     public String JavaDoc toString() {
604
605         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("MemoryUserDatabase[id=");
606         sb.append(this.id);
607         sb.append(",pathname=");
608         sb.append(pathname);
609         sb.append(",groupCount=");
610         sb.append(this.groups.size());
611         sb.append(",roleCount=");
612         sb.append(this.roles.size());
613         sb.append(",userCount=");
614         sb.append(this.users.size());
615         sb.append("]");
616         return (sb.toString());
617
618     }
619
620
621     // -------------------------------------------------------- Package Methods
622

623
624     /**
625      * Return the <code>StringManager</code> for use in looking up messages.
626      */

627     StringManager getStringManager() {
628
629         return (sm);
630
631     }
632
633
634 }
635
636
637
638 /**
639  * Digester object creation factory for group instances.
640  */

641 class MemoryGroupCreationFactory implements ObjectCreationFactory {
642
643     public MemoryGroupCreationFactory(MemoryUserDatabase database) {
644         this.database = database;
645     }
646
647     public Object JavaDoc createObject(Attributes JavaDoc attributes) {
648         String JavaDoc groupname = attributes.getValue("groupname");
649         if (groupname == null) {
650             groupname = attributes.getValue("name");
651         }
652         String JavaDoc description = attributes.getValue("description");
653         String JavaDoc roles = attributes.getValue("roles");
654         Group group = database.createGroup(groupname, description);
655         if (roles != null) {
656             while (roles.length() > 0) {
657                 String JavaDoc rolename = null;
658                 int comma = roles.indexOf(',');
659                 if (comma >= 0) {
660                     rolename = roles.substring(0, comma).trim();
661                     roles = roles.substring(comma + 1);
662                 } else {
663                     rolename = roles.trim();
664                     roles = "";
665                 }
666                 if (rolename.length() > 0) {
667                     Role role = database.findRole(rolename);
668                     if (role == null) {
669                         role = database.createRole(rolename, null);
670                     }
671                     group.addRole(role);
672                 }
673             }
674         }
675         return (group);
676     }
677
678     private MemoryUserDatabase database = null;
679
680     private Digester digester = null;
681
682     public Digester getDigester() {
683         return (this.digester);
684     }
685
686     public void setDigester(Digester digester) {
687         this.digester = digester;
688     }
689
690 }
691
692
693 /**
694  * Digester object creation factory for role instances.
695  */

696 class MemoryRoleCreationFactory implements ObjectCreationFactory {
697
698     public MemoryRoleCreationFactory(MemoryUserDatabase database) {
699         this.database = database;
700     }
701
702     public Object JavaDoc createObject(Attributes JavaDoc attributes) {
703         String JavaDoc rolename = attributes.getValue("rolename");
704         if (rolename == null) {
705             rolename = attributes.getValue("name");
706         }
707         String JavaDoc description = attributes.getValue("description");
708         Role role = database.createRole(rolename, description);
709         return (role);
710     }
711
712     private MemoryUserDatabase database = null;
713
714     private Digester digester = null;
715
716     public Digester getDigester() {
717         return (this.digester);
718     }
719
720     public void setDigester(Digester digester) {
721         this.digester = digester;
722     }
723
724 }
725
726
727 /**
728  * Digester object creation factory for user instances.
729  */

730 class MemoryUserCreationFactory implements ObjectCreationFactory {
731
732     public MemoryUserCreationFactory(MemoryUserDatabase database) {
733         this.database = database;
734     }
735
736     public Object JavaDoc createObject(Attributes JavaDoc attributes) {
737         String JavaDoc username = attributes.getValue("username");
738         if (username == null) {
739             username = attributes.getValue("name");
740         }
741         String JavaDoc password = attributes.getValue("password");
742         String JavaDoc fullName = attributes.getValue("fullName");
743         if (fullName == null) {
744             fullName = attributes.getValue("fullname");
745         }
746         String JavaDoc groups = attributes.getValue("groups");
747         String JavaDoc roles = attributes.getValue("roles");
748         User user = database.createUser(username, password, fullName);
749         if (groups != null) {
750             while (groups.length() > 0) {
751                 String JavaDoc groupname = null;
752                 int comma = groups.indexOf(',');
753                 if (comma >= 0) {
754                     groupname = groups.substring(0, comma).trim();
755                     groups = groups.substring(comma + 1);
756                 } else {
757                     groupname = groups.trim();
758                     groups = "";
759                 }
760                 if (groupname.length() > 0) {
761                     Group group = database.findGroup(groupname);
762                     if (group == null) {
763                         group = database.createGroup(groupname, null);
764                     }
765                     user.addGroup(group);
766                 }
767             }
768         }
769         if (roles != null) {
770             while (roles.length() > 0) {
771                 String JavaDoc rolename = null;
772                 int comma = roles.indexOf(',');
773                 if (comma >= 0) {
774                     rolename = roles.substring(0, comma).trim();
775                     roles = roles.substring(comma + 1);
776                 } else {
777                     rolename = roles.trim();
778                     roles = "";
779                 }
780                 if (rolename.length() > 0) {
781                     Role role = database.findRole(rolename);
782                     if (role == null) {
783                         role = database.createRole(rolename, null);
784                     }
785                     user.addRole(role);
786                 }
787             }
788         }
789         return (user);
790     }
791
792     private MemoryUserDatabase database = null;
793
794     private Digester digester = null;
795
796     public Digester getDigester() {
797         return (this.digester);
798     }
799
800     public void setDigester(Digester digester) {
801         this.digester = digester;
802     }
803
804 }
805
Popular Tags