1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.sun.syndication.io.impl;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Properties;
24 import java.util.StringTokenizer;
25
26 /***
27 * Loads and instantiates classes indicated in property files.
28 * <p>
29 * The PlugableClasses is useful for handling collection of classes that are not known or fixed
30 * at development time.
31 * <p>
32 * It reads the class names from a default properties file and from an additional properties
33 * file indicated through a System property. The additional properties file does not override
34 * the default properties file, the classes are aggregated.
35 * <p>
36 * @author Alejandro Abdelnur
37 *
38 */
39 public class PlugableClasses {
40 private String _defaultFile;
41 private String _systemPropertyFile;
42 private String _propertyKey;
43 private ClassLoader _classLoader;
44 private boolean _hardFailure = true;
45 private Class[] _classes;
46
47 /***
48 * Creates a PlugableClasses instance that will load the classes indicated in properties files.
49 * <p>
50 * It uses the same ClassLoader of the PlugableClasses and it is set for hard failure
51 * (a RuntimeException will be thrown if one or more of the classes cannot be loaded or instanciated).
52 * <p>
53 * @param defaultFile properties file that defines the classes to load
54 * @param systemPropertyFile system property that if present it should be indicate an additional
55 * properties file to look for classes to load. The additional properties file does not
56 * override the default properties file, the classes are aggregated.
57 * @param propertyKey property name that contains the list of classes to load. The class names
58 * must be separated with white spaces.
59 *
60 */
61 public PlugableClasses(String defaultFile,String systemPropertyFile,String propertyKey) {
62 this(defaultFile,systemPropertyFile,propertyKey,true,PlugableClasses.class.getClassLoader());
63 }
64
65 /***
66 * Creates a PlugableClasses instance that will load the classes indicated in properties files.
67 * <p>
68 * @param defaultFile properties file that defines the classes to load
69 * @param systemPropertyFile system property that if present it should be indicate an additional
70 * properties file to look for classes to load. The additional properties file does not
71 * override the default properties file, the classes are aggregated.
72 * @param propertyKey property name that contains the list of classes to load. The class names
73 * must be separated with white spaces.
74 * @param hardFailure indicates if a RuntimeException will be thrown if one or more of the classes
75 * cannot be loaded or instanciated. Otherwise it will ignore the failure and continue with
76 * the other classes.
77 * @param classLoader ClassLoader to use for loading the properties files and classes.
78 *
79 */
80 public PlugableClasses(String defaultFile,String systemPropertyFile,String propertyKey,
81 boolean hardFailure,ClassLoader classLoader) {
82 _defaultFile = defaultFile;
83 _systemPropertyFile = systemPropertyFile;
84 _propertyKey = propertyKey;
85 _hardFailure = hardFailure;
86 _classLoader = classLoader;
87 }
88
89 /***
90 * Sets the hard failure mode for the PlugableClasses instance.
91 * <p>
92 * If a hard failure mode is OFF, a ClassNotFoundException will be thrown if one of the classes cannot
93 * be loaded or instanciated. Otherwise it will ignore the failure and continue with the other
94 * classes.
95 * <p>
96 * @param hardFailure <b>true</b> to set hard failure to ON, <b>false</b> to set it to OFF.
97 *
98 */
99 public void setHardFailure(boolean hardFailure) {
100 _hardFailure = hardFailure;
101 }
102
103 /***
104 * Returns the hard failure mode for the PlugableClasses instance.
105 * <p>
106 * If a hard failure mode is OFF, a RuntimeException will be thrown if one of the classes cannot
107 * be loaded or instanciated. Otherwise it will ignore the failure and continue with the other
108 * classes.
109 * <p>
110 * @return <b>true</b> to set hard failure to ON, <b>false</b> to set it to OFF.
111 *
112 */
113 public boolean isHardFailure() {
114 return _hardFailure;
115 }
116
117 /***
118 * Loads and returns the classes defined in the properties files.
119 * <p>
120 * @return array containing the classes defined in the properties files.
121 * @throws java.io.IOException thrown if the properties files cannot be found or read, and hard failure is ON.
122 * @throws java.lang.ClassNotFoundException thrown if one of the classes defined in the properties file cannot be loaded
123 * and hard failure is ON.
124 *
125 */
126 public Class[] getClasses() throws IOException,ClassNotFoundException {
127 synchronized (this) {
128 if (_classes==null) {
129 _classes = loadClasses();
130 }
131 }
132 return _classes;
133 }
134
135 /***
136 * Loads, instanciates and returns the classes defined in the properties files.
137 * <p>
138 * @return array containing the classes defined in the properties files.
139 * @throws java.io.IOException thrown if the properties files cannot be found or read, and hard failure is ON.
140 * @throws java.lang.ClassNotFoundException thrown if one of the classes defined in the properties files cannot be loaded
141 * and hard failure is ON.
142 * @throws java.lang.InstantiationException thrown if one of the classes defined in the properties files cannot be
143 * instantiated and hard failure is ON.
144 *
145 */
146 public Object[] createInstances() throws IOException,ClassNotFoundException,InstantiationException {
147 List objects = new ArrayList();
148 Class[] classes = getClasses();
149 for (int i=0;i<classes.length;i++) {
150 try {
151 objects.add(classes[i].newInstance());
152 }
153 catch (Exception ex) {
154 if (isHardFailure()) {
155 if (ex instanceof InstantiationException) {
156 throw (InstantiationException)ex;
157 }
158 throw new InstantiationException("Could not create instance for ["+classes[i].getName()+"]");
159 }
160 }
161 }
162 return objects.toArray();
163 }
164
165 /***
166 * Loads classes defined in the default and System-properties-indicated properties files.
167 *
168 */
169 private Class[] loadClasses() throws IOException,ClassNotFoundException {
170 List classes = new ArrayList();
171 if (_defaultFile!=null) {
172 classes.addAll(loadClasses(_defaultFile));
173 }
174 if (_systemPropertyFile!=null) {
175 String extraFile = System.getProperty(_systemPropertyFile);
176 if (extraFile!=null) {
177 classes.addAll(loadClasses(extraFile));
178 }
179 }
180 Class[] array = new Class[classes.size()];
181 classes.toArray(array);
182 return array;
183 }
184
185 /***
186 * Loads classes defined in a properties file.
187 *
188 */
189 private List loadClasses(String fileName) throws IOException,ClassNotFoundException {
190 List classes = new ArrayList();
191 Properties props = new Properties();
192 InputStream is = _classLoader.getResourceAsStream(fileName);
193 if (is!=null) {
194 try {
195 props.load(is);
196 }
197 catch (IOException ioEx) {
198 if (isHardFailure()) {
199 throw ioEx;
200 }
201 }
202 String classNames = props.getProperty(_propertyKey);
203 if (classNames!=null) {
204 classes.addAll(parseAndLoadClasses(classNames));
205 }
206 }
207 else {
208 if (isHardFailure()) {
209 throw new IOException("Could not find properties file ["+fileName+"]");
210 }
211 }
212 return classes;
213
214 }
215
216 private List parseAndLoadClasses(String classNames) throws ClassNotFoundException {
217 List classes = new ArrayList();
218 StringTokenizer st = new StringTokenizer(classNames," ");
219 while (st.hasMoreTokens()) {
220 String className = st.nextToken();
221 Class mClass = null;
222 try {
223 mClass = _classLoader.loadClass(className);
224 classes.add(mClass);
225 }
226 catch (ClassNotFoundException ex) {
227 if (isHardFailure()) {
228 throw ex;
229 }
230 }
231 }
232 return classes;
233 }
234
235 }