View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    * 
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   * 
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.river.tool.envcheck.plugins;
19  
20  import org.apache.river.tool.envcheck.AbstractPlugin;
21  import org.apache.river.tool.envcheck.EnvCheck;
22  import org.apache.river.tool.envcheck.Reporter;
23  import org.apache.river.tool.envcheck.Reporter.Message;
24  import org.apache.river.tool.envcheck.Plugin;
25  import org.apache.river.tool.envcheck.SubVMTask;
26  import org.apache.river.tool.envcheck.Util;
27  
28  import java.io.File;
29  import java.io.IOException;
30  import java.io.Serializable;
31  import java.net.InetAddress;
32  import java.net.URL;
33  import java.net.URLClassLoader;
34  import java.rmi.activation.ActivationGroup;
35  import java.rmi.activation.ActivationException;
36  import java.util.ArrayList;
37  import java.util.Iterator;
38  import java.util.Properties;
39  import java.util.Enumeration;
40  import java.util.Set;
41  
42  import net.jini.config.Configuration;
43  import net.jini.config.ConfigurationFile;
44  import net.jini.config.ConfigurationException;
45  import net.jini.config.ConfigurationProvider;
46  import net.jini.config.NoSuchEntryException;
47  
48  import org.apache.river.start.NonActivatableServiceDescriptor;
49  import org.apache.river.start.SharedActivatableServiceDescriptor;
50  import org.apache.river.start.SharedActivationGroupDescriptor;
51  import org.apache.river.start.ServiceDescriptor;
52  import org.apache.river.start.ClassLoaderUtil;
53  
54  /**
55   * Check the configuration files for services identified by service descriptors
56   * in the service starter configuration. For each
57   * <code>SharedActivatableServiceDescriptor</code> or
58   * <code>NonActivatableServiceDescriptor</code>, a check is made that the
59   * command line arguments are not <code>null</code> or empty and that a
60   * configuration can be instantiated from those arguments. The configuration is
61   * searched for all occurrences of <code>initialLookupGroups</code> entries and
62   * generates warnings for those set to <code>ALL_GROUPS</code>.
63   */
64  public class CheckConfig extends AbstractPlugin {
65  
66      /** reference to the plugin container */
67      private EnvCheck envCheck;
68  
69      /**
70       * If configured to perform JSK checks, perform checks for each descriptor.
71       * Any service which conforms to the same command line argument convention
72       * may be included in a JSK check.
73       *
74       * @param envCheck the plugin container
75       */
76      public void run(EnvCheck envCheck) {
77          this.envCheck = envCheck;
78  	ServiceDescriptor[] d = envCheck.getDescriptors();
79  	for (int i = 0; i < d.length; i++) {
80  	    if (d[i] instanceof NonActivatableServiceDescriptor) {
81  		NonActivatableServiceDescriptor serviceDesc = 
82  		    (NonActivatableServiceDescriptor) d[i];
83  		String source = getString("descfor") 
84  		              + " " 
85  		              + serviceDesc.getImplClassName();
86  		if (checkArgs(serviceDesc, source)) {
87  		    checkServiceConfig(serviceDesc, source);
88  		}
89  	    }
90  	}
91      }
92  
93      /**
94       * Check that the arguments array obtained by calling
95       * <code>getServerConfigArgs</code> on the given service descriptor is
96       * non-<code>null</code> and has length > 0. This method is silent if the
97       * check is successful.
98       *
99       * @param d the <code>NonActivatableServiceDescriptor</code> to check
100      * @return true if the arguments are 'well formed'
101      */
102     private boolean checkArgs(NonActivatableServiceDescriptor d, 
103 			      String source) 
104     {
105         String[] args = d.getServerConfigArgs();
106         if (args == null || args.length == 0) {
107 	    Message message = new Message(Reporter.ERROR,
108 					  getString("emptydesclist"),
109 					  getString("emptydesclistExp"));
110 	    Reporter.print(message, source);
111             return false;
112         }
113 	return true;
114     }
115 
116     /**
117      * Check the service configuration file by instantiating the configuration
118      * in a subtask created using the same properties and arguments that would
119      * be used to run the actual service. If instantiation is successful, the
120      * configuration file and overrides are presumed to be well-formed. If the
121      * load is successful, another subtask is run in the same way which checks
122      * for an <code>initialLookupGroups</code> entry of <code>ALL_GROUPS.</code>
123      * A warning is output if such an entry is found.
124      *
125      * @param d the <code>NonActivatableServiceDescriptor</code> to check
126      */
127     private void checkServiceConfig(NonActivatableServiceDescriptor d,
128 				    String source)
129     {
130 	if (checkConfigLoad(d, source)) {
131 	    checkForAllGroups(d, source);
132 	}
133     }
134 
135     /**
136      * Execute the subtask which loads the configuration file.
137      *
138      * @param d the service descriptor
139      * @param source the source of the arguments
140      * @return true if the load was successful
141      */
142     private boolean checkConfigLoad(NonActivatableServiceDescriptor d, 
143 				    String source) 
144     {
145 	Message message;
146 	String task = taskName("ConfigTask");
147 	boolean ret = false;
148 	Object o = envCheck.launch(d, envCheck.getGroupDescriptor(), task);
149 	if (o instanceof Boolean) {
150 	    if (((Boolean) o).booleanValue()) {
151 		message = new Message(Reporter.INFO,
152 				      getString("ssconfigOK"),
153 				      getString("ssconfigExp"));
154 		ret = true;
155 	    } else {
156 		message = new Message(Reporter.ERROR,
157 				      getString("loadfailed"),
158 				      getString("ssconfigExp"));
159 	    }
160 	    Reporter.print(message, source);
161 	} else if (o instanceof ConfigurationException) {
162 	    message = new Message(Reporter.ERROR,
163 				  getString("loadfailed"),
164 				  (Throwable) o,
165 				  getString("ssconfigExp"));
166 	    Reporter.print(message, source);
167 	} else {
168 	    handleUnexpectedSubtaskReturn(o, source);
169 	}
170 	return ret;
171     }
172 
173     /**
174      * Execute the subtask which checks for ALL_GROUPS.
175      *
176      * @param d the service descriptor
177      * @param source the source of the arguments
178      */
179     private void checkForAllGroups(NonActivatableServiceDescriptor d, 
180 				   String source) 
181     {
182 	String task = taskName("GetGroupsTask");
183 	Object o = envCheck.launch(d, envCheck.getGroupDescriptor(), task);
184 	if (o instanceof GroupInfo[]) {
185 	    Message message;
186 	    GroupInfo[] info = (GroupInfo[]) o;
187 	    if (info.length == 0) {
188 		message = new Message(Reporter.INFO,
189 				      getString("notallgroup"),
190 				      getString("allgroupExp"));
191 		Reporter.print(message, source);
192 	    } else {
193 		for (int i = 0; i < info.length; i++) {
194 		    GroupInfo gi = info[i];
195 		    if (gi.groups == null) {
196 			message = new Message(Reporter.WARNING,
197 					      getString("allgroup"),
198 					      getString("allgroupExp"));
199 		    } else {
200 			StringBuffer groupList = new StringBuffer();
201 			for (int j = 0; j < gi.groups.length; j++) {
202 			    String group = gi.groups[j];
203 			    if (group.equals("")) {
204 				group = "public";
205 			    }
206 			    if (j > 0) {
207 				groupList.append(",");
208 			    }
209 			    groupList.append(group);
210 			}
211 			message = new Message(Reporter.INFO,
212 					      getString("groups", 
213 							groupList.toString()),
214 					      getString("allgroupExp"));
215 		    }
216 		    Reporter.print(message, source + ": " + gi.entryName);
217 		}
218 	    }
219 	} else {
220 	    handleUnexpectedSubtaskReturn(o, source);
221 	}			
222    }
223 
224     /** Struct to hold entryName/Group pairs */
225     private static class GroupInfo implements Serializable {
226 
227 	String entryName;
228 	String[] groups;
229 
230 	GroupInfo(String entryName, String[] groups) {
231 	    this.entryName = entryName;
232 	    this.groups = groups;
233 	}
234     }
235 
236     /**
237      * Subtask which obtains all <code>initialLookupGroups</code> entries and
238      * returns them in an array of <code>GroupInfo</code> objects.
239      */
240     public static class GetGroupsTask implements SubVMTask {
241 	
242 	/**
243 	 * Instantiate the configuration. <code>args</code> is stripped of its
244 	 * first value, which is the name of this task. The remaining args are
245 	 * used to instantiate the configuration. This operation should never
246 	 * fail since the configuration will have been instantiated previous in
247 	 * an identical way. Once instantiated, search for an ALL_GROUPS
248 	 * definition.
249 	 *
250 	 * @param args the args used to start this VM
251 	 * @return a <code>Boolean(false)</code> if no entries named
252 	 *         <code>initialLookupGroups,</code> or the value of
253 	 *         <code>initialLookupGroups</code> (a <code>String[]</code>) if
254 	 *         the entry is found.
255 	 */
256 	public Object run(String[] args) {
257 	    try {
258 		Configuration config = 
259 		    ConfigurationProvider.getInstance(args);
260 		return getGroups(config);
261 	    } catch (Exception e) {
262 		return e;
263 	    }
264 	}
265 	
266 	/**
267 	 * Search for all entries named <code>initialLookupGroups</code>
268 	 * in the configuration and return the array of <code>GroupInfo</code>
269 	 * objects containing the full entry name and associated groups
270 	 *
271 	 * @param conf the configuration to examine
272 	 * @return the <code>GroupInfo</code> array
273 	 */
274 	private Object getGroups(Configuration conf) {
275 	    ConfigurationFile cf = (ConfigurationFile) conf;
276 	    ArrayList list = new ArrayList();
277 	    Set names = cf.getEntryNames();
278 	    Iterator it = names.iterator();
279 	    while (it.hasNext()) {
280 		String name = (String) it.next();
281 		int lastDot = name.lastIndexOf(".initialLookupGroups");
282 		if (lastDot > 0) {
283 		    String component = name.substring(0, lastDot);
284 		    try {
285 			String[] groups = 
286 			    (String[]) (conf.getEntry(component, 
287 						      "initialLookupGroups",
288 						      String[].class));
289 			list.add(new GroupInfo(name, groups));
290 		    } catch (ConfigurationException e) {
291 			return e;
292 		    }
293 		}
294 	    }
295 	    return list.toArray(new GroupInfo[list.size()]);
296 	}
297     }
298 
299     /**
300      * Subtask to load the configuration
301      */
302     public static class ConfigTask implements SubVMTask {
303 	
304 	/**
305 	 * Instantiate the configuration using the given <code>args</code>.
306 	 *
307 	 * @return a <code>Boolean(true)</code> if successful, or the 
308 	 *         exception thrown if unsuccessful
309 	 */
310 	public Object run(String[] args) {
311 	    try {
312 		ConfigurationProvider.getInstance(args);
313 		return new Boolean(true);
314 	    } catch (Exception e) {
315 		return e;
316 	    }
317 	}
318     }
319 }