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.webapp.example2.plugin;
24
25
26 import java.io.BufferedInputStream;
27 import java.io.BufferedOutputStream;
28 import java.io.File;
29 import java.io.FileOutputStream;
30 import java.util.ArrayList;
31
32 import jakarta.servlet.ServletException;
33
34 import org.apache.struts.action.ActionServlet;
35 import org.apache.struts.action.PlugIn;
36 import org.apache.struts.apps.mailreader.dao.impl.memory.MemoryUserDatabase;
37 import org.apache.struts.config.ModuleConfig;
38 import org.apache.struts.util.LabelValueBean;
39 import org.apache.struts.webapp.example2.Constants;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 /**
44 * <p><strong>MemoryDatabasePlugIn</strong> initializes and finalizes the
45 * persistent storage of User and Subscription information for the Struts
46 * Demonstration Application, using an in-memory database backed by an
47 * XML file.</p>
48 *
49 * <p><strong>IMPLEMENTATION WARNING</strong> - If this web application is run
50 * from a WAR file, or in another environment where reading and writing of the
51 * web application resource is impossible, the initial contents will be copied
52 * to a file in the web application temporary directory provided by the
53 * container. This is for demonstration purposes only - you should
54 * <strong>NOT</strong> assume that files written here will survive a restart
55 * of your servlet container.</p>
56 *
57 * @author Craig R. McClanahan
58 * @version $Rev$ $Date$
59 */
60
61 public final class MemoryDatabasePlugIn implements PlugIn {
62
63
64 // ----------------------------------------------------- Instance Variables
65
66
67 /**
68 * The {@link MemoryUserDatabase} object we construct and make available.
69 */
70 private MemoryUserDatabase database = null;
71
72
73 /**
74 * The {@code Log} instance for this class.
75 */
76 private final static Logger LOG =
77 LoggerFactory.getLogger(MemoryDatabasePlugIn.class);
78
79
80 /**
81 * The {@link ActionServlet} owning this application.
82 */
83 private ActionServlet servlet = null;
84
85
86 // ------------------------------------------------------------- Properties
87
88
89 /**
90 * The web application resource path of our persistent database
91 * storage file.
92 */
93 private String pathname = "/WEB-INF/database.xml";
94
95 public String getPathname() {
96 return (this.pathname);
97 }
98
99 public void setPathname(String pathname) {
100 this.pathname = pathname;
101 }
102
103
104 // --------------------------------------------------------- PlugIn Methods
105
106
107 /**
108 * Gracefully shut down this database, releasing any resources
109 * that were allocated at initialization.
110 */
111 public void destroy() {
112
113 LOG.info("Finalizing memory database plug in");
114
115 if (database != null) {
116 try {
117 database.close();
118 } catch (Exception e) {
119 LOG.error("Closing memory database", e);
120 }
121 }
122
123 servlet.getServletContext().removeAttribute(Constants.DATABASE_KEY);
124 database = null;
125 servlet = null;
126 database = null;
127
128 }
129
130
131 /**
132 * Initialize and load our initial database from persistent storage.
133 *
134 * @param servlet The ActionServlet for this web application
135 * @param config The ApplicationConfig for our owning module
136 *
137 * @exception ServletException if we cannot configure ourselves correctly
138 */
139 public void init(ActionServlet servlet, ModuleConfig config)
140 throws ServletException {
141
142 LOG.info("Initializing memory database plug in from '{}'",
143 pathname);
144
145 // Remember our associated configuration and servlet
146 this.servlet = servlet;
147
148 // Construct a new database and make it available
149 database = new MemoryUserDatabase();
150 try {
151 String path = calculatePath();
152 LOG.debug(" Loading database from '{}'", path);
153 database.setPathname(path);
154 database.open();
155 } catch (Exception e) {
156 LOG.error("Opening memory database", e);
157 throw new ServletException("Cannot load database from '" +
158 pathname + "'", e);
159 }
160
161 // Make the initialized database available
162 servlet.getServletContext().setAttribute(Constants.DATABASE_KEY,
163 database);
164
165 // Setup and cache other required data
166 setupCache(servlet, config);
167
168 }
169
170
171 // --------------------------------------------------------- Public Methods
172
173
174 // ------------------------------------------------------ Protected Methods
175
176
177 /**
178 * <p>Cache commonly required data as servlet context attributes.</p>
179 *
180 * @param servlet The <code>ActionServlet</code> instance running
181 * this webapp
182 * @param config The <code>ModuleConfig</code> for this application module
183 */
184 protected void setupCache(ActionServlet servlet, ModuleConfig config) {
185
186 // Set up list of server types under "serverTypes"
187 ArrayList<LabelValueBean> serverTypes = new ArrayList<>();
188 serverTypes.add(new LabelValueBean("IMAP Protocol", "imap"));
189 serverTypes.add(new LabelValueBean("POP3 Protocol", "pop3"));
190 servlet.getServletContext().setAttribute("serverTypes", serverTypes);
191
192 }
193
194
195
196
197 // -------------------------------------------------------- Private Methods
198
199
200 /**
201 * Calculate and return an absolute pathname to the XML file to contain
202 * our persistent storage information.
203 *
204 * @exception Exception if an input/output error occurs
205 */
206 private String calculatePath() throws Exception {
207
208 // Can we access the database via file I/O?
209 String path = servlet.getServletContext().getRealPath(pathname);
210 if (path != null) {
211 return (path);
212 }
213
214 // Does a copy of this file already exist in our temporary directory
215 File dir = (File)
216 servlet.getServletContext().getAttribute
217 ("jakarta.servlet.context.tempdir");
218 File file = new File(dir, "struts-example-database.xml");
219 if (file.exists()) {
220 return (file.getAbsolutePath());
221 }
222
223 // Copy the static resource to a temporary file and return its path
224 try (BufferedInputStream bis = new BufferedInputStream(
225 servlet.getServletContext().getResourceAsStream(pathname), 1024);
226 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file), 1024)) {
227
228 byte buffer[] = new byte[1024];
229 while (true) {
230 int n = bis.read(buffer);
231 if (n <= 0) {
232 break;
233 }
234 bos.write(buffer, 0, n);
235 }
236 }
237
238 return (file.getAbsolutePath());
239
240 }
241 }