/*
* Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed 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 org.wso2.carbon.registry.core.config;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.securevault.SecretResolver;
import org.wso2.securevault.SecretResolverFactory;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.registry.core.Aspect;
import org.wso2.carbon.registry.core.RegistryConstants;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.jdbc.handlers.CustomEditManager;
import org.wso2.carbon.registry.core.jdbc.handlers.EditProcessor;
import org.wso2.carbon.registry.core.jdbc.handlers.Handler;
import org.wso2.carbon.registry.core.jdbc.handlers.HandlerLifecycleManager;
import org.wso2.carbon.registry.core.jdbc.handlers.filters.Filter;
import org.wso2.carbon.registry.core.session.CurrentSession;
import org.wso2.carbon.registry.core.utils.RegistryUtils;
import org.wso2.carbon.user.core.UserStoreException;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.carbon.utils.multitenancy.CarbonContextHolder;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import java.io.File;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
/**
* Builds the registry configuration from xml document. Configuration has to be given as an input
* stream. Registry configuration consists of details of data sources, handlers and aspects. These
* information is extracted from the configuration populates the necessary components.
*/
@SuppressWarnings("unused")
public class RegistryConfigurationProcessor {
private static final Log log = LogFactory.getLog(RegistryConfigurationProcessor.class);
/**
* Read XML configuration from the passed InputStream, or from the classpath.
*
* @param in an InputStream containing XML data, or null.
* @param registryContext the RegistryContext to populate
*
* @throws RegistryException if there's a problem
*/
public static void populateRegistryConfig(InputStream in, RegistryContext registryContext)
throws RegistryException {
if (in == null) {
in = Thread.currentThread().getContextClassLoader().getResourceAsStream(
"org/wso2/carbon/registry/core/servlet/registry.xml");
if (in == null) {
return;
}
}
try {
StAXOMBuilder builder = new StAXOMBuilder(in);
OMElement configElement = builder.getDocumentElement();
if (configElement != null) {
OMElement registryRootEle =
configElement.getFirstChildWithName(new QName("registryRoot"));
if (registryRootEle != null) {
String registryRoot = registryRootEle.getText();
if (registryRoot != null && !registryRoot.equals(RegistryConstants.ROOT_PATH)) {
if (registryRoot.endsWith(RegistryConstants.PATH_SEPARATOR)) {
registryRoot = registryRoot.substring(0, registryRoot.length() - 1);
} else if (!registryRoot.startsWith(RegistryConstants.PATH_SEPARATOR)) {
registryRoot = RegistryConstants.ROOT_PATH + registryRoot;
}
} else {
registryRoot = null;
}
registryContext.setRegistryRoot(registryRoot);
}
OMElement readOnlyEle =
configElement.getFirstChildWithName(new QName("readOnly"));
if (readOnlyEle != null) {
registryContext.setReadOnly(CarbonUtils.isReadOnlyNode() ||
"true".equals(readOnlyEle.getText()));
}
OMElement enableCachingEle =
configElement.getFirstChildWithName(new QName("enableCache"));
if (enableCachingEle != null) {
registryContext.setCacheEnabled("true".equals(enableCachingEle.getText()));
}
SecretResolver secretResolver = SecretResolverFactory.create(configElement, false);
Iterator dbConfigs = configElement.getChildrenWithName(new QName("dbConfig"));
// Read Database configurations
while (dbConfigs.hasNext()) {
OMElement dbConfig = (OMElement) dbConfigs.next();
DataBaseConfiguration dataBaseConfiguration = new DataBaseConfiguration();
dataBaseConfiguration.setPasswordManager(secretResolver);
String dbName = dbConfig.getAttributeValue(new QName("name"));
if (dbName == null) {
throw new RegistryException("The database configuration name cannot be " +
"null.");
}
dataBaseConfiguration.setConfigName(dbName);
OMElement dataSource = dbConfig.getFirstChildWithName(new QName("dataSource"));
if (dataSource != null) {
dataBaseConfiguration.setDataSourceName(dataSource.getText());
} else {
OMElement userName = dbConfig.getFirstChildWithName(new QName("userName"));
if (userName != null) {
dataBaseConfiguration.setUserName(userName.getText());
}
OMElement password = dbConfig.getFirstChildWithName(new QName("password"));
if (password != null) {
dataBaseConfiguration.setPassWord(password.getText());
}
OMElement url = dbConfig.getFirstChildWithName(new QName("url"));
String dbUrl = url.getText();
if (dbUrl != null) {
// If the connection URL contains ${carbon.home}, replace it with the
// corresponding value.
if (dbUrl.contains(CarbonConstants.CARBON_HOME_PARAMETER)) {
File carbonHomeDir;
carbonHomeDir = new File(CarbonUtils.getCarbonHome());
String path = carbonHomeDir.getPath();
path = path.replaceAll(Pattern.quote("\\"), "/");
if (carbonHomeDir.exists() && carbonHomeDir.isDirectory()) {
dbUrl = dbUrl.replaceAll(
Pattern.quote(CarbonConstants.CARBON_HOME_PARAMETER),
path);
} else {
log.warn("carbon home invalid");
String[] tempStrings1 = dbUrl.split(
Pattern.quote(CarbonConstants.CARBON_HOME_PARAMETER));
String tempUrl = tempStrings1[1];
String[] tempStrings2 = tempUrl.split("/");
for (int i = 0; i < tempStrings2.length - 1; i++) {
dbUrl = tempStrings1[0] + tempStrings2[i] + "/";
}
dbUrl = dbUrl + tempStrings2[tempStrings2.length - 1];
}
url.setText(dbUrl);
}
}
dataBaseConfiguration.setDbUrl(url.getText());
OMElement driverName =
dbConfig.getFirstChildWithName(new QName("driverName"));
if (driverName != null) {
dataBaseConfiguration.setDriverName(driverName.getText());
}
OMElement maxWait = dbConfig.getFirstChildWithName(new QName("maxWait"));
if (maxWait != null) {
dataBaseConfiguration.setMaxWait(maxWait.getText());
}
OMElement maxActive =
dbConfig.getFirstChildWithName(new QName("maxActive"));
if (maxActive != null) {
dataBaseConfiguration.setMaxActive(maxActive.getText());
}
OMElement maxIdle = dbConfig.getFirstChildWithName(new QName("maxIdle"));
if (maxIdle != null) {
dataBaseConfiguration.setMaxIdle(maxIdle.getText());
}
OMElement minIdle = dbConfig.getFirstChildWithName(new QName("minIdle"));
if (minIdle != null) {
dataBaseConfiguration.setMinIdle(minIdle.getText());
}
OMElement validationQuery =
dbConfig.getFirstChildWithName(new QName("validationQuery"));
if (validationQuery != null) {
dataBaseConfiguration.setValidationQuery(validationQuery.getText());
}
}
registryContext.addDBConfig(dbName, dataBaseConfiguration);
}
// loading one-time start-up configurations
OMElement staticConfigElement =
configElement.getFirstChildWithName(new QName("staticConfiguration"));
if (staticConfigElement != null) {
Iterator staticConfigs = staticConfigElement.getChildElements();
while (staticConfigs.hasNext()) {
OMElement staticConfig = (OMElement) staticConfigs.next();
if (staticConfig.getLocalName().equals("versioningProperties")) {
String versioningProperties = staticConfig.getText();
StaticConfiguration
.setVersioningProperties(versioningProperties.equals("true"));
} else if (staticConfig.getLocalName().equals("versioningComments")) {
String versioningComments = staticConfig.getText();
StaticConfiguration
.setVersioningComments(versioningComments.equals("true"));
} else if (staticConfig.getLocalName().equals("versioningTags")) {
String versioningTags = staticConfig.getText();
StaticConfiguration.setVersioningTags(versioningTags.equals("true"));
} else if (staticConfig.getLocalName().equals("versioningRatings")) {
String versioningRatings = staticConfig.getText();
StaticConfiguration
.setVersioningRatings(versioningRatings.equals("true"));
} else if (staticConfig.getLocalName().equals("versioningAssociations")) {
String versioningAssociations = staticConfig.getText();
StaticConfiguration.setVersioningAssociations(
versioningAssociations.equals("true"));
} else if (staticConfig.getLocalName().equals("profilesPath")) {
String profilesPath = staticConfig.getText();
if (!profilesPath.startsWith(
RegistryConstants.PATH_SEPARATOR)) {
//if user give the path like test or test/
profilesPath = RegistryConstants.PATH_SEPARATOR + profilesPath;
}
if (profilesPath.endsWith(RegistryConstants.PATH_SEPARATOR)) {
profilesPath = profilesPath.substring(0, (profilesPath.length() -
1)); //if user give the path like this /test/
}
if (profilesPath != null) {
if (profilesPath.startsWith(
RegistryConstants.CONFIG_REGISTRY_BASE_PATH)) {
registryContext.setProfilesPath(profilesPath);
} else {
registryContext.setProfilesPath(
RegistryConstants.CONFIG_REGISTRY_BASE_PATH +
profilesPath);
}
}
} else if (staticConfig.getLocalName().equals("servicePath")) {
String servicePath = staticConfig.getText();
if (!servicePath.startsWith(
RegistryConstants.PATH_SEPARATOR)) {
//if user give the path like test or test/
servicePath = RegistryConstants.PATH_SEPARATOR + servicePath;
}
if (servicePath.endsWith(RegistryConstants.PATH_SEPARATOR)) {
servicePath = servicePath.substring(0, (servicePath.length() -
1)); //if user give the path like this /test/
}
if (servicePath != null) {
if (servicePath.startsWith(
RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH)) {
registryContext.setServicePath(servicePath);
} else {
registryContext.setServicePath(
RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH +
servicePath);
}
}
}
}
}
OMElement currentConfigElement =
configElement.getFirstChildWithName(new QName("currentDBConfig"));
if (currentConfigElement == null) {
throw new RegistryException("The current database configuration is not " +
"defined.");
}
String currentConfigName = currentConfigElement.getText();
DataBaseConfiguration dbConfiguration =
registryContext.selectDBConfig(currentConfigName);
registryContext.setDefaultDataBaseConfiguration(dbConfiguration);
initializeHandlers(configElement, registryContext);
readRemoteInstances(configElement, registryContext, secretResolver);
readMounts(configElement, registryContext);
// process query processor config
Iterator queryProcessors = configElement.
getChildrenWithName(new QName("queryProcessor"));
while (queryProcessors.hasNext()) {
QueryProcessorConfiguration queryProcessorConfiguration =
new QueryProcessorConfiguration();
OMElement queryProcessorElement = (OMElement) queryProcessors.next();
OMElement queryType = queryProcessorElement.
getFirstChildWithName(new QName("queryType"));
if (queryType != null) {
queryProcessorConfiguration.setQueryType(queryType.getText());
}
OMElement processorName = queryProcessorElement.
getFirstChildWithName(new QName("processor"));
if (processorName != null) {
queryProcessorConfiguration.
setProcessorClassName(processorName.getText());
}
registryContext.addQueryProcessor(queryProcessorConfiguration);
}
initializeAspects(configElement, registryContext);
OMElement versionConfig =
configElement.getFirstChildWithName(new QName("versionResourcesOnChange"));
if (versionConfig != null && "true".equals(versionConfig.getText())) {
registryContext.setVersionOnChange(true);
} else {
registryContext.setVersionOnChange(false);
}
}
} catch (XMLStreamException e) {
throw new RegistryException(e.getMessage());
}
}
/**
* Obtains the registry configuration as XML element.
*
* @param registryContext the Registry Context used by this registry instance.
*
* @return AXIOM element containing registry configuration.
*/
public static OMElement getRegistryConfigAsXML(RegistryContext registryContext) {
OMFactory factory = OMAbstractFactory.getOMFactory();
OMElement root = factory.createOMElement("wso2registry", null);
if (registryContext.getDefaultDataBaseConfiguration() != null) {
OMElement currentConfigElement = factory.createOMElement("currentConfig", null);
currentConfigElement
.setText(registryContext.getDefaultDataBaseConfiguration().getConfigName());
root.addChild(currentConfigElement);
}
Iterator values = registryContext.getDBConfigNames();
while (values.hasNext()) {
DataBaseConfiguration dataBaseConfiguration = (DataBaseConfiguration) values.next();
OMElement config = factory.createOMElement("dbConfig", null);
OMElement url = factory.createOMElement("url", null);
url.setText(dataBaseConfiguration.getDbUrl());
config.addChild(url);
OMElement userName = factory.createOMElement("userName", null);
userName.setText(dataBaseConfiguration.getUserName());
config.addChild(userName);
OMElement password = factory.createOMElement("password", null);
password.setText(dataBaseConfiguration.getResolvedPassword());
config.addChild(password);
OMElement driverName = factory.createOMElement("driverName", null);
driverName.setText(dataBaseConfiguration.getDriverName());
config.addChild(driverName);
config.addAttribute("name", dataBaseConfiguration.getConfigName(), null);
root.addChild(config);
}
return root;
}
/**
* Creates and initializes an aspect.
*
* @param configElement the aspect configuration element.
* @param registryContext the Registry Context used by this registry instance.
*
* @throws RegistryException if anything goes wrong.
*/
public static void initializeAspects(OMElement configElement, RegistryContext registryContext)
throws RegistryException {
Iterator aspectElement = configElement.
getChildrenWithName(new QName("aspect"));
if (aspectElement != null) {
while (aspectElement.hasNext()) {
OMElement aspect = (OMElement) aspectElement.next();
String name = aspect.getAttributeValue(new QName("name"));
registryContext.addAspect(name, buildAspect(aspect, name), 0);
}
}
}
// common method to build an aspect
private static Aspect buildAspect(OMElement aspect, String name) throws RegistryException {
String clazz = aspect.getAttributeValue(new QName("class"));
Aspect aspectInstance = null;
try {
if (name == null || clazz == null) {
throw new RegistryException("Invalid aspect element , required " +
"values are missing " + aspect.toString());
}
Class handlerClass = loadClass(clazz);
if (aspect.getChildElements().hasNext()) {
try {
Constructor constructor =
handlerClass.getConstructor(OMElement.class);
try {
aspectInstance = (Aspect) constructor.newInstance(aspect);
} catch (Exception e) {
throw new RegistryException("Couldn't instantiate", e);
}
} catch (NoSuchMethodException e) {
// Throw error because the specified config won't be used?
}
}
if (aspectInstance == null) {
aspectInstance = (Aspect) handlerClass.newInstance();
}
return aspectInstance;
} catch (Exception e) {
String msg = "Could not initialize custom aspects. Caused by: " + e.getMessage();
log.error(msg, e);
throw new RegistryException(msg, e);
}
}
/**
* Updates an aspect based on given configuration.
*
* @param configElement the aspect configuration element.
*
* @return Created aspect
* @throws RegistryException if anything goes wrong.
*/
public static Aspect updateAspects(OMElement configElement) throws RegistryException {
Iterator aspectElement = configElement.
getChildrenWithName(new QName("aspect"));
if (aspectElement != null) {
OMElement aspect = (OMElement) aspectElement.next();
String name = aspect.getAttributeValue(new QName("name"));
return buildAspect(aspect, name);
}
return null;
}
// Creates and initializes a handler
private static void initializeHandlers(OMElement configElement, RegistryContext registryContext)
throws RegistryException {
// process handler configurations
CustomEditManager customEditManager = registryContext.getCustomEditManager();
try {
@SuppressWarnings("unchecked")
Iterator<OMElement> handlerConfigs =
configElement.getChildrenWithName(new QName("handler"));
while (handlerConfigs.hasNext()) {
OMElement handlerConfigElement = handlerConfigs.next();
buildHandler(registryContext, customEditManager, handlerConfigElement, null);
}
} catch (Exception e) {
String msg = "Could not initialize custom handlers. Caused by: " + e.getMessage();
log.error(msg, e);
throw new RegistryException(msg, e);
}
}
/**
* Updates a handler based on given configuration.
*
* @param configElement the handler configuration element.
* @param lifecyclePhase the lifecycle phase to which this handler belongs. The possible values
* are "default", "reporting" and "user".
* @param registryContext the Registry Context used by this registry instance.
*
* @return Created handler
* @throws RegistryException if anything goes wrong.
*/
public static boolean updateHandler(OMElement configElement, RegistryContext registryContext,
String lifecyclePhase)
throws RegistryException {
try {
Iterator handlerConfigs =
configElement.getChildrenWithName(new QName("handler"));
if (handlerConfigs != null) {
OMElement handlerConfigElement = (OMElement) handlerConfigs.next();
// We won't be adding custom edit processors for handlers inserted through the UI.
// This is because the CustomEditManager is not MT aware.
return buildHandler(registryContext, null, handlerConfigElement, lifecyclePhase);
}
return false;
} catch (Exception e) {
String msg = "Could not create custom handler. Caused by: " + e.getMessage();
log.error(msg, e);
throw new RegistryException(msg, e);
}
}
// common method to build a handler
private static boolean buildHandler(RegistryContext registryContext,
CustomEditManager customEditManager,
OMElement handlerConfigElement,
String lifecyclePhase)
throws InstantiationException, IllegalAccessException,
NoSuchMethodException, InvocationTargetException, UserStoreException {
HandlerDefinitionObject handlerDefinitionObject =
new HandlerDefinitionObject(customEditManager, handlerConfigElement).invoke();
String[] methods = handlerDefinitionObject.getMethods();
Filter filter = handlerDefinitionObject.getFilter();
Handler handler = handlerDefinitionObject.getHandler();
if (filter == null || handler == null) {
return false;
}
if (lifecyclePhase != null) {
if (handlerDefinitionObject.getTenantId() != -1 &&
!HandlerLifecycleManager.DEFAULT_SYSTEM_HANDLER_PHASE.equals(lifecyclePhase)) {
CurrentSession.setCallerTenantId(handlerDefinitionObject.getTenantId());
try {
// We need to swap the tenant id for this call, if the handler overrides the
// default value.
registryContext.getHandlerManager().addHandler(methods, filter,
handler, lifecyclePhase);
} finally {
CurrentSession.removeCallerTenantId();
}
} else {
registryContext.getHandlerManager().addHandler(methods, filter,
handler, lifecyclePhase);
}
} else {
registryContext.getHandlerManager().addHandler(methods, filter, handler);
}
return true;
}
// reads remote instances from the configuration
private static void readRemoteInstances(OMElement configElement,
RegistryContext registryContext,
SecretResolver secretResolver) throws RegistryException {
try {
@SuppressWarnings("unchecked")
Iterator<OMElement> remoteConfigs =
configElement.getChildrenWithName(new QName("remoteInstance"));
List<String> idList = new ArrayList<String>();
while (remoteConfigs.hasNext()) {
OMElement remoteConfigElement = remoteConfigs.next();
String url = remoteConfigElement.getAttributeValue(new QName("url"));
String id = remoteConfigElement.getFirstChildWithName(new QName("id")).getText();
if (idList.contains(id)) {
String msg = "Two remote instances can't have the same id.";
log.error(msg);
throw new RegistryException(msg);
}
idList.add(id);
String trustedUser = null;
if (remoteConfigElement.getFirstChildWithName(new QName("username")) != null) {
trustedUser =
remoteConfigElement.getFirstChildWithName(new QName("username"))
.getText();
}
String trustedPwd = null;
if (remoteConfigElement.getFirstChildWithName(new QName("password")) != null) {
trustedPwd =
remoteConfigElement.getFirstChildWithName(new QName("password"))
.getText();
}
String type = null;
if (remoteConfigElement.getFirstChildWithName(new QName("type")) != null) {
type =
remoteConfigElement.getFirstChildWithName(new QName("type"))
.getText();
}
String dbConfig = null;
if (remoteConfigElement.getFirstChildWithName(new QName("dbConfig")) != null) {
dbConfig =
remoteConfigElement.getFirstChildWithName(new QName("dbConfig"))
.getText();
}
String readOnly = null;
if (remoteConfigElement.getFirstChildWithName(new QName("readOnly")) != null) {
readOnly =
remoteConfigElement.getFirstChildWithName(new QName("readOnly"))
.getText();
}
String enableCache = null;
if (remoteConfigElement.getFirstChildWithName(new QName("enableCache")) != null) {
enableCache =
remoteConfigElement.getFirstChildWithName(new QName("enableCache"))
.getText();
}
String registryRoot = null;
if (remoteConfigElement.getFirstChildWithName(new QName("registryRoot")) != null) {
registryRoot =
remoteConfigElement.getFirstChildWithName(new QName("registryRoot"))
.getText();
}
RemoteConfiguration remoteConfiguration = new RemoteConfiguration();
remoteConfiguration.setPasswordManager(secretResolver);
remoteConfiguration.setId(id);
remoteConfiguration.setUrl(url);
remoteConfiguration.setTrustedUser(trustedUser);
remoteConfiguration.setTrustedPwd(trustedPwd);
remoteConfiguration.setType(type);
remoteConfiguration.setDbConfig(dbConfig);
remoteConfiguration.setReadOnly(readOnly);
remoteConfiguration.setCacheEnabled(enableCache);
remoteConfiguration.setRegistryRoot(registryRoot);
registryContext.getRemoteInstances().add(remoteConfiguration);
}
} catch (Exception e) {
String msg =
"Could not read remote instance configuration. Caused by: " + e.getMessage();
log.error(msg, e);
throw new RegistryException(msg, e);
}
}
// read mounts from configuration
private static void readMounts(OMElement configElement,
RegistryContext registryContext) throws RegistryException {
try {
@SuppressWarnings("unchecked")
Iterator<OMElement> mounts =
configElement.getChildrenWithName(new QName("mount"));
List<String> pathList = new ArrayList<String>();
while (mounts.hasNext()) {
OMElement mountElement = mounts.next();
String path = mountElement.getAttributeValue(new QName("path"));
if (path == null) {
String msg = "The path attribute was not specified for remote mount. " +
"Skipping creation of remote mount. " +
"Element: " + mountElement.toString();
log.warn(msg);
continue;
}
if (pathList.contains(path)) {
String msg = "Two remote instances can't have the same path.";
log.error(msg);
throw new RegistryException(msg);
}
OMElement instanceIdElement = mountElement.getFirstChildWithName(
new QName("instanceId"));
if (instanceIdElement == null) {
String msg = "The instance identifier was not specified for the mount: " + path;
log.warn(msg);
continue;
}
OMElement targetPathElement = mountElement.getFirstChildWithName(
new QName("targetPath"));
if (targetPathElement == null) {
String msg = "The target path was not specified for the mount: " + path;
log.warn(msg);
continue;
}
pathList.add(path);
String overwriteStr = mountElement.getAttributeValue(new QName("overwrite"));
boolean overwrite = false;
boolean virtual = false;
if (overwriteStr != null) {
overwrite = Boolean.toString(true).equalsIgnoreCase(overwriteStr);
if (!overwrite) {
virtual = "virtual".equalsIgnoreCase(overwriteStr);
}
}
String instanceId = instanceIdElement.getText();
String targetPath = targetPathElement.getText();
Mount mount = new Mount();
mount.setPath(path);
mount.setOverwrite(overwrite);
mount.setVirtual(virtual);
mount.setInstanceId(instanceId);
mount.setTargetPath(targetPath);
registryContext.getMounts().add(mount);
}
} catch (Exception e) {
String msg =
"Could not read remote instance configuration. Caused by: " + e.getMessage();
log.error(msg, e);
throw new RegistryException(msg, e);
}
}
// utility method to get setter name for a given property.
private static String getSetterName(String varName) {
String setterName;
if (varName.length() == 1) {
setterName = "set" + varName.substring(0, 1).toUpperCase();
} else {
setterName = "set" +
varName.substring(0, 1).toUpperCase() + varName.substring(1, varName.length());
}
return setterName;
}
/**
* Object to store a handler definition
*/
public static class HandlerDefinitionObject {
private CustomEditManager customEditManager;
private OMElement handlerConfigElement;
private List<String> methods;
private Handler handler;
private Filter filter;
private int tenantId;
/**
* Constructor accepting a handler configuration and the custom edit manager to use.
*
* @param customEditManager the custom edit manager to use.
* @param handlerConfigElement the handler configuration element.
*/
public HandlerDefinitionObject(CustomEditManager customEditManager,
OMElement handlerConfigElement) {
this.customEditManager = customEditManager;
this.handlerConfigElement = handlerConfigElement;
}
/**
* Constructor accepting a handler configuration.
*
* @param handlerConfigElement the handler configuration element.
*/
public HandlerDefinitionObject(OMElement handlerConfigElement) {
this.customEditManager = null;
this.handlerConfigElement = handlerConfigElement;
}
/**
* Get methods to which this handler is engaged.
*
* @return array of methods
*/
public String[] getMethods() {
if (methods == null) {
return null;
}
return methods.toArray(new String[methods.size()]);
}
/**
* Gets the handler instance.
*
* @return the handler instance.
*/
public Handler getHandler() {
return handler;
}
/**
* Gets the tenant identifier
*
* @return tenant id
*/
public int getTenantId() {
return tenantId;
}
/**
* Gets the filter instance.
*
* @return the filter instance.
*/
public Filter getFilter() {
return filter;
}
/**
* Builds a handler definition object from XML configuration
*
* @return the definition object
* @throws InstantiationException for errors in creating classes
* @throws IllegalAccessException for exceptions due to invisibility of methods
* @throws NoSuchMethodException for errors due to accessing non-existing methods.
* @throws InvocationTargetException for errors in invoking methods or constructors.
* @throws UserStoreException if an error occurs in user management related
* operations.
*/
public HandlerDefinitionObject invoke()
throws InstantiationException, IllegalAccessException,
NoSuchMethodException, InvocationTargetException, UserStoreException {
String handlerClassName = handlerConfigElement.getAttributeValue(new QName("class"));
String methodsValue = handlerConfigElement.getAttributeValue(new QName("methods"));
String tenantIdString = handlerConfigElement.getAttributeValue(new QName("tenant"));
tenantId = -1;
int tempTenantId = CarbonContextHolder.getCurrentCarbonContextHolder().getTenantId();
// if the tenant id was found from the carbon context, it will be greater than -1. If not, it will be equal
// to -1. Therefore, we need to check whether the carbon context had a tenant id and use it if it did.
if (tempTenantId > -1) {
tenantId = tempTenantId;
} else if (tenantIdString != null) {
try {
tenantId = Integer.parseInt(tenantIdString);
} catch (NumberFormatException ignore) {
RegistryContext context = RegistryContext.getBaseInstance();
if (context != null && context.getRealmService() != null) {
try {
tenantId = context.getRealmService().getTenantManager().getTenantId(
tenantIdString);
} catch (org.wso2.carbon.user.api.UserStoreException e) {
throw new UserStoreException(e);
}
}
}
}
String[] methods;
if (methodsValue != null) {
methods = methodsValue.split(",");
for (int i = 0; i < methods.length; i++) {
methods[i] = methods[i].trim();
}
this.methods = Arrays.asList(methods);
}
Class handlerClass;
try {
handlerClass = loadClass(handlerClassName);
} catch (ClassNotFoundException e) {
String msg = "Could not find the handler class " + handlerClassName +
". This handler will not be registered. All handler and " +
"filter classes should be in the class path of the Registry.";
log.warn(msg);
return this;
}
handler = (Handler) handlerClass.newInstance();
// set configured properties of the handler object
@SuppressWarnings("unchecked")
Iterator<OMElement> handlerProps =
handlerConfigElement.getChildrenWithName(new QName("property"));
while (handlerProps.hasNext()) {
OMElement propElement = handlerProps.next();
String propName = propElement.getAttributeValue(new QName("name"));
String propType = propElement.getAttributeValue(new QName("type"));
if (propType != null && "xml".equals(propType)) {
String setterName = getSetterName(propName);
Method setter = handlerClass.getMethod(setterName, OMElement.class);
setter.invoke(handler, propElement);
} else {
String setterName = getSetterName(propName);
Method setter = handlerClass.getMethod(setterName, String.class);
String propValue = propElement.getText();
setter.invoke(handler, propValue);
}
}
// initialize and configure the filter for this handler
OMElement filterElement =
handlerConfigElement.getFirstChildWithName(new QName("filter"));
String filterClassName = filterElement.getAttributeValue(new QName("class"));
Class filterClass;
try {
filterClass = loadClass(filterClassName);
} catch (ClassNotFoundException e) {
String msg = "Could not find the filter class " +
filterClassName + ". " + handlerClassName +
" will not be registered. All configured handler, filter and " +
"edit processor classes should be in the class " +
"path of the Registry.";
log.warn(msg);
return this;
}
filter = (Filter) filterClass.newInstance();
// set configured properties of the filter object
@SuppressWarnings("unchecked")
Iterator<OMElement> filterProps =
filterElement.getChildrenWithName(new QName("property"));
while (filterProps.hasNext()) {
OMElement propElement = filterProps.next();
String propName = propElement.getAttributeValue(new QName("name"));
String propValue = propElement.getText();
String setterName = getSetterName(propName);
Method setter = filterClass.getMethod(setterName, String.class);
setter.invoke(filter, propValue);
}
if (customEditManager != null) {
OMElement editElement =
handlerConfigElement.getFirstChildWithName(new QName("edit"));
if (editElement != null) {
String processorKey = editElement.getAttributeValue(new QName("processor"));
String processorClassName = editElement.getText();
Class editProcessorClass;
try {
editProcessorClass = loadClass(processorClassName);
} catch (ClassNotFoundException e) {
String msg = "Could not find the edit processor class " +
processorClassName + ". " + handlerClassName +
" will not be registered. All configured handler, filter and " +
"edit processor classes should be in the class " +
"path of the Registry.";
log.warn(msg);
return this;
}
EditProcessor editProcessor = (EditProcessor) editProcessorClass.newInstance();
customEditManager.addProcessor(processorKey, editProcessor);
}
}
return this;
}
}
private static Class loadClass(String name) throws ClassNotFoundException {
try {
return Class.forName(name);
} catch(ClassNotFoundException e) {
File extensionLibDirectory = new File(RegistryUtils.getExtensionLibDirectoryPath());
if (extensionLibDirectory.exists() && extensionLibDirectory.isDirectory()) {
File[] files = extensionLibDirectory.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name != null && name.endsWith(".jar");
}
});
if (files != null && files.length > 0) {
List<URL> urls = new ArrayList<URL>(files.length);
for(File file : files) {
try {
urls.add(file.toURI().toURL());
} catch (MalformedURLException ignore) { }
}
ClassLoader origTCCL = Thread.currentThread().getContextClassLoader();
try {
ClassLoader cl = new URLClassLoader(urls.toArray(new URL[urls.size()]),
RegistryConfigurationProcessor.class.getClassLoader());
return cl.loadClass(name);
} finally {
Thread.currentThread().setContextClassLoader(origTCCL);
}
}
}
throw e;
}
}
}