ulrich
2018-02-24 9c2c3c7fa694464e8eb16affe9fdca9363ee0b05
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*
 *  Radiozentrale - Webradio App
 *  Copyright (C) 2018 Ulrich Hilger, http://uhilger.de
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/
 */
 
package de.uhilger.radiozentrale.web;
 
import de.uhilger.baselink.GenericRecord;
import de.uhilger.baselink.PersistenceManager;
import de.uhilger.baselink.Record;
import de.uhilger.radiozentrale.daten.Abspieler;
import de.uhilger.radiozentrale.daten.Sender;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
 
/**
 * Initialisierungsklasse der Anwendung radiozentrale
 * 
 * Hier wird u.a. geprüft, ob die Datenbank vorhanden ist und diese 
 * angelegt, falls nicht. Das SQL-Skript zur Anlage der Datenbank findet 
 * sich in WEB-INF/create_database.sql
 * 
 * @author Ulrich Hilger
 */
public class Initialiser implements ServletContextListener {
  
  private static final Logger logger = Logger.getLogger(Initialiser.class.getName());
 
  /** Name der Datei mit dem SQL-Skript zum Erzeugen der Datenbank */
  private static final String SCRIPT_NAME = "create_database.sql";  
  /** Name der Datei mit den SQL-Kommandos dieser Anwendung */
  public static final String SQL_PROPERTIES_NAME = "sql.properties";
  /** Name des Parameters, unter dem der Name der DataSource im Deployment Descritpor zu finden ist */
  public static final String P_DSNAME = "dsname";
  /** Name, unter dem das Properties-Objekt mit den SQL-Befehlen im ServletContext hinterlegt ist */
  public static final String RZ_SQL_PROPERTIES = "radiozentraleSqlProperties";
  /** Name, unter dem das Zugriffsobjekt zur Datenbank im ServletContext hinterlegt ist */
  public static final String RZ_DB = "radiozentraleDb";
  
    
  /** Name des SQL-Befehls zum Pruefen, ob die Datenbank vorhanden ist */
  public static final String SQL_DB_VORHANDEN = "dbVorhanden";  
  
  public static final String MP_SENDER = "senderMapper";
  public static final String MP_ABSPIELER = "abspielerMapper";
 
  /**
   * Diese Webanwendung initialisieren, also z.B. Elemente instantiieren, die
   * über den Deployment Descritpor veränderlich gehalten sind.
   * 
   * @param servletContext  der zur Laufzeit bestehende ServletContext
   */
  private void initApp(ServletContext servletContext) {
    try {
      initSql(servletContext);
      initDb(servletContext);
    } catch (Exception ex) {
      logger.log(Level.SEVERE, null, ex);
    }
  }
  
 /**
   * Ein Eigenschaften-Objekt mit den SQL-Statements initialisieren, 
   * die von dieser Webanwendung verwendet werden
   * 
   * Die SQL-Kommandos werden aus der Datei 
   * [CatalinaBase]/webapps/[Context]/WEB-INF/sql.properties 
   * gelesen und als Properties-Objekt unter dem von der Konstante 
   * SPOT_SQL_PROPERTIES bezeichneten Namen im ServletContext hinterlegt
   */
  private void initSql(ServletContext servletContext) {
    try {
      File basis = new File(this.getClass().getResource("/").toURI());
      File sqlFile = new File(basis.getParentFile(), SQL_PROPERTIES_NAME);
      logger.fine("lese SQL-Eigenschaften von " + sqlFile.getAbsolutePath());
      Properties sql = new Properties();
      sql.loadFromXML(new FileInputStream(sqlFile));
      servletContext.setAttribute(RZ_SQL_PROPERTIES, sql);
      logger.fine("Abfrage dbVorhanden='" + sql.getProperty(SQL_DB_VORHANDEN) + "'");
    } catch(Exception ex) {
      logger.log(Level.SEVERE, ex.getMessage(), ex);
    }
  }
  
