1 /*
2 * $Id$
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22
23 package org.apache.struts.apps.scriptingmailreader.plugin;
24
25
26 import java.io.BufferedInputStream;
27 import java.io.BufferedOutputStream;
28 import java.io.File;
29 import java.io.FileOutputStream;
30
31 import jakarta.servlet.ServletException;
32
33 import org.apache.struts.action.ActionServlet;
34 import org.apache.struts.action.PlugIn;
35 import org.apache.struts.apps.mailreader.dao.impl.memory.MemoryUserDatabase;
36 import org.apache.struts.apps.scriptingmailreader.Constants;
37 import org.apache.struts.config.ModuleConfig;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 /**
42 * <p><strong>MemoryDatabasePlugIn</strong> initializes and finalizes the
43 * persistent storage of User and Subscription information for the Struts
44 * Demonstration Application, using an in-memory database backed by an
45 * XML file.</p>
46 *
47 * <p><strong>IMPLEMENTATION WARNING</strong> - If this web application is run
48 * from a WAR file, or in another environment where reading and writing of the
49 * web application resource is impossible, the initial contents will be copied
50 * to a file in the web application temporary directory provided by the
51 * container. This is for demonstration purposes only - you should
52 * <strong>NOT</strong> assume that files written here will survive a restart
53 * of your servlet container.</p>
54 *
55 * @author Craig R. McClanahan
56 * @version $Rev$ $Date$
57 */
58
59 public final class MemoryDatabasePlugIn implements PlugIn {
60
61
62 // ----------------------------------------------------- Instance Variables
63
64
65 /**
66 * The {@link MemoryUserDatabase} object we construct and make available.
67 */
68 private MemoryUserDatabase database = null;
69
70
71 /**
72 * The {@code Log} instance for this class.
73 */
74 private final static Logger LOG =
75 LoggerFactory.getLogger(MemoryDatabasePlugIn.class);
76
77
78 /**
79 * The {@link ActionServlet} owning this application.
80 */
81 private ActionServlet servlet = null;
82
83
84 // ------------------------------------------------------------- Properties
85
86
87 /**
88 * The web application resource path of our persistent database
89 * storage file.
90 */
91 private String pathname = "/WEB-INF/database.xml";
92
93 public String getPathname() {
94 return (this.pathname);
95 }
96
97 public void setPathname(String pathname) {
98 this.pathname = pathname;
99 }
100
101
102 // --------------------------------------------------------- PlugIn Methods
103
104
105 /**
106 * Gracefully shut down this database, releasing any resources
107 * that were allocated at initialization.
108 */
109 public void destroy() {
110
111 LOG.info("Finalizing memory database plug in");
112
113 if (database != null) {
114 try {
115 database.close();
116 } catch (Exception e) {
117 LOG.error("Closing memory database", e);
118 }
119 }
120
121 servlet.getServletContext().removeAttribute(Constants.DATABASE_KEY);
122 database = null;
123 servlet = null;
124 database = null;
125 }
126
127
128 /**
129 * Initialize and load our initial database from persistent storage.
130 *
131 * @param servlet The ActionServlet for this web application
132 * @param config The ApplicationConfig for our owning module
133 *
134 * @throws ServletException if we cannot configure ourselves correctly
135 */
136 public void init(ActionServlet servlet, ModuleConfig config)
137 throws ServletException {
138
139 LOG.info("Initializing memory database plug in from '{}'",
140 pathname);
141
142 // Remember our associated configuration and servlet
143 this.servlet = servlet;
144
145 // Construct a new database and make it available
146 database = new MemoryUserDatabase();
147 try {
148 String path = calculatePath();
149 LOG.debug(" Loading database from '{}'", path);
150 database.setPathname(path);
151 database.open();
152 } catch (Exception e) {
153 LOG.error("Opening memory database", e);
154 throw new ServletException("Cannot load database from '" +
155 pathname + "'", e);
156 }
157
158 // Make the initialized database available
159 servlet.getServletContext().setAttribute(Constants.DATABASE_KEY,
160 database);
161
162 }
163
164
165 // --------------------------------------------------------- Public Methods
166
167
168
169
170 // -------------------------------------------------------- Private Methods
171
172
173 /**
174 * Calculate and return an absolute pathname to the XML file to contain
175 * our persistent storage information.
176 *
177 * @throws Exception if an input/output error occurs
178 */
179 private String calculatePath() throws Exception {
180
181 // Can we access the database via file I/O?
182 String path = servlet.getServletContext().getRealPath(pathname);
183 if (path != null) {
184 return (path);
185 }
186
187 // Does a copy of this file already exist in our temporary directory
188 File dir = (File)
189 servlet.getServletContext().getAttribute
190 ("jakarta.servlet.context.tempdir");
191 File file = new File(dir, "struts-example-database.xml");
192 if (file.exists()) {
193 return (file.getAbsolutePath());
194 }
195
196 // Copy the static resource to a temporary file and return its path
197 try (BufferedInputStream bis = new BufferedInputStream(
198 servlet.getServletContext().getResourceAsStream(pathname), 1024);
199 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file), 1024)) {
200
201 byte buffer[] = new byte[1024];
202 while (true) {
203 int n = bis.read(buffer);
204 if (n <= 0) {
205 break;
206 }
207 bos.write(buffer, 0, n);
208 }
209 }
210
211 return (file.getAbsolutePath());
212
213 }
214 }