View Javadoc
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 }