  /* ----------------- Logik zur Datenbank-Erzeugung ------------ */
  
  /*
    Die Logik zur Datenbank-Erzeugung benoetigt zwei Parameter: 
      1. den Namen der DataSource
      2. einen SQL-Befehl, mit dem geprueft werden kann, ob die 
          Datenbank vorhanden ist
  
    Der Name der DataSource ist im Deployment Descriptor unter dem mit 
    P_DSNAME bezeichneten Namen hinterlegt, der SQL-Befehl ist 
    im Properties-Objekt mit den SQL-Befehlen dieser Anwendung unter dem 
    mit SQL_DB_VORHANDEN bezeichneten Namen zu finden.
  */
  
  /**
   * Pruefen, ob die von dieser Webanwendung benoetigte Datenbank 
   * vorhanden ist. Erzeugen der Datenbank, wenn sie nicht vorgefunden 
   * wird.
   * 
   * @param servletContext der ServletContext dieser Webanwendung, in dem 
   * die Parameter zu finden sind, welche die Datenbankverbindung beschreiben
   */
  private void initDb(ServletContext servletContext) {
    try {
      PersistenceManager db = new PersistenceManager();
      db.setDataSourceName(servletContext.getInitParameter(P_DSNAME));
      servletContext.setAttribute(RZ_DB, db);
      initMapper(servletContext);
      Properties sql = (Properties) servletContext.getAttribute(RZ_SQL_PROPERTIES);
      if(!dbVorhanden(db, sql.getProperty(SQL_DB_VORHANDEN))) {
        logger.info("Datenbank ist nicht vorhanden");
        int[] ergebnis = db.executeScript(getSqlSkript());
      }
    } catch(Exception ex) {
      logger.log(Level.INFO, ex.getMessage(), ex);
    }
  }
  
  /**
   * Mapper erzeugen
   * @param servletContext der ServletContext dieser Webanwendung
   */
  /*
  TODO: das noch auf on demand anlegen: GenericRecord wird erst angelegt
   wenn er erstmals benoetigt wird. Ggf. auch einen Mechanismus zum entfernen 
   laenger nicht benoetigter Mapper hinzufuegen
  */
  private void initMapper(ServletContext servletContext) {
    servletContext.setAttribute(MP_SENDER, new GenericRecord(Sender.class));
    servletContext.setAttribute(MP_ABSPIELER, new GenericRecord(Abspieler.class));
  }
  
  @SuppressWarnings("rawtypes")
  private boolean dbVorhanden(PersistenceManager pm, String sql) {
    boolean istVorhanden = false;
    List<List<String>> list = pm.select(sql, Record.WITHOUT_BLOBS);
    if(list != null && list.size() > 1) {
      istVorhanden = true;
      logger.fine("Datenbank ist vorhanden");
    }
    return istVorhanden;
  }
    
  private String getSqlSkript() throws Exception {
    File basis = new File(this.getClass().getResource("/").toURI());
    File skript = new File(basis.getParentFile(), SCRIPT_NAME);
    return fromStream(new FileInputStream(skript));
  }
  
  private String fromStream(InputStream in) throws IOException
  {
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    StringBuilder out = new StringBuilder();
    String line;
    while ((line = reader.readLine()) != null) {
      out.append(line);
    }
    return out.toString();
  }
 
  /* --- ServletContextListener --- */
  
  @Override
  public void contextInitialized(ServletContextEvent sce) {
    ServletContext servletContext = sce.getServletContext();
    initApp(servletContext);
  }
 
  @Override
  public void contextDestroyed(ServletContextEvent sce) {
    // destroy whatever 
    ServletContext ctx = sce.getServletContext();
    ctx.removeAttribute(MP_SENDER);
    ctx.removeAttribute(MP_ABSPIELER);
    ctx.removeAttribute(RZ_SQL_PROPERTIES);
    ctx.removeAttribute(RZ_DB);
  }
  
}