View Javadoc

1   /*
2    * Copyright 2012-2013 smartics, Kronseder & Reiner GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package de.smartics.properties.spi.config.ds;
17  
18  import java.sql.Connection;
19  import java.sql.PreparedStatement;
20  import java.sql.ResultSet;
21  import java.sql.SQLException;
22  import java.sql.Statement;
23  
24  import de.smartics.properties.api.config.domain.Property;
25  import de.smartics.properties.api.config.domain.PropertyCollection;
26  import de.smartics.properties.api.config.domain.PropertyLocation;
27  import de.smartics.properties.api.config.domain.PropertyProvider;
28  import de.smartics.properties.api.config.domain.key.ConfigurationKey;
29  import de.smartics.util.lang.Arg;
30  
31  /**
32   * Provides access to properties in a data source.
33   */
34  public final class PropertiesStore extends DefaultDataSourceManager implements
35      PropertiesDataSourceAccessor
36  {
37    // ********************************* Fields *********************************
38  
39    // --- constants ------------------------------------------------------------
40  
41    /**
42     * The class version identifier.
43     */
44    private static final long serialVersionUID = 1L;
45  
46    // --- members --------------------------------------------------------------
47  
48    // ****************************** Initializer *******************************
49  
50    // ****************************** Constructors ******************************
51  
52    /**
53     * Default constructor.
54     *
55     * @param builder the builder of manager instance.
56     */
57    protected PropertiesStore(final Builder builder)
58    {
59      super(builder);
60    }
61  
62    // ****************************** Inner Classes *****************************
63  
64    /**
65     * The builder of manager instances.
66     */
67    public static class Builder extends DefaultDataSourceManager.Builder
68    {
69      // ******************************** Fields ********************************
70  
71      // --- constants ----------------------------------------------------------
72  
73      // --- members ------------------------------------------------------------
74  
75      // ***************************** Initializer ******************************
76  
77      // ***************************** Constructors *****************************
78  
79      // ***************************** Inner Classes ****************************
80  
81      // ******************************** Methods *******************************
82  
83      // --- init ---------------------------------------------------------------
84  
85      // --- get&set ------------------------------------------------------------
86  
87      // --- business -----------------------------------------------------------
88  
89      /**
90       * Creates the instance.
91       *
92       * @return the created instance.
93       * @throws NullPointerException if no data source proxy has been provided.
94       */
95      @Override
96      public final PropertiesStore build() throws NullPointerException
97      {
98        Arg.checkNotNull("dataSourceProxy", dataSourceProxy);
99        Arg.checkNotNull("insertOrUpdateSqlStatementTemplate",
100           insertOrUpdateSqlStatementTemplate);
101 
102       return new PropertiesStore(this);
103     }
104 
105     // --- object basics ------------------------------------------------------
106   }
107 
108   // ********************************* Methods ********************************
109 
110   // --- init -----------------------------------------------------------------
111 
112   // --- get&set --------------------------------------------------------------
113 
114   // --- business -------------------------------------------------------------
115 
116   @Override
117   public Property getProperty(final String config, final String name)
118     throws NullPointerException, IllegalArgumentException, DataSourceException
119   {
120     Arg.checkNotBlank("config", config); // NOPMD
121     Arg.checkNotBlank("name", name); // NOPMD
122 
123     final String path = getDataSourceId() + '@' + getTable() + '>' + config;
124     try
125     {
126       final Connection connection =
127           getDataSourceProxy().getDataSource().getConnection();
128 
129       try
130       {
131         final PreparedStatement statement =
132             createGetPropertyStatement(connection);
133         statement.setString(1, config);
134         statement.setString(2, name);
135         final ResultSet resultSet = statement.executeQuery();
136         final String value;
137         if (resultSet.next())
138         {
139           value = resultSet.getString(1);
140         }
141         else
142         {
143           value = null;
144         }
145         return new Property(new PropertyLocation(path), name, value);
146       }
147       finally
148       {
149         connection.close();
150       }
151     }
152     catch (final SQLException e)
153     {
154       final String dataSourceId = getDataSourceId();
155       throw new DataSourceException(new DataSourcePropertyKeyMessageBean(
156           DataSourceCode.CANNOT_ACCESS_PROPERTY, e, dataSourceId, path, name));
157     }
158   }
159 
160   @Override
161   public void setProperty(final String config, final String name,
162       final String value) throws IllegalArgumentException, DataSourceException
163   {
164     Arg.checkNotBlank("config", config);
165     Arg.checkNotBlank("name", name);
166 
167     try
168     {
169       final Connection connection =
170           getDataSourceProxy().getDataSource().getConnection();
171 
172       try
173       {
174         final PreparedStatement statement =
175             createSetPropertyStatement(connection);
176 
177         getDataSourceProxy().setInsertOrUpdate(statement, config, name, value);
178         statement.executeUpdate();
179       }
180       finally
181       {
182         connection.close();
183       }
184     }
185     catch (final SQLException e)
186     {
187       final String dataSourceId = getDataSourceId();
188       final String path = dataSourceId + '@' + getTable() + '>' + config;
189       throw new DataSourceException(new DataSourcePropertyMessageBean(
190           DataSourceCode.CANNOT_STORE_PROPERTY, e, dataSourceId, path, name,
191           value));
192     }
193   }
194 
195   @Override
196   public void setProperties(final PropertyProvider provider)
197     throws NullPointerException, DataSourceException
198   {
199     Arg.checkNotNull("provider", provider);
200 
201     final ConfigurationKey<?> key = provider.getConfigurationKey();
202     final String config = key.toString();
203 
204     try
205     {
206       final Connection connection =
207           getDataSourceProxy().getDataSource().getConnection();
208 
209       try
210       {
211         final PreparedStatement statement =
212             createSetPropertyStatement(connection);
213 
214         storeProperties(provider, config, statement);
215       }
216       finally
217       {
218         connection.close();
219       }
220     }
221     catch (final SQLException e)
222     {
223       final String dataSourceId = getDataSourceId();
224       throw new DataSourceException(new DataSourceConfigurationMessageBean(
225           DataSourceCode.CANNOT_STORE_PROPERTIES, e, dataSourceId, config));
226     }
227   }
228 
229   private void storeProperties(final PropertyProvider provider,
230       final String config, final PreparedStatement statement)
231   {
232     for (final Property property : provider.getProperties())
233     {
234       final String name = property.getName();
235       final String value = property.getValue();
236 
237       try
238       {
239         statement.setString(1, config);
240         statement.setString(2, name);
241         statement.setString(3, value);
242         // statement.setString(4, config);
243         // statement.setString(5, name);
244         statement.setString(4, value);
245         statement.executeUpdate();
246       }
247       catch (final SQLException e)
248       {
249         final String dataSourceId = getDataSourceId();
250         final String path = dataSourceId + '@' + getTable() + '>' + config;
251         throw new DataSourceException(new DataSourcePropertyMessageBean(
252             DataSourceCode.CANNOT_STORE_PROPERTY, e, dataSourceId, path, name,
253             value));
254       }
255     }
256   }
257 
258   @Override
259   public void deleteProperty(final String config, final String name)
260     throws IllegalArgumentException, DataSourceException
261   {
262     Arg.checkNotBlank("config", config);
263     Arg.checkNotBlank("name", name);
264 
265     try
266     {
267       final Connection connection =
268           getDataSourceProxy().getDataSource().getConnection();
269 
270       try
271       {
272         final PreparedStatement statement =
273             createDeletePropertyStatement(connection);
274         statement.setString(1, config);
275         statement.setString(2, name);
276         statement.executeUpdate();
277       }
278       finally
279       {
280         connection.close();
281       }
282     }
283     catch (final SQLException e)
284     {
285       final String dataSourceId = getDataSourceId();
286       final String path = dataSourceId + '@' + getTable() + '>' + config;
287       throw new DataSourceException(new DataSourcePropertyKeyMessageBean(
288           DataSourceCode.CANNOT_DELETE_PROPERTY, e, dataSourceId, path, name));
289     }
290   }
291 
292   /**
293    * The collection of all properties stored.
294    *
295    * @param config the name of the configuration the property is part of.
296    * @return the collection of all properties stored.
297    * @throws DataSourceException on any database problem.
298    */
299   public PropertyCollection getCollection(final String config)
300     throws DataSourceException
301   {
302     try
303     {
304       final Connection connection =
305           getDataSourceProxy().getDataSource().getConnection();
306 
307       final PreparedStatement statement =
308           createGetPropertiesStatement(connection);
309       statement.setString(1, config);
310       final ResultSet resultSet = statement.executeQuery(); // NOPMD
311       final String path = getDataSourceId() + '@' + getTable() + '>' + config;
312       final DsPropertyCollection collection =
313           new DsPropertyCollection(path, connection, resultSet);
314       return collection;
315     }
316     catch (final SQLException e)
317     {
318       final String dataSourceId = getDataSourceId();
319       throw new DataSourceException(new DataSourceConfigurationMessageBean(
320           DataSourceCode.CANNOT_ACCESS_PROPERTIES, e, dataSourceId, config));
321     }
322   }
323 
324   /**
325    * Checks if a property with the given {@code name} is stored.
326    *
327    * @param config the name of the configuration the property is part of.
328    * @param name the name of the property to check if it is stored.
329    * @return <code>true</code> if there is a property with that name and a non-
330    *         <code>null</code> value, <code>false</code> otherwise.
331    * @throws IllegalArgumentException if {@code config} or {@code name} is
332    *           blank.
333    */
334   public boolean containsKey(final String config, final String name)
335     throws IllegalArgumentException
336   {
337     final Property property = getProperty(config, name);
338     return property.getValue() != null;
339   }
340 
341   private PreparedStatement createGetPropertyStatement(
342       final Connection connection) throws SQLException
343   {
344     final String sql =
345         "SELECT " + getValueColumn() + " FROM " + getTable() + " WHERE "
346             + getConfigColumn() + " = ?" + " AND " + getNameColumn() + " = ?"; // NOPMD
347     return connection.prepareStatement(sql);
348   }
349 
350   private PreparedStatement createGetPropertiesStatement(
351       final Connection connection) throws SQLException
352   {
353     final String sql =
354         "SELECT " + getNameColumn() + ", " + getValueColumn() + " FROM "
355             + getTable() + " WHERE " + getConfigColumn() + "= ?";
356     return connection.prepareStatement(sql);
357   }
358 
359   private PreparedStatement createSetPropertyStatement(
360       final Connection connection) throws SQLException
361   {
362     final String sql = getInsertOrUpdateSqlStatementTemplate();
363     return connection.prepareStatement(sql);
364   }
365 
366   private PreparedStatement createDeletePropertyStatement(
367       final Connection connection) throws SQLException
368   {
369     final String sql =
370         "DELETE FROM " + getTable() + " WHERE " + getConfigColumn()
371             + " = ? AND " + getNameColumn() + " = ? ";
372     return connection.prepareStatement(sql);
373   }
374 
375   /**
376    * Deletes all properties.
377    *
378    * @throws DataSourceException on any database problem.
379    */
380   public void deleteProperties() throws DataSourceException
381   {
382     final String sql = "DELETE FROM " + getTable();
383     try
384     {
385       final Connection connection =
386           getDataSourceProxy().getDataSource().getConnection();
387       try
388       {
389         final Statement statement = connection.createStatement();
390         statement.executeUpdate(sql);
391       }
392       finally
393       {
394         connection.close();
395       }
396     }
397     catch (final SQLException e)
398     {
399       final String dataSourceId = getDataSourceId();
400       throw new DataSourceException(new DataSourceMessageBean(
401           DataSourceCode.CANNOT_DELETE_PROPERTIES, e, dataSourceId));
402     }
403   }
404 
405   // --- object basics --------------------------------------------------------
406 
407 }