/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.jini.tool.envcheck.plugins;
import com.sun.jini.tool.envcheck.AbstractPlugin;
import com.sun.jini.tool.envcheck.EnvCheck;
import com.sun.jini.tool.envcheck.Reporter;
import com.sun.jini.tool.envcheck.Reporter.Message;
import com.sun.jini.tool.envcheck.Plugin;
import com.sun.jini.tool.envcheck.SubVMTask;
import com.sun.jini.tool.envcheck.Util;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.URL;
import java.net.URLClassLoader;
import java.rmi.activation.ActivationGroup;
import java.rmi.activation.ActivationException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Properties;
import java.util.Enumeration;
import java.util.Set;
import net.jini.config.Configuration;
import net.jini.config.ConfigurationFile;
import net.jini.config.ConfigurationException;
import net.jini.config.ConfigurationProvider;
import net.jini.config.NoSuchEntryException;
import com.sun.jini.start.NonActivatableServiceDescriptor;
import com.sun.jini.start.SharedActivatableServiceDescriptor;
import com.sun.jini.start.SharedActivationGroupDescriptor;
import com.sun.jini.start.ServiceDescriptor;
import com.sun.jini.start.ClassLoaderUtil;
/**
* Check the configuration files for services identified by service descriptors
* in the service starter configuration. For each
* <code>SharedActivatableServiceDescriptor</code> or
* <code>NonActivatableServiceDescriptor</code>, a check is made that the
* command line arguments are not <code>null</code> or empty and that a
* configuration can be instantiated from those arguments. The configuration is
* searched for all occurrences of <code>initialLookupGroups</code> entries and
* generates warnings for those set to <code>ALL_GROUPS</code>.
*/
public class CheckConfig extends AbstractPlugin {
/** reference to the plugin container */
private EnvCheck envCheck;
/**
* If configured to perform JSK checks, perform checks for each descriptor.
* Any service which conforms to the same command line argument convention
* may be included in a JSK check.
*
* @param envCheck the plugin container
*/
public void run(EnvCheck envCheck) {
this.envCheck = envCheck;
ServiceDescriptor[] d = envCheck.getDescriptors();
for (int i = 0; i < d.length; i++) {
if (d[i] instanceof NonActivatableServiceDescriptor) {
NonActivatableServiceDescriptor serviceDesc =
(NonActivatableServiceDescriptor) d[i];
String source = getString("descfor")
+ " "
+ serviceDesc.getImplClassName();
if (checkArgs(serviceDesc, source)) {
checkServiceConfig(serviceDesc, source);
}
}
}
}
/**
* Check that the arguments array obtained by calling
* <code>getServerConfigArgs</code> on the given service descriptor is
* non-<code>null</code> and has length > 0. This method is silent if the
* check is successful.
*
* @param d the <code>NonActivatableServiceDescriptor</code> to check
* @return true if the arguments are 'well formed'
*/
private boolean checkArgs(NonActivatableServiceDescriptor d,
String source)
{
String[] args = d.getServerConfigArgs();
if (args == null || args.length == 0) {
Message message = new Message(Reporter.ERROR,
getString("emptydesclist"),
getString("emptydesclistExp"));
Reporter.print(message, source);
return false;
}
return true;
}
/**
* Check the service configuration file by instantiating the configuration
* in a subtask created using the same properties and arguments that would
* be used to run the actual service. If instantiation is successful, the
* configuration file and overrides are presumed to be well-formed. If the
* load is successful, another subtask is run in the same way which checks
* for an <code>initialLookupGroups</code> entry of <code>ALL_GROUPS.</code>
* A warning is output if such an entry is found.
*
* @param d the <code>NonActivatableServiceDescriptor</code> to check
*/
private void checkServiceConfig(NonActivatableServiceDescriptor d,
String source)
{
if (checkConfigLoad(d, source)) {
checkForAllGroups(d, source);
}
}
/**
* Execute the subtask which loads the configuration file.
*
* @param d the service descriptor
* @param source the source of the arguments
* @return true if the load was successful
*/
private boolean checkConfigLoad(NonActivatableServiceDescriptor d,
String source)
{
Message message;
String task = taskName("ConfigTask");
boolean ret = false;
Object o = envCheck.launch(d, envCheck.getGroupDescriptor(), task);
if (o instanceof Boolean) {
if (((Boolean) o).booleanValue()) {
message = new Message(Reporter.INFO,
getString("ssconfigOK"),
getString("ssconfigExp"));
ret = true;
} else {
message = new Message(Reporter.ERROR,
getString("loadfailed"),
getString("ssconfigExp"));
}
Reporter.print(message, source);
} else if (o instanceof ConfigurationException) {
message = new Message(Reporter.ERROR,
getString("loadfailed"),
(Throwable) o,
getString("ssconfigExp"));
Reporter.print(message, source);
} else {
handleUnexpectedSubtaskReturn(o, source);
}
return ret;
}
/**
* Execute the subtask which checks for ALL_GROUPS.
*
* @param d the service descriptor
* @param source the source of the arguments
*/
private void checkForAllGroups(NonActivatableServiceDescriptor d,
String source)
{
String task = taskName("GetGroupsTask");
Object o = envCheck.launch(d, envCheck.getGroupDescriptor(), task);
if (o instanceof GroupInfo[]) {
Message message;
GroupInfo[] info = (GroupInfo[]) o;
if (info.length == 0) {
message = new Message(Reporter.INFO,
getString("notallgroup"),
getString("allgroupExp"));
Reporter.print(message, source);
} else {
for (int i = 0; i < info.length; i++) {
GroupInfo gi = info[i];
if (gi.groups == null) {
message = new Message(Reporter.WARNING,
getString("allgroup"),
getString("allgroupExp"));
} else {
StringBuffer groupList = new StringBuffer();
for (int j = 0; j < gi.groups.length; j++) {
String group = gi.groups[j];
if (group.equals("")) {
group = "public";
}
if (j > 0) {
groupList.append(",");
}
groupList.append(group);
}
message = new Message(Reporter.INFO,
getString("groups",
groupList.toString()),
getString("allgroupExp"));
}
Reporter.print(message, source + ": " + gi.entryName);
}
}
} else {
handleUnexpectedSubtaskReturn(o, source);
}
}
/** Struct to hold entryName/Group pairs */
private static class GroupInfo implements Serializable {
String entryName;
String[] groups;
GroupInfo(String entryName, String[] groups) {
this.entryName = entryName;
this.groups = groups;
}
}
/**
* Subtask which obtains all <code>initialLookupGroups</code> entries and
* returns them in an array of <code>GroupInfo</code> objects.
*/
public static class GetGroupsTask implements SubVMTask {
/**
* Instantiate the configuration. <code>args</code> is stripped of its
* first value, which is the name of this task. The remaining args are
* used to instantiate the configuration. This operation should never
* fail since the configuration will have been instantiated previous in
* an identical way. Once instantiated, search for an ALL_GROUPS
* definition.
*
* @param args the args used to start this VM
* @return a <code>Boolean(false)</code> if no entries named
* <code>initialLookupGroups,</code> or the value of
* <code>initialLookupGroups</code> (a <code>String[]</code>) if
* the entry is found.
*/
public Object run(String[] args) {
try {
Configuration config =
ConfigurationProvider.getInstance(args);
return getGroups(config);
} catch (Exception e) {
return e;
}
}
/**
* Search for all entries named <code>initialLookupGroups</code>
* in the configuration and return the array of <code>GroupInfo</code>
* objects containing the full entry name and associated groups
*
* @param conf the configuration to examine
* @return the <code>GroupInfo</code> array
*/
private Object getGroups(Configuration conf) {
ConfigurationFile cf = (ConfigurationFile) conf;
ArrayList list = new ArrayList();
Set names = cf.getEntryNames();
Iterator it = names.iterator();
while (it.hasNext()) {
String name = (String) it.next();
int lastDot = name.lastIndexOf(".initialLookupGroups");
if (lastDot > 0) {
String component = name.substring(0, lastDot);
try {
String[] groups =
(String[]) (conf.getEntry(component,
"initialLookupGroups",
String[].class));
list.add(new GroupInfo(name, groups));
} catch (ConfigurationException e) {
return e;
}
}
}
return list.toArray(new GroupInfo[list.size()]);
}
}
/**
* Subtask to load the configuration
*/
public static class ConfigTask implements SubVMTask {
/**
* Instantiate the configuration using the given <code>args</code>.
*
* @return a <code>Boolean(true)</code> if successful, or the
* exception thrown if unsuccessful
*/
public Object run(String[] args) {
try {
ConfigurationProvider.getInstance(args);
return new Boolean(true);
} catch (Exception e) {
return e;
}
}
}
}