View Javadoc

1   /*
2    *******************************************************************************
3    * Copyright (c) 2005 Chris Rose and AIMedia
4    * All rights reserved. Datasources and the accompanying materials
5    * are made available under the terms of the Common Public License v1.0
6    * which accompanies this distribution, and is available at
7    * http://www.eclipse.org/legal/cpl-v10.html
8    * 
9    * Contributors:
10   *     Chris Rose
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 }