001: /*
002: * $Id: MemoryUserDatabase.java 471754 2006-11-06 14:55:09Z husted $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021: package org.apache.struts.apps.mailreader.dao.impl.memory;
022:
023: import java.io.BufferedInputStream;
024: import java.io.File;
025: import java.io.FileInputStream;
026: import java.io.FileOutputStream;
027: import java.io.IOException;
028: import java.io.OutputStreamWriter;
029: import java.io.PrintWriter;
030: import java.util.HashMap;
031:
032: import org.apache.commons.digester.Digester;
033: import org.apache.commons.digester.ObjectCreationFactory;
034: import org.apache.commons.logging.Log;
035: import org.apache.commons.logging.LogFactory;
036: import org.apache.struts.apps.mailreader.dao.Subscription;
037: import org.apache.struts.apps.mailreader.dao.User;
038: import org.apache.struts.apps.mailreader.dao.UserDatabase;
039: import org.xml.sax.Attributes;
040:
041: /**
042: * <p>Concrete implementation of {@link UserDatabase} for an in-memory
043: * database backed by an XML data file.</p>
044: *
045: * @version $Rev: 471754 $ $Date: 2006-11-06 08:55:09 -0600 (Mon, 06 Nov 2006) $
046: * @since Struts 1.1
047: */
048:
049: public class MemoryUserDatabase implements UserDatabase {
050:
051: // ----------------------------------------------------------- Constructors
052:
053: // ----------------------------------------------------- Instance Variables
054:
055: /**
056: * Logging output for this user database instance.
057: */
058: private Log log = LogFactory.getLog(this .getClass());
059:
060: /**
061: * The {@link User}s associated with this UserDatabase, keyed by username.
062: */
063: private HashMap users = new HashMap();
064:
065: private boolean open = false;
066:
067: // ------------------------------------------------------------- Properties
068:
069: /**
070: * Absolute pathname to the persistent file we use for loading and storing
071: * persistent data.
072: */
073: private String pathname = null;
074:
075: private String pathnameOld = null;
076:
077: private String pathnameNew = null;
078:
079: public String getPathname() {
080: return (this .pathname);
081: }
082:
083: public void setPathname(String pathname) {
084: this .pathname = pathname;
085: pathnameOld = pathname + ".old";
086: pathnameNew = pathname + ".new";
087: }
088:
089: // --------------------------------------------------------- Public Methods
090:
091: // See interface for Javadoc
092: public void close() throws Exception {
093:
094: save();
095: this .open = false;
096:
097: }
098:
099: // See interface for Javadoc
100: public User createUser(String username) {
101:
102: synchronized (users) {
103: if (users.get(username) != null) {
104: throw new IllegalArgumentException("Duplicate user '"
105: + username + "'");
106: }
107: if (log.isTraceEnabled()) {
108: log.trace("Creating user '" + username + "'");
109: }
110: MemoryUser user = new MemoryUser(this , username);
111: synchronized (users) {
112: users.put(username, user);
113: }
114: return (user);
115: }
116:
117: }
118:
119: // See interface for Javadoc
120: public User findUser(String username) {
121:
122: synchronized (users) {
123: return ((User) users.get(username));
124: }
125:
126: }
127:
128: // See interface for Javadoc
129: public User[] findUsers() {
130:
131: synchronized (users) {
132: User results[] = new User[users.size()];
133: return ((User[]) users.values().toArray(results));
134: }
135:
136: }
137:
138: // See interface for Javadoc
139: public void open() throws Exception {
140:
141: FileInputStream fis = null;
142: BufferedInputStream bis = null;
143:
144: try {
145:
146: // Acquire an input stream to our database file
147: if (log.isDebugEnabled()) {
148: log.debug("Loading database from '" + pathname + "'");
149: }
150: fis = new FileInputStream(pathname);
151: bis = new BufferedInputStream(fis);
152:
153: // Construct a digester to use for parsing
154: Digester digester = new Digester();
155: digester.push(this );
156: digester.setValidating(false);
157: digester.addFactoryCreate("database/user",
158: new MemoryUserCreationFactory(this ));
159: digester.addFactoryCreate("database/user/subscription",
160: new MemorySubscriptionCreationFactory());
161:
162: // Parse the input stream to initialize our database
163: digester.parse(bis);
164: bis.close();
165: bis = null;
166: fis = null;
167: this .open = true;
168:
169: } catch (Exception e) {
170:
171: log.error("Loading database from '" + pathname + "':", e);
172: throw e;
173:
174: } finally {
175:
176: if (bis != null) {
177: try {
178: bis.close();
179: } catch (Throwable t) {
180: // do nothing
181: }
182: bis = null;
183: fis = null;
184: }
185:
186: }
187:
188: }
189:
190: // See interface for Javadoc
191: public void removeUser(User user) {
192:
193: if (!(this == user.getDatabase())) {
194: throw new IllegalArgumentException(
195: "User not associated with this database");
196: }
197: if (log.isTraceEnabled()) {
198: log.trace("Removing user '" + user.getUsername() + "'");
199: }
200: synchronized (users) {
201: users.remove(user.getUsername());
202: }
203:
204: }
205:
206: // See interface for Javadoc
207: public void save() throws Exception {
208:
209: if (log.isDebugEnabled()) {
210: log.debug("Saving database to '" + pathname + "'");
211: }
212: File fileNew = new File(pathnameNew);
213: PrintWriter writer = null;
214:
215: try {
216:
217: // Configure our PrintWriter
218: FileOutputStream fos = new FileOutputStream(fileNew);
219: OutputStreamWriter osw = new OutputStreamWriter(fos);
220: writer = new PrintWriter(osw);
221:
222: // Print the file prolog
223: writer.println("<?xml version='1.0'?>");
224: writer.println("<database>");
225:
226: // Print entries for each defined user and associated subscriptions
227: User yusers[] = findUsers();
228: for (int i = 0; i < yusers.length; i++) {
229: writer.print(" ");
230: writer.println(yusers[i]);
231: Subscription subscriptions[] = yusers[i]
232: .getSubscriptions();
233: for (int j = 0; j < subscriptions.length; j++) {
234: writer.print(" ");
235: writer.println(subscriptions[j]);
236: writer.print(" ");
237: writer.println("</subscription>");
238: }
239: writer.print(" ");
240: writer.println("</user>");
241: }
242:
243: // Print the file epilog
244: writer.println("</database>");
245:
246: // Check for errors that occurred while printing
247: if (writer.checkError()) {
248: writer.close();
249: fileNew.delete();
250: throw new IOException("Saving database to '" + pathname
251: + "'");
252: }
253: writer.close();
254: writer = null;
255:
256: } catch (IOException e) {
257:
258: if (writer != null) {
259: writer.close();
260: }
261: fileNew.delete();
262: throw e;
263:
264: }
265:
266: // Perform the required renames to permanently save this file
267: File fileOrig = new File(pathname);
268: File fileOld = new File(pathnameOld);
269: if (fileOrig.exists()) {
270: fileOld.delete();
271: if (!fileOrig.renameTo(fileOld)) {
272: throw new IOException("Renaming '" + pathname
273: + "' to '" + pathnameOld + "'");
274: }
275: }
276: if (!fileNew.renameTo(fileOrig)) {
277: if (fileOld.exists()) {
278: fileOld.renameTo(fileOrig);
279: }
280: throw new IOException("Renaming '" + pathnameNew + "' to '"
281: + pathname + "'");
282: }
283: fileOld.delete();
284:
285: }
286:
287: public boolean isOpen() {
288: return this .open;
289: }
290:
291: }
292:
293: /**
294: * Digester object creation factory for subscription instances.
295: */
296: class MemorySubscriptionCreationFactory implements
297: ObjectCreationFactory {
298:
299: private Digester digester = null;
300:
301: public Digester getDigester() {
302: return (this .digester);
303: }
304:
305: public void setDigester(Digester digester) {
306: this .digester = digester;
307: }
308:
309: public Object createObject(Attributes attributes) {
310: String host = attributes.getValue("host");
311: User user = (User) digester.peek();
312: Subscription subscription = user.createSubscription(host);
313: String autoConnect = attributes.getValue("autoConnect");
314: if (autoConnect == null) {
315: autoConnect = "false";
316: }
317: if ("true".equalsIgnoreCase(autoConnect)
318: || "yes".equalsIgnoreCase(autoConnect)) {
319: subscription.setAutoConnect(true);
320: } else {
321: subscription.setAutoConnect(false);
322: }
323: subscription.setPassword(attributes.getValue("password"));
324: subscription.setType(attributes.getValue("type"));
325: subscription.setUsername(attributes.getValue("username"));
326: return (subscription);
327: }
328:
329: }
330:
331: /**
332: * Digester object creation factory for user instances.
333: */
334: class MemoryUserCreationFactory implements ObjectCreationFactory {
335:
336: public MemoryUserCreationFactory(MemoryUserDatabase database) {
337: this .database = database;
338: }
339:
340: private MemoryUserDatabase database = null;
341:
342: private Digester digester = null;
343:
344: public Digester getDigester() {
345: return (this .digester);
346: }
347:
348: public void setDigester(Digester digester) {
349: this .digester = digester;
350: }
351:
352: public Object createObject(Attributes attributes) {
353: String username = attributes.getValue("username");
354: User user = database.createUser(username);
355: user.setFromAddress(attributes.getValue("fromAddress"));
356: user.setFullName(attributes.getValue("fullName"));
357: user.setPassword(attributes.getValue("password"));
358: user.setReplyToAddress(attributes.getValue("replyToAddress"));
359: return (user);
360: }
361:
362: }
|