View Javadoc

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.james.user.impl.file;
21  
22  import java.io.BufferedInputStream;
23  import java.io.BufferedOutputStream;
24  import java.io.File;
25  import java.io.FileInputStream;
26  import java.io.FileOutputStream;
27  import java.io.IOException;
28  import java.io.ObjectInputStream;
29  import java.io.ObjectOutputStream;
30  import java.io.Serializable;
31  
32  import org.apache.commons.io.FileUtils;
33  import org.apache.commons.io.IOUtils;
34  import org.apache.james.api.user.UserMetaDataRespository;
35  import org.apache.james.api.user.UserRepositoryException;
36  
37  /**
38   * Stores user meta-data in the file system.
39   */
40  public class FileUserMetaDataRepository implements UserMetaDataRespository {
41      
42      private static final String SERIALIZED_FILE_TYPE_NAME = ".ser";
43  
44      /** Characters that may safely be used to create names */
45      private final static char[] SAFE_CHARS = {
46          'a','b','c','d','e','f','g','h','i','j',
47          'k','l','m','n','o','p','q','r','s','t',
48          'u','v','w','x','y','z','0','1','2','3',
49          '4','5','6','7','8','9'
50      };
51      
52      private final String baseDirectory;
53      
54      public FileUserMetaDataRepository(final String baseDirectory) {
55          super();
56          this.baseDirectory = baseDirectory;
57      }
58  
59      public void clear(String username) throws UserRepositoryException {
60          final File userDir = userDirectory(username);
61          try {
62              FileUtils.deleteDirectory(userDir);
63          } catch (IOException e) {
64              throw new UserRepositoryException("Cannot delete " + userDir.getAbsolutePath(), e);
65          }
66      }
67  
68      public Serializable getAttribute(String username, String key)
69              throws UserRepositoryException {
70          final File valueFile = valueFile(username, key);
71          final Serializable result;
72          if (valueFile.exists()) {
73              ObjectInputStream in = null;
74              try {
75                  in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(valueFile)));
76                  result = (Serializable) in.readObject();
77              } catch (IOException e) {
78                  throw new UserRepositoryException(e);
79              } catch (ClassNotFoundException e) {
80                  throw new UserRepositoryException(e);
81              } finally {
82                  IOUtils.closeQuietly(in);
83              }
84              
85          } else {
86              result = null;
87          }
88          return result;
89      }
90  
91      public void setAttribute(String username, Serializable value, String key)
92              throws UserRepositoryException {
93  
94          final File valueFile = valueFile(username, key);
95          ObjectOutputStream out = null;
96          try {
97              
98              out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(valueFile)));
99              out.writeObject(value);
100             
101         } catch (IOException e) {
102             throw new UserRepositoryException(e);
103         } finally {
104             IOUtils.closeQuietly(out);
105         }
106     }
107 
108     private File valueFile(String username, String key) throws UserRepositoryException {
109         final File userDir = userDirectory(username);
110         
111         final String valueFileName = fileSystemSafeName(key, SERIALIZED_FILE_TYPE_NAME);
112         final File valueFile = new File(userDir, valueFileName);
113         return valueFile;
114     }
115 
116     private File userDirectory(String username) throws UserRepositoryException {
117         final File baseDir = getBaseDirectory();
118         
119         final String userDirectoryName = fileSystemSafeName(username);
120         final File userDir = new File(baseDir, userDirectoryName);
121         if (!userDir.exists()) {
122             if (!userDir.mkdir()) {
123                 throw new UserRepositoryException("Cannot create directory: " + userDir.getAbsolutePath());
124             }
125         }
126         return userDir;
127     }
128 
129     private File getBaseDirectory() throws UserRepositoryException {
130         final File baseDir = new File(baseDirectory);
131         if (!baseDir.exists()) {
132             if (!baseDir.mkdirs()) {
133                 throw new UserRepositoryException("Cannot create directory: " + baseDirectory);
134             }
135         }
136         return baseDir;
137     }
138 
139     /**
140      * Maps a value to a file-system safe name.
141      * @param value name, not null
142      * @param suffix optional suffix to be append, possibly null
143      * @return file system safe mapping of the name
144      */
145     private String fileSystemSafeName(String value) {
146         return fileSystemSafeName(value, null);
147     }
148     
149     /**
150      * Maps a value to a file-system safe name.
151      * @param value name, not null
152      * @param suffix optional suffix to be append, possibly null
153      * @return file system safe mapping of the name
154      */
155     private String fileSystemSafeName(String value, String suffix) {
156         final int length = value.length();
157         final StringBuffer buffer = new StringBuffer(length * 10);
158         for (int i=0;i<length;i++) {
159             final int next = value.charAt(i);
160             for (int j=0;j<4;j++) {
161                 buffer.append(SAFE_CHARS[(next >> j * 4) % 32]);
162             }
163         }
164         if (suffix != null) {
165             buffer.append(suffix);
166         }
167         final String result = buffer.toString();
168         return result;
169     }
170 }