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.start.ServiceDescriptor;
21  import org.apache.river.start.SharedActivatableServiceDescriptor;
22  import org.apache.river.start.SharedActivationGroupDescriptor;
23  import org.apache.river.tool.envcheck.AbstractPlugin;
24  import org.apache.river.tool.envcheck.EnvCheck;
25  import org.apache.river.tool.envcheck.Reporter;
26  import org.apache.river.tool.envcheck.Reporter.Message;
27  import org.apache.river.tool.envcheck.SubVMTask;
28  import org.apache.river.tool.envcheck.Util;
29  import java.io.File;
30  import java.util.ArrayList;
31  import java.util.Iterator;
32  import java.util.ResourceBundle;
33  import java.util.Set;
34  import net.jini.config.Configuration;
35  import net.jini.config.ConfigurationException;
36  import net.jini.config.ConfigurationFile;
37  import net.jini.config.ConfigurationProvider;
38  import org.apache.river.api.security.CombinerSecurityManager;
39  
40  /**
41   * Check that the persistence directory supplied by any
42   * <code>SharedActivatableServiceDescriptor</code>s are either non-existant or
43   * empty. Check is performed in a subtask VM started identically to how the
44   * activation system would have started it. The first entry in the service
45   * configuration named <code>persistenceDirectory</code> is checked. Doesn't
46   * work correctly if multiple services share a configuration. Don't know how to
47   * handle this.
48   */
49  public class CheckPersistence extends AbstractPlugin {
50  
51      EnvCheck envCheck;
52  
53      /**
54       * Check the persistence directory for every
55       * <code>SharedActivatableServiceDescriptor</code> in the starter
56       * configuration.
57       *
58       * @param envCheck the plugin container
59       */
60      public void run(EnvCheck envCheck) {
61          this.envCheck = envCheck;
62  	ServiceDescriptor[] d = envCheck.getDescriptors();
63  	for (int i = 0; i < d.length; i++) {
64  	    if (d[i] instanceof SharedActivatableServiceDescriptor) {
65  		SharedActivatableServiceDescriptor sd = 
66  		    (SharedActivatableServiceDescriptor) d[i];
67  		checkDirectory(sd);
68  	    }
69  	}
70      }
71  
72      /** 
73       * Launch a subtask for the given descriptor to obtain all the
74       * <code>persistenceDirectory</code> entries. Check each
75       * entry found for validity.
76       *
77       * @param d the descriptor to check, which must be a
78       *        <code>SharedActivatableServiceDescriptor</code
79       */
80      private void checkDirectory(SharedActivatableServiceDescriptor d) {
81  	SharedActivationGroupDescriptor gd = envCheck.getGroupDescriptor();
82  	String source = getString("descfor", d.getImplClassName());
83  	Object o = envCheck.launch(d, gd, taskName("GetEntriesTask"));
84  	if (o instanceof String[]) {
85  	    checkEntries((String[]) o, d, source);
86  	} else if (o instanceof String) {
87  	    Message message = new Message(Reporter.WARNING,
88  					  (String) o,
89  					  getString("dirExp"));
90  	    Reporter.print(message, source);
91  	} else {
92  	    handleUnexpectedSubtaskReturn(o, source);
93  	}
94      }
95  
96      /** 
97       * Check <code>entries</code> for validity. <code>entries</code> 
98       * contains a collection of pairs, the first being the fully
99       * qualified name of the <code>persistenceDirectory</code> entry,
100      * and the second being its value.
101      *
102      * @param entries the array of entry/value pairs
103      * @param d the descriptor
104      * @param source the source descriptive text
105      */
106     private void checkEntries(String[] entries, 
107 			      SharedActivatableServiceDescriptor d,
108 			      String source) 
109     {
110 	if (entries.length == 0) {
111 	    Message message = new Message(Reporter.WARNING,
112 					  getString("noentry"),
113 					  getString("dirExp"));
114 	    Reporter.print(message, source);
115 	}
116 	for (int i = 0; i < entries.length; i += 2) {
117 	    String name = entries[i];
118 	    String dir = entries[i + 1];
119 	    String loopSource = source + ": " + name + "=" + dir;
120 	    Object lobj = checkDir(dir, d);
121 	    Message message;
122 	    if (lobj == null) {
123 		message = new Message(Reporter.INFO,
124 				      getString("dirOK"),
125 				      getString("dirExp"));
126 		Reporter.print(message, loopSource);
127 	    } else if (lobj instanceof String) {
128 		message = new Message(Reporter.ERROR,
129 				      (String) lobj,
130 				      getString("dirExp"));
131 		Reporter.print(message, loopSource);
132 	    } else {
133 		handleUnexpectedSubtaskReturn(lobj, loopSource);
134 	    }
135 	}
136     }
137 
138     /**
139      * Perform a check on the given persistence directory. 
140      *
141      * @param dir the name of the directory to check
142      * @param d the service descriptor
143      * @return <code>null</code> if the specified directory is empty
144      *         or non-existant (i.e. OK). Otherwise returns an error message
145      *         or <code>Throwable</code> returned by the subtask.
146      */
147     private Object checkDir(String dir, SharedActivatableServiceDescriptor d) {
148 	if (dir == null) {
149 	    return getString("nulldir");
150 	}
151 	String taskName = taskName("CheckDirTask");
152 	String[] args = new String[]{dir};
153 	SharedActivationGroupDescriptor g =  envCheck.getGroupDescriptor();
154 	return envCheck.launch(d, g, taskName, args);
155     }
156 
157     /**
158      * Perform directory check with an active security policy in place.
159      */
160     public static class CheckDirTask implements SubVMTask {
161 
162 	private ResourceBundle bundle = 
163 	    Util.getResourceBundle(CheckPersistence.class);
164 
165 	public Object run(String[] args) {
166             if (System.getSecurityManager() == null) {
167 	    System.setSecurityManager(new CombinerSecurityManager());
168             }
169 	    String dir = args[0];
170 	    File dirFile = new File(dir);
171 	    if (!dirFile.exists()) {
172 		return null; // the OK value
173 	    }
174 	    if (!dirFile.isDirectory()) {
175 		return Util.getString("notadir", bundle, dir);
176 	    }
177 	    File[] contents = dirFile.listFiles();
178 	    if (contents == null) { // should never happen
179 		return Util.getString("emptylist", bundle, dir);
180 	    }
181 	    if (contents.length > 0) {
182 		return Util.getString("dirnotempty", bundle, dir);
183 	    }
184 	    return null; // directory exists but is empty
185 	}
186     }
187 
188     /**
189      * The subtask which obtains the list of persistence directory entries. The
190      * arg list is cleaned up, the configuration in obtained, and a String array
191      * of pairs of all entries named  <code>persistenceDirectory</code> and
192      * their associated value is returned.
193      */
194     public static class GetEntriesTask implements SubVMTask {
195 
196 	private ResourceBundle bundle = 
197 	    Util.getResourceBundle(CheckPersistence.class);
198 
199 	public Object run(String[] args) {
200 	    try {
201 		Configuration config = 
202 		    ConfigurationProvider.getInstance(args);
203 		return getEntries(config);
204 	    } catch (ConfigurationException e) {
205 		return Util.getString("configproblem", bundle, e.getMessage());
206 	    } catch (Exception e) {
207 		return e;
208 	    }
209 	}
210 
211 	/**
212 	 * Obtain all of the <code>persistenceDirectory</code> entries in the
213 	 * configuration and return them as pairs in a <code>String</code>
214 	 * array.
215 	 *
216 	 * @param conf the configuration to examine
217 	 * @return the array of entry/value pairs
218 	 */
219 	private Object getEntries(Configuration conf) {
220 	    ConfigurationFile cf = (ConfigurationFile) conf;
221 	    ArrayList<String> list = new ArrayList<String>();
222 	    Set<String> names = cf.getEntryNames();
223 	    Iterator<String> it = names.iterator();
224 	    String s = "";
225 	    while (it.hasNext()) {
226 		String name = it.next();
227 		s += name + "\n";
228 		int lastDot = name.lastIndexOf(".persistenceDirectory");
229 		if (lastDot > 0) {
230 		    String component = name.substring(0, lastDot);
231 		    try {
232 			String dir = conf.getEntry(component, 
233 						   "persistenceDirectory",
234 						   String.class,
235 						   null);
236 			list.add(name);
237 			list.add(dir);
238 		    } catch (ConfigurationException e) {
239 			return e;
240 		    }
241 		}
242 	    }
243 	    return list.toArray(new String[list.size()]);
244 	}
245     }
246 }