ulrich
2016-12-27 1fc020b8ce526f562badb1a18318c10e00d54cdf
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
package de.uhilger.um;
 
import de.uhilger.baselink.PersistenceManager;
import de.uhilger.baselink.Record;
import de.uhilger.um.api.UserMgr;
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;
 
/**
 * Hauptklasse der Anwendung Nutzerverwaltung
 * 
 * Hier wird u.a. geprüft, ob die Datenbank vorhanden ist und diese 
 * angelegt, falls nicht. Das SQL zur Anlage der Datenbank findet 
 * sich in WEB-INF/create_database.sql
 * 
 * @author Ulrich Hilger
 */
public class App implements ServletContextListener {
  
  private static final Logger logger = Logger.getLogger(App.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";
  
  public static final String P_DIGESTER = "digester";
  
  /** Name des SQL-Befehls zum Pruefen, ob die Datenbank vorhanden ist */
  public static final String SQL_DB_VORHANDEN = "dbVorhanden";  
  
  /** Boolean-Konstante zur Kennzeichnung von Datenbankergebnissen mit/ohne Blobs */
  public static final boolean WITHOUT_BLOBS = false;
 
  /** Anwendungsweite Referenz zur Datenbank */
  private static PersistenceManager db;
  
  /** Anwendungsweite Referenz zu den SQL-Befehlen */
  private static Properties sql;
  
  /** die Klasse, die von der Nutzerverwaltung zum Verschlüsseln verwendet wird */
  private static Digester digester;
  
  /**
   * 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);
      String digesterClassName = servletContext.getInitParameter(P_DIGESTER);
      digester = (Digester) Class.forName(digesterClassName).newInstance();
    } 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());
      sql = new Properties();
      sql.loadFromXML(new FileInputStream(sqlFile));
      servletContext.setAttribute(UserMgr.UM_SQL_PROPERTIES, sql);
      logger.fine("Abfrage dbVorhanden='" + sql.getProperty(SQL_DB_VORHANDEN) + "'");
    } catch(Exception ex) {
      logger.log(Level.SEVERE, ex.getMessage(), ex);
    }
  }
 
  /* ----------------- statische Getter --------------------- */
  
  /**
   * Das Zugriffsobjekt fuer die Datenbank dieser Webanwendung 
   * ermitteln
   * 
   * @return das Zugriffsobjekt zur Datenbank dieser Webanwendung
   */
  public static PersistenceManager getDatabase() {
    if(db == null) {
      db = new PersistenceManager();
    }
    return db;
  }
  
  public static Digester getDigester() {
    return digester;
  }
  
  /* ----------------- 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 {
      db = new PersistenceManager();
      db.setDataSourceName(servletContext.getInitParameter(P_DSNAME));
      Properties sql = (Properties) servletContext.getAttribute(UserMgr.UM_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);
    }
  }
  
  @SuppressWarnings("rawtypes")
  private boolean dbVorhanden(PersistenceManager pm, String sql) {
    boolean istVorhanden = false;
    List<List<String>> list = pm.select(sql, Record.WITHOUT_BLOBS);
    if(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 
  }
  
}