View Javadoc

1   ////////////////////////////////////////////////////////////////////////////////
2   // MillScript: an Open Spice interpreter and batch website creation tool
3   // Copyright (C) 2001-2004 Open World Ltd
4   // Copyright (C) 2005 Kevin Rogers
5   //
6   // This file is part of MillScript.
7   //
8   // MillScript is free software; you can redistribute it and/or modify it under
9   // the terms of the GNU General Public License as published by the Free
10  // Software Foundation; either version 2 of the License, or (at your option)
11  // any later version.
12  //
13  // MillScript is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  // more details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // MillScript; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA  02111-1307  USA
21  ////////////////////////////////////////////////////////////////////////////////
22  package org.millscript.millscript.loaders;
23  
24  import org.millscript.commons.vfs.VFile;
25  import org.millscript.millscript.alert.Alerts;
26  import org.millscript.millscript.conf.functions.DatabaseLockfileFunction;
27  import org.millscript.millscript.datatypes.DatabaseSource;
28  
29  import java.io.File;
30  import java.io.IOException;
31  import java.util.Properties;
32  
33  import org.postgresql.jdbc3.Jdbc3PoolingDataSource;
34  
35  /**
36   * This class implements a JDBC connection file loader. The idea is to take a
37   * Java properties file containing all the properties required to establish a
38   * JDBC connection and construct a new DataSource. The Java properties file is
39   * expected to look something like:
40   * <pre>
41   * data.source.name = The name of this DataSource
42   * host             = ahost.somewhere.org
43   * port             = 5432
44   * username         = testuser
45   * password         = testpassword
46   * db.name          = test
47   * max.connections  = 10
48   * </pre>
49   * where <code>port</code> and <code>max.connections</code> are optional.
50   *
51   * @see     org.millscript.millscript.loaders.ValueLoader
52   * @see     javax.sql.DataSource
53   * @since   9.6.4
54   */
55  public class JdbcConnectionLoader extends ValueLoader {
56  
57      /**
58       * The Properties object containing the required settings to construct a
59       * database connection pool.
60       */
61      private static Properties connectionProperties = new Properties();
62  
63      /**
64       * Tests if the specified key is defined in the connection properties.
65       *
66       * @param   key a key in the connection properties
67       * @return  <code>true</code> if the connection file defines the specified
68       * key, <code>false</code> otherwise
69       */
70      private boolean containsKey( final String key ) {
71          return connectionProperties.containsKey( key );
72      }
73  
74      /**
75       * Returns the value associated with the specified key, generating a Mishap
76       * if the key is not defined.
77       *
78       * @param   key a key in the connection properties
79       * @return  the string containing the value for the specified key
80       */
81      private String getStringValue( final String key ) {
82  
83          if ( !containsKey( key ) ) {
84  
85              throw(
86                  Alerts.compile(
87                      "Required JDBC connection properties must be defined",
88                      "All required properties must be defined"
89                  ).
90                  culprit( "file", getOrigin() ).
91                  culprit( "key", key ).
92                  mishap()
93              );
94  
95          }
96  
97          String value = connectionProperties.getProperty( key );
98  
99          if ( value == null ) {
100             return "";
101         }
102 
103         return value;
104 
105     }
106 
107     /**
108      * Returns the value, as an int, associated with the specified key,
109      * generating a Mishap if the key is not defined.
110      *
111      * @param   key a key in the connection properties
112      * @return  an int containing the value for the specified key
113      */
114     private int getIntValue( final String key ) {
115 
116         String value = getStringValue( key );
117 
118         try {
119             return Integer.parseInt( value );
120         } catch ( NumberFormatException ex ) {
121             throw(
122                 Alerts.compile(
123                     "JDBC connection property must be an integer",
124                     "Cannot convert the supplied value to an int"
125                 ).
126                 culprit( "file", getOrigin() ).
127                 culprit( "key", key ).
128                 culprit( "value", value ).
129                 mishap()
130             );
131         }
132 
133     }
134 
135     /**
136      * @see org.millscript.millscript.loaders.Loader#loadValue()
137      */
138     @Override
139     public Object loadValue() throws IOException {
140 
141         if ( this.entry instanceof VFile && this.entry.exists() ) {
142             connectionProperties.load( ((VFile) entry).getInputStream() );
143         } else {
144             throw(
145                 Alerts.compile(
146                     "Inventory entry is not a file",
147                     "JDBC connection loader can only be used to load files"
148                 ).culprit( "entry", this.entry ).mishap()
149             );
150         }
151 
152         Jdbc3PoolingDataSource jdbcsource = new Jdbc3PoolingDataSource();
153 
154         // OPTIONAL
155         // The following settings are optional. Nothing bad will happen
156         // if you forget to set these in your connection file.
157 
158         // Set the port the database server is running on
159         if ( containsKey( "port" ) ) {
160             jdbcsource.setPortNumber( getIntValue( "port" ) );
161         }
162 
163         // Set the maximum number of connections available in this pool
164         if ( containsKey( "max.connections" ) ) {
165             jdbcsource.setMaxConnections( getIntValue( "max.connections" ) );
166         }
167 
168         // REQUIRED
169         // All settings below this point are required.
170         // If they are missing an exception will be generated.
171 
172         // Give this data source a name
173         jdbcsource.setDataSourceName( getStringValue( "data.source.name" ) );
174 
175         // Set the server the database is hosted on
176         jdbcsource.setServerName( getStringValue( "host" ) );
177 
178         // Set the database name we want to connect to
179         jdbcsource.setDatabaseName( getStringValue( "db.name" ) );
180 
181         // Set the user name to connect to the database with
182         jdbcsource.setUser( getStringValue( "username" ) );
183 
184         // Set the password for the user
185         jdbcsource.setPassword( getStringValue( "password" ) );
186 
187         // Construct the lockfile for this database connection
188         String templateLF = this.pack.getConfig().getProperty( DatabaseLockfileFunction.KEY );
189         File lf = null;
190 
191         if ( !templateLF.equals( "" ) ) {
192             templateLF = templateLF.replaceAll( "\\$\\{DATABASENAME\\}", getStringValue( "db.name" ) );
193             lf = new File( templateLF );
194         }
195 
196         return new DatabaseSource( jdbcsource.getDataSourceName(), jdbcsource, lf );
197 
198     }
199 
200 }