1
2
3
4
5
6
7
8
9
10
11
12 package ca.spaz.cron.datasource;
13
14 import java.io.*;
15 import java.lang.reflect.*;
16 import java.util.*;
17 import java.util.regex.*;
18
19 import org.apache.log4j.Logger;
20
21 import ca.spaz.cron.CRONConfiguration;
22 import ca.spaz.util.ProgressListener;
23
24 /***
25 * A class for managing datasources.
26 *
27 * @author Chris Rose
28 */
29 public class Datasources {
30 /***
31 * Logger for this class
32 */
33 private static final Logger logger = Logger.getLogger(Datasources.class);
34
35 private static Datasources instance;
36
37 private Map mutablemap;
38
39 private Map dsmap;
40
41 private static List dbIDList;
42
43 public static final Datasources getInstance() {
44 if (null == instance) {
45 instance = new Datasources(true);
46 }
47 return instance;
48 }
49
50 public static final void initialize(ProgressListener pl) {
51 if (null == instance) {
52 instance = new Datasources(false);
53 }
54 instance.initDatasources(pl);
55 }
56
57 private Datasources(boolean initialize) {
58 this.dsmap = new HashMap();
59 this.mutablemap = new HashMap();
60 if (initialize) {
61 initDatasources(null);
62 }
63 }
64
65 /***
66 *
67 */
68 private void initDatasources(ProgressListener pl) {
69 if (null != pl) {
70 pl.progressStart();
71 }
72 Pattern dsPattern = Pattern.compile("datasource//.(//d+)//.class");
73 if (null != pl) {
74 pl.progress(5);
75 }
76 ArrayList keys = new ArrayList();
77 for (Iterator iter = getProperties().keySet().iterator(); iter.hasNext();) {
78 String key = (String) iter.next();
79 keys.add(key);
80 }
81 int pstep = 95 / (keys.size() + 1);
82 int progress = 5;
83 for (Iterator iter = keys.iterator(); iter.hasNext();) {
84 String key = (String) iter.next();
85 Matcher m = dsPattern.matcher(key);
86 if (m.matches()) {
87 String dsID = m.group(1);
88 IFoodDatasource ds = null;
89 try {
90 ds = getFoodDataSource(dsID);
91 } catch (Exception e1) {
92 logger.error("initDatasources(ProgressListener)", e1);
93 }
94 if (null != ds) {
95 dsmap.put(dsID, ds);
96 }
97 if (!ds.isAvailable()) {
98 ds.initialize();
99 }
100 }
101 progress += pstep;
102 if (null != pl) {
103 pl.progress(progress);
104 }
105 }
106 getMutableDataSource();
107 if (null != pl) {
108 pl.progress(100);
109 pl.progressFinish();
110 }
111 }
112
113 /***
114 * @return
115 * @throws IOException
116 */
117 private CRONConfiguration getProperties() {
118 return CRONConfiguration.getInstance();
119 }
120
121 /***
122 * Retrieve the unique instance of the user data source. This data source must
123 * accept writing.
124 *
125 * @return an <code>ILocalFoodDatasource</code> instance for this run of the application.
126 */
127 public ILocalFoodDatasource getMutableDataSource() {
128 ILocalFoodDatasource ds = (ILocalFoodDatasource) mutablemap.get("user");
129 if (null == ds) {
130 try {
131 ds = (ILocalFoodDatasource) getFoodDataSource("user");
132 if (!ds.isAvailable()) {
133 ds.initialize();
134 }
135 } catch (Exception e) {
136 logger.error("getMutableDataSource()", e);
137 throw new IllegalStateException("Unable to provide user DS", e);
138 }
139 mutablemap.put("user", ds);
140 }
141 return ds;
142
143 }
144
145 private IFoodDatasource getFoodDataSource(String dskey) throws Exception {
146 String dsClassName = getProperties().getProperty("datasource." + dskey + ".class");
147 int pcount = Integer.valueOf(getProperties().getProperty("datasource." + dskey + ".parametercount", "0")).intValue();
148 Class[] paramClasses = new Class[pcount];
149 String[] paramValues = new String[pcount];
150 for (int i = 0; i < pcount; i++) {
151 int pid = i + 1;
152 String dsParameterValue = getProperties().getProperty("datasource." + dskey + ".parameter." + pid + ".value");
153 paramClasses[i] = String.class;
154 paramValues[i] = dsParameterValue;
155 }
156
157 Class dsClass = Class.forName(dsClassName);
158 Method dsMethod = dsClass.getMethod(getProperties().getProperty("datasource." + dskey + ".method", "createReadonlyFoodSource"), paramClasses);
159 if (!Modifier.isStatic(dsMethod.getModifiers())) {
160 throw new IllegalStateException(dsClass + " must have a static method to create the DS");
161 }
162 IFoodDatasource ret = (IFoodDatasource) dsMethod.invoke(null, paramValues);
163 return ret;
164 }
165
166 /***
167 * Retrieve a list of all functional data sources in the application. This list will
168 * not contain any Datasources that have indicated that they are not available.
169 *
170 * @return a <code>List</code> of <code>IFoodDatasource</code> instances consisting of
171 * only those for which <code>isAvailable()</code> returns <code>true</code>.
172 */
173 public List getDatasources() {
174 return getDatasources(false);
175 }
176
177 /***
178 * Closes all data sources in the application.
179 */
180 public void closeAll() {
181 List ds = getDatasources(true);
182 for (Iterator iter = ds.iterator(); iter.hasNext();) {
183 IFoodDatasource element = (IFoodDatasource) iter.next();
184 element.close();
185 }
186 }
187
188 /***
189 * Retrieve a list of the Food Groups consisting of the union of all food groups in the
190 * various supported data sources.
191 *
192 * @return The food groups available in the application.
193 */
194 public List getFoodGroups() {
195 Set fgs = new HashSet();
196 for (Iterator iter = mutablemap.values().iterator(); iter.hasNext();) {
197 IFoodDatasource element = (IFoodDatasource) iter.next();
198 fgs.addAll(element.getFoodGroups());
199 }
200 for (Iterator iter = dsmap.values().iterator(); iter.hasNext();) {
201 IFoodDatasource element = (IFoodDatasource) iter.next();
202 fgs.addAll(element.getFoodGroups());
203 }
204 return new ArrayList(fgs);
205 }
206
207 /***
208 * Retrieve a list of the Sources listed in the food data sources.
209 *
210 * @return a list of sources.
211 */
212 public List getSources() {
213 Set fgs = new HashSet();
214 for (Iterator iter = mutablemap.values().iterator(); iter.hasNext();) {
215 IFoodDatasource element = (IFoodDatasource) iter.next();
216 fgs.addAll(element.getSources());
217 }
218 for (Iterator iter = dsmap.values().iterator(); iter.hasNext();) {
219 IFoodDatasource element = (IFoodDatasource) iter.next();
220 fgs.addAll(element.getSources());
221 }
222 return new ArrayList(fgs);
223 }
224
225 /***
226 * Retrieve a list of data sources available in the application.
227 *
228 * @param includeUnAvailable Set this to true if the datasources list should
229 * include data sources that indicate that they are unavailable.
230 * @return A List of <code>IFoodDatasource</code> objects representing all
231 * loaded datasources. if <code>includeUnAvailable</code> is <code>true</code>,
232 * this list will include Datasources that are not operational.
233 */
234 public List getDatasources(boolean includeUnAvailable) {
235 List ret = new ArrayList();
236 if (includeUnAvailable) {
237 ret.addAll(mutablemap.values());
238 ret.addAll(dsmap.values());
239 } else {
240 for (Iterator iter = mutablemap.values().iterator(); iter.hasNext();) {
241 ILocalFoodDatasource ds = (ILocalFoodDatasource) iter.next();
242 if (ds.isAvailable()) {
243 ret.add(ds);
244 }
245 }
246 for (Iterator iter = dsmap.values().iterator(); iter.hasNext();) {
247 IFoodDatasource ds = (IFoodDatasource) iter.next();
248 if (ds.isAvailable()) {
249 ret.add(ds);
250 }
251 }
252 }
253 return ret;
254 }
255
256 }