001 package com.sptci.rwt;
002
003 import java.io.FileNotFoundException;
004 import java.io.Serializable;
005
006 import java.util.ArrayList;
007 import java.util.Collection;
008 import java.util.Collections;
009 import java.util.TreeMap;
010
011 import com.thoughtworks.xstream.XStream;
012
013 import com.sptci.KeyValue;
014 import com.sptci.util.StringUtilities;
015
016 /**
017 * A serializable wrapper used to represent saved SQL queries for
018 * the application. This class will be serialised to the following file
019 * and initialised from the same file during application load:
020 *
021 * <pre><sptrwt.data.directory>/queries.xml</pre>
022 *
023 * <p>© Copyright 2007 <a href='http://sptci.com/' target='_new'>Sans Pareil Technologies, Inc.</a></p>
024 * @author Rakesh Vidyadharan 2007-10-10
025 * @version $Id: Queries.java 4123 2008-05-25 21:49:01Z rakesh $
026 */
027 public class Queries implements Serializable
028 {
029 /**
030 * The encoding to use to serialise and deserialise instances of this
031 * class.
032 *
033 * {@value}
034 */
035 public static final String ENCODING = "UTF-8";
036
037 /**
038 * The name of the file to which this class will be serialised.
039 */
040 public static final String FILE_NAME = "queries.xml";
041
042 /**
043 * The system property used to configure the location of the root directory
044 * under which persistent state information for the application is stored.
045 *
046 * {@value}
047 */
048 public static final String DIRECTORY = "sptrwt.data.directory";
049
050 /**
051 * The {@link com.thoughtworks.xstream.XStream} instance used to serialise
052 * and deserialise instances of this class.
053 */
054 protected static final XStream xstream;
055
056 /**
057 * Static initialiser for {@link #xstream}.
058 */
059 static
060 {
061 xstream = new XStream();
062 xstream.alias( "queries", Queries.class );
063 xstream.alias( "query", Query.class );
064 xstream.alias( "keyValue", KeyValue.class );
065 xstream.alias( "category", Category.class );
066
067 xstream.useAttributeFor( KeyValue.class, "key" );
068 xstream.useAttributeFor( KeyValue.class, "value" );
069 }
070
071 /**
072 * A map used to quickly look up {@link Query} instances by their
073 * {@link Category#name}.
074 */
075 private final TreeMap<String,Category> categories;
076
077 /**
078 * The fully qualified file name to use to serialise this instance into.
079 */
080 private transient String fileName;
081
082 /**
083 * Default constructor. Cannot be instantiated.
084 */
085 protected Queries()
086 {
087 categories = new TreeMap<String,Category>();
088 }
089
090 /**
091 * Create a new instance of the class for the specified user. Saved
092 * files are stored under a directory named after the <code>user</code>
093 * under {@link #DIRECTORY}.
094 *
095 * @see #deserialise
096 * @return The newly initialised instance of the class.
097 * @throws RuntimeException If errors are encountered while deserialising
098 * the persistent state of this instance.
099 */
100 public static Queries getInstance( final String user )
101 {
102 final Queries queries = new Queries();
103 queries.deserialise( user );
104 return queries;
105 }
106
107 /**
108 * Return a {@link java.sql.Query} for the specified category and saved
109 * with the specified unique name.
110 *
111 * @param category The category under which the query is saved.
112 * @param name The unique name used to identify the saved query.
113 * @return The SQL statement associated with the named query, or
114 * <code>null</code> if no such mapping exists.
115 */
116 public Query getQuery( final String category, final String name )
117 {
118 Query query = null;
119 Category cat = categories.get( category );
120 if ( cat != null )
121 {
122 query = cat.getQuery( name );
123 }
124
125 return query;
126 }
127
128 /**
129 * Add the specified query parameters value object to the application
130 * persistent state.
131 *
132 * @see #serialise
133 * @param category The category to associate the query with.
134 * @param query The query to be saved.
135 */
136 public void add( final String category, final Query query )
137 {
138 Category cat = categories.get( category );
139
140 if ( cat == null )
141 {
142 cat = new Category( category );
143 categories.put( category, cat );
144 }
145
146 cat.addQuery( query );
147 serialise();
148 }
149
150 /**
151 * Remove the specified query parameters from the application
152 * persistent state.
153 *
154 * @see #serialise
155 * @param category The category under which the query was saved.
156 * @param name The unique name to use to identify the saved query.
157 */
158 public void delete( final String category, final String name )
159 {
160 final Category cat = categories.get( category );
161 if ( cat != null )
162 {
163 cat.deleteQuery( name );
164 serialise();
165 }
166 }
167
168 /**
169 * Remove the specified category from persistent state. This removes
170 * all saved queries for that category.
171 *
172 * @see #serialise
173 * @param name The name of the category to remove from saved state.
174 */
175 public void delete( final String name )
176 {
177 categories.remove( name );
178 serialise();
179 }
180
181 /**
182 * Deserialise the contents of {@link #FILE_NAME} into this instance.
183 *
184 * @param user The name of the user to use to construct the full filename.
185 * @throws RuntimeException If errors are encountered while deserialising
186 * the persistent state. No exceptions are thrown if the file does
187 * not exist.
188 */
189 protected void deserialise( final String user ) throws RuntimeException
190 {
191 final String separator =
192 System.getProperties().getProperty( "file.separator" );
193
194 final StringBuilder builder = new StringBuilder( 64 );
195 builder.append( System.getProperty( DIRECTORY ) );
196 builder.append( separator );
197 builder.append( user );
198 builder.append( separator );
199 builder.append( FILE_NAME );
200 fileName = builder.toString();
201
202 try
203 {
204 final String xml = StringUtilities.fromFile( fileName, ENCODING );
205 xstream.fromXML( xml, this );
206 }
207 catch ( FileNotFoundException fnfe ) {}
208 catch ( Throwable t )
209 {
210 throw new RuntimeException( "Error deserialising saved instance", t );
211 }
212 }
213
214 /**
215 * Serialise this instance to the {@link #FILE_NAME}.
216 *
217 * @throws RuntimeException If errors are encountered while serialising
218 * the instance.
219 */
220 protected void serialise() throws RuntimeException
221 {
222 try
223 {
224 final String xml = xstream.toXML( this );
225 StringUtilities.toFile( xml, fileName, ENCODING );
226 }
227 catch ( Throwable t )
228 {
229 throw new RuntimeException( t );
230 }
231 }
232
233 /**
234 * Returns the category identified by the name specified.
235 *
236 * @param name The name of the category.
237 * @return The category identified by the name specified, or
238 * <code>null</code> if no such category exists.
239 */
240 public Category getCategory( final String name )
241 {
242 return categories.get( name );
243 }
244
245 /**
246 * Returns the names of the categories under which queries have been
247 * saved.
248 *
249 * @return A read only collection of category names.
250 */
251 public Collection<Category> getCategories()
252 {
253 return Collections.unmodifiableCollection( categories.values() );
254 }
255 }