View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.log4j.chainsaw.prefs;
18  
19  import java.io.BufferedInputStream;
20  import java.io.BufferedOutputStream;
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.FileOutputStream;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.OutputStream;
27  import java.net.URLEncoder;
28  import java.util.EventListener;
29  import java.util.Properties;
30  
31  import javax.swing.event.EventListenerList;
32  
33  
34  /**
35   * SettingManager allows components to register interest in Saving/Loading
36   * of general application preferences/settings.
37   *
38   * @author Paul Smith <psmith@apache.org>
39   * @author Scott Deboy <sdeboy@apache.org>
40   *
41   */
42  public final class SettingsManager {
43      private static final SettingsManager instance = new SettingsManager();
44      private static final String GLOBAL_SETTINGS_FILE_NAME = "chainsaw.settings.properties";
45      private static final String HEADER = "Chainsaws Settings Files";
46      private EventListenerList listenerList = new EventListenerList();
47      private Properties defaultProperties = new Properties();
48  
49      /**
50       * Initialises the SettingsManager by loading the default Properties from
51       * a resource
52       *
53       */
54      private SettingsManager() {
55          //	load the default properties as a Resource
56          InputStream is = null;
57  
58          try {
59              is = this.getClass().getClassLoader()
60                       .getResource("org/apache/log4j/chainsaw/prefs/default.properties")
61                       .openStream();
62              defaultProperties.load(is);
63  
64              //      defaultProperties.list(System.out);
65              is.close();
66          } catch (IOException e) {
67              e.printStackTrace();
68          } finally {
69              if (is != null) {
70                  try {
71                      is.close();
72                  } catch (Exception e) {
73                  }
74              }
75          }
76      }
77  
78      /**
79       * Returns the singleton instance of the SettingsManager
80       * @return settings manager
81       */
82      public static SettingsManager getInstance() {
83          return instance;
84      }
85  
86      /**
87       * Registers the listener with the manager
88       * @param listener
89       */
90      public void addSettingsListener(SettingsListener listener) {
91          listenerList.add(SettingsListener.class, listener);
92      }
93  
94      /**
95       * Requests that the settings be loaded, all listeners will be notified of
96       * this call, and configure themselves according to the values found in the
97       * loaded settings
98       *
99       */
100     public void loadSettings() {
101         /*
102          * Ok, note we ensure we have a .chainsaw directory in the users
103          * home folder, and create a chainsaw.settings.properties file..
104          */
105         File settingsDir = getSettingsDirectory();
106 
107         if (!settingsDir.exists()) {
108             settingsDir.mkdir();
109         }
110 
111         loadGlobalSettings();
112         loadProfileableSettings();
113     }
114 
115     /**
116      *
117      */
118     private void loadProfileableSettings() {
119         EventListener[] listeners = listenerList.getListeners(SettingsListener.class);
120 
121         for (int i = 0; i < listeners.length; i++) {
122             SettingsListener settingsListener = (SettingsListener) listeners[i];
123 
124             if (settingsListener instanceof Profileable) {
125                 Profileable p = (Profileable) settingsListener;
126                 loadProfileble(p);
127             }
128         }
129     }
130 
131     private void loadProfileble(Profileable p) {
132         LoadSettingsEvent event = createProfilebleEvent(p);
133         p.loadSettings(event);
134     }
135 
136     private LoadSettingsEvent createProfilebleEvent(Profileable p) {
137         Properties loadedProperties = new Properties();
138         loadedProperties.putAll(getDefaultSettings());
139         loadedProperties.putAll(loadProperties(p));
140         
141 
142         LoadSettingsEvent event = new LoadSettingsEvent(this, loadedProperties);
143 
144         return event;
145     }
146 
147     /**
148      * @param p
149      * @return
150      */
151     private Properties loadProperties(Profileable p) {
152         Properties properties = new Properties(defaultProperties);
153         InputStream is = null;
154 
155         File f = new File(getSettingsDirectory(),
156         		URLEncoder.encode(p.getNamespace() + ".properties"));
157         
158         if (!f.exists()) {
159         	f = new File(getSettingsDirectory(),
160             		p.getNamespace() + ".properties");        	
161         }
162 
163         if (f.exists()) {
164             try {
165                 is = new BufferedInputStream(new FileInputStream(f));
166 
167                 Properties toLoad = new Properties();
168                 toLoad.load(is);
169                 properties.putAll(toLoad);
170             } catch (IOException ioe) {
171                 ioe.printStackTrace();
172             } finally {
173                 if (is != null) {
174                     try {
175                         is.close();
176                     } catch (IOException e1) {
177                         e1.printStackTrace();
178                     }
179                 }
180             }
181         }
182 
183         return properties;
184     }
185 
186     private void loadGlobalSettings() {
187         EventListener[] listeners = listenerList.getListeners(SettingsListener.class);
188         LoadSettingsEvent event = null;
189 
190         for (int i = 0; i < listeners.length; i++) {
191             SettingsListener settingsListener = (SettingsListener) listeners[i];
192 
193             if (event == null) {
194                 Properties loadedProperties = loadGlobalProperties();
195 
196                 //        loadedProperties.list(System.out);
197                 event = new LoadSettingsEvent(this, loadedProperties);
198             }
199 
200             settingsListener.loadSettings(event);
201         }
202     }
203 
204     /**
205      * Creates a SaveSettingsEvent and calls all the SettingsListeners
206      * to populate the properties with configuration information
207      *
208      */
209     public void saveSettings() {
210         /*
211          * Ok, note we ensure we have a .chainsaw directory in the users
212          * home folder, and create a chainsaw.settings.properties file..
213          */
214         File settingsDir = getSettingsDirectory();
215 
216         if (!settingsDir.exists()) {
217             settingsDir.mkdir();
218         }
219 
220         saveGlobalSettings(settingsDir);
221         saveProfileableSetting(settingsDir);
222     }
223 
224     /**
225      * Looks up all the Profileable's that have been registered
226      * and creates a new event for each of them, and ensures that they
227      * are saved within a separate external store
228      * @param settingsDir
229      */
230     private void saveProfileableSetting(File settingsDir) {
231         EventListener[] listeners = listenerList.getListeners(SettingsListener.class);
232         SaveSettingsEvent event = null;
233 
234         for (int i = 0; i < listeners.length; i++) {
235             SettingsListener settingsListener = (SettingsListener) listeners[i];
236 
237             if (settingsListener instanceof Profileable) {
238                 Profileable profileable = (Profileable) settingsListener;
239                 event = new SaveSettingsEvent(this, getSettingsDirectory());
240 
241                 profileable.saveSettings(event);
242 
243                 OutputStream os = null;
244 
245                 try {
246                     os = new BufferedOutputStream(new FileOutputStream(
247                                 new File(settingsDir,
248                                 		 URLEncoder.encode(profileable.getNamespace()) + ".properties")));
249                     event.getProperties().store(os, HEADER);
250                 } catch (Exception e) {
251                     e.printStackTrace();
252                 } finally {
253                     if (os != null) {
254                         try {
255                             os.close();
256                         } catch (IOException e1) {
257                             e1.printStackTrace();
258                         }
259                     }
260                 }
261             }
262         }
263     }
264 
265     private void saveGlobalSettings(File settingsDir) {
266         EventListener[] listeners = listenerList.getListeners(SettingsListener.class);
267         SaveSettingsEvent event = null;
268 
269         for (int i = 0; i < listeners.length; i++) {
270             SettingsListener settingsListener = (SettingsListener) listeners[i];
271 
272             if (!(settingsListener instanceof Profileable)) {
273                 if (event == null) {
274                     event = new SaveSettingsEvent(this, getSettingsDirectory());
275                 }
276 
277                 settingsListener.saveSettings(event);
278             }
279         }
280 
281         OutputStream os = null;
282 
283         try {
284             os = new BufferedOutputStream(new FileOutputStream(
285                         new File(settingsDir, GLOBAL_SETTINGS_FILE_NAME)));
286             event.getProperties().store(os, HEADER);
287         } catch (Exception e) {
288             e.printStackTrace();
289         } finally {
290             if (os != null) {
291                 try {
292                     os.close();
293                 } catch (IOException e1) {
294                     e1.printStackTrace();
295                 }
296             }
297         }
298     }
299 
300     public File getSettingsDirectory() {
301         return new File(System.getProperty("user.home"), ".chainsaw");
302     }
303 
304     public void configure(SettingsListener listener) {
305         if (listener instanceof Profileable) {
306             loadProfileble((Profileable) listener);
307         } else {
308             Properties loadedProperties = loadGlobalProperties();
309             LoadSettingsEvent event = new LoadSettingsEvent(this,
310                     loadedProperties);
311             listener.loadSettings(event);
312         }
313     }
314 
315     /**
316      * Returns the current Properties settings for this user
317      * by merging the default Properties with the ones we find in their directory.
318      *
319      * @return
320      */
321     private Properties loadGlobalProperties() {
322         Properties properties = new Properties(defaultProperties);
323         InputStream is = null;
324 
325         File f = new File(getSettingsDirectory(), GLOBAL_SETTINGS_FILE_NAME);
326 
327         if (f.exists()) {
328             try {
329                 is = new BufferedInputStream(new FileInputStream(f));
330 
331                 Properties toLoad = new Properties();
332                 toLoad.load(is);
333                 properties.putAll(toLoad);
334             } catch (IOException ioe) {
335                 ioe.printStackTrace();
336             } finally {
337                 if (is != null) {
338                     try {
339                         is.close();
340                     } catch (IOException e1) {
341                         e1.printStackTrace();
342                     }
343                 }
344             }
345         }
346 
347         return properties;
348     }
349 
350     /**
351      * Returns the loaded default settings, which can be used by
352      * other classes within this package.
353      * @return Properties defaults
354      */
355     public Properties getDefaultSettings() {
356         return defaultProperties;
357     }
358 }