/*
* Copyright 2004,2005 The Apache Software Foundation.
*
* 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.core.multitenancy;
import org.apache.axis2.AxisFault;
import org.apache.axis2.deployment.AxisConfigBuilder;
import org.apache.axis2.deployment.DeploymentConstants;
import org.apache.axis2.deployment.DeploymentEngine;
import org.apache.axis2.deployment.DeploymentException;
import org.apache.axis2.deployment.ModuleDeployer;
import org.apache.axis2.description.AxisModule;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.axis2.engine.AxisConfigurator;
import org.apache.axis2.engine.AxisObserver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.wso2.carbon.context.RegistryType;
import org.wso2.carbon.core.CarbonAxisConfigurator;
import org.wso2.carbon.core.deployment.DeploymentInterceptor;
import org.wso2.carbon.core.deployment.RegistryBasedRepository;
import org.wso2.carbon.core.deployment.RegistryBasedRepositoryUpdater;
import org.wso2.carbon.core.internal.CarbonCoreDataHolder;
import org.wso2.carbon.core.multitenancy.utils.TenantAxisUtils;
import org.wso2.carbon.core.util.ParameterUtil;
import org.wso2.carbon.registry.core.session.UserRegistry;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.carbon.utils.PreAxisConfigurationPopulationObserver;
import org.wso2.carbon.base.ServerConfiguration;
import org.wso2.carbon.utils.WSO2Constants;
import org.wso2.carbon.utils.deployment.Axis2DeployerRegistry;
import org.wso2.carbon.utils.deployment.Axis2ModuleRegistry;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import java.io.*;
import java.util.ArrayList;
import java.util.Collection;
import static org.apache.axis2.transport.TransportListener.HOST_ADDRESS;
/**
* The tenant specific AxisConfigurator
*/
public class TenantAxisConfigurator extends DeploymentEngine implements AxisConfigurator {
private static Log log = LogFactory.getLog(TenantAxisConfigurator.class);
private Collection globallyEngagedModules = new ArrayList();
private final AxisConfiguration mainAxisConfig;
private final String tenantDomain;
private final int tenantId;
private final String repoLocation;
private final UserRegistry registry;
private final BundleContext bundleContext;
private final Bundle[] moduleBundles;
private final Bundle[] deployerBundles;
@Deprecated
public TenantAxisConfigurator(AxisConfiguration mainAxisConfig,
String tenantDomain,
int tenantId,
UserRegistry registry) throws AxisFault {
this.tenantDomain = tenantDomain;
this.tenantId = tenantId;
this.mainAxisConfig = mainAxisConfig;
this.registry = registry;
this.bundleContext = CarbonCoreDataHolder.getInstance().getBundleContext();
this.moduleBundles =
((CarbonAxisConfigurator) mainAxisConfig.getConfigurator()).
getConfigItemHolder().getModuleBundles();
this.deployerBundles =
((CarbonAxisConfigurator) mainAxisConfig.getConfigurator()).
getConfigItemHolder().getDeployerBundles();
File tenantDir = new File(CarbonUtils.getCarbonTenantsDirPath() + File.separator + tenantId);
if (!tenantDir.exists() && !tenantDir.mkdirs()) {
log.warn("Could not create directory " + tenantDir.getAbsolutePath());
}
this.repoLocation = tenantDir.getAbsolutePath();
// Use registry based deployer if necessary
if (CarbonUtils.useRegistryBasedRepository()) {
String registryPath = "/repository/deployment";
new RegistryBasedRepository(registry,
registryPath,
repoLocation).updateFileSystemFromRegistry();
RegistryBasedRepositoryUpdater.scheduleAtFixedRate(registry,
registryPath,
repoLocation, 0, 10);
}
}
// New constructor is introduced to set the config and local registry separately
public TenantAxisConfigurator(AxisConfiguration mainAxisConfig,
String tenantDomain,
int tenantId,
UserRegistry configRegistry,
UserRegistry localRegistry) throws AxisFault {
this.tenantDomain = tenantDomain;
this.tenantId = tenantId;
this.mainAxisConfig = mainAxisConfig;
this.registry = configRegistry;
this.bundleContext = CarbonCoreDataHolder.getInstance().getBundleContext();
this.moduleBundles =
((CarbonAxisConfigurator) mainAxisConfig.getConfigurator()).
getConfigItemHolder().getModuleBundles();
this.deployerBundles =
((CarbonAxisConfigurator) mainAxisConfig.getConfigurator()).
getConfigItemHolder().getDeployerBundles();
String filePath = MultitenantUtils.getAxis2RepositoryPath(tenantId);
File tenantDir = new File(filePath);
if (!tenantDir.exists() && !tenantDir.mkdirs()) {
log.warn("Could not create directory " + tenantDir.getAbsolutePath());
}
this.repoLocation = filePath;
// Use registry based deployer if necessary
if (CarbonUtils.useRegistryBasedRepository()) {
String registryPath = "/repository/deployment";
new RegistryBasedRepository(localRegistry,
registryPath,
repoLocation).updateFileSystemFromRegistry();
RegistryBasedRepositoryUpdater.scheduleAtFixedRate(localRegistry,
registryPath,
repoLocation, 0, 10);
}
}
private String getTenantString(String tenantDomain, int tenantId) {
return tenantDomain + "[" + tenantId + "]";
}
/**
* First create a Deployment engine, use that to create an AxisConfiguration
*
* @return Axis Configuration
* @throws AxisFault
*/
public AxisConfiguration getAxisConfiguration() throws AxisFault {
//ClassLoader origTccl = Thread.currentThread().getContextClassLoader();
//Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
log.info("Creating tenant AxisConfiguration for tenant: " +
getTenantString(tenantDomain, tenantId));
SuperTenantCarbonContext.startTenantFlow();
try {
SuperTenantCarbonContext carbonContext = SuperTenantCarbonContext.getCurrentContext();
carbonContext.setTenantId(tenantId);
carbonContext.setTenantDomain(tenantDomain);
if (log.isDebugEnabled()) {
log.debug("Axis2 repo: " + repoLocation);
}
populateAxisConfig();
addDeployer(new ModuleDeployer(), repoLocation + File.separator +
"axis2modules", "mar");
axisConfig.setConfigurator(this);
//TODO: May need to set certain parameters into the AxisConfig
// Hot deployment & update should be turned on for tenants
axisConfig.addParameter(new Parameter(DeploymentConstants.TAG_HOT_DEPLOYMENT,
"true"));
axisConfig.addParameter(new Parameter(DeploymentConstants.TAG_HOT_UPDATE,
"true"));
globallyEngagedModules = axisConfig.getEngagedModules();
loadRepository(repoLocation);
for (Object globallyEngagedModule : globallyEngagedModules) {
AxisModule module = (AxisModule) globallyEngagedModule;
if (log.isDebugEnabled()) {
log.debug("Globally engaging module: " + module.getName());
}
}
// Remove all the transports made available in the tenant's axis2.xml
axisConfig.getTransportsOut().clear();
// Remove all in-transports made available in the tenant's axis2.xml
axisConfig.getTransportsIn().clear();
// Add the transports that are made available in the main axis2.xml file
TenantAxisUtils.setTenantTransports(mainAxisConfig, tenantDomain, axisConfig);
} finally {
SuperTenantCarbonContext.endTenantFlow();
//Thread.currentThread().setContextClassLoader(origTccl);
}
return axisConfig;
}
private void populateAxisConfig() throws DeploymentException {
InputStream axis2xmlStream = null;
try {
File tenantAxis2XML = new File(CarbonUtils.getAdvancedCarbonConfigDirPath() +
File.separator + "tenant-axis2.xml");
axis2xmlStream = new FileInputStream(tenantAxis2XML);
axisConfig = populateAxisConfiguration(axis2xmlStream);
} catch (FileNotFoundException e) {
String msg = "Cannot read tenant-axis2.xml";
log.error(msg, e);
throw new DeploymentException(msg, e);
} finally {
try {
if (axis2xmlStream != null) {
axis2xmlStream.close();
}
} catch (IOException e) {
log.error("Could not close input stream to " +
DeploymentConstants.AXIS2_CONFIGURATION_RESOURCE, e);
}
}
}
public boolean isGlobalyEngaged(AxisModule axisModule) {
String modName = axisModule.getName();
for (Object globallyEngagedModule : globallyEngagedModules) {
AxisModule module = (AxisModule) globallyEngagedModule;
if (modName.startsWith(module.getName())) {
return true;
}
}
return false;
}
public void engageGlobalModules() throws AxisFault {
engageModules();
}
public AxisConfiguration populateAxisConfiguration(InputStream in) throws DeploymentException {
axisConfig = TenantAxisConfiguration.createInstance();
SuperTenantCarbonContext carbonContext = SuperTenantCarbonContext.getCurrentContext(axisConfig);
carbonContext.setTenantId(tenantId);
carbonContext.setTenantDomain(tenantDomain);
// Notify all observers
if (bundleContext != null) {
ServiceTracker tracker =
new ServiceTracker(bundleContext,
PreAxisConfigurationPopulationObserver.class.getName(), null);
tracker.open();
Object[] services = tracker.getServices();
if (services != null) {
for (Object service : services) {
((PreAxisConfigurationPopulationObserver) service).createdAxisConfiguration(axisConfig);
}
}
tracker.close();
}
try {
// Add the relevant AxisObservers to the tenantAxisConfig
if (bundleContext != null) {
ServiceTracker tracker =
new ServiceTracker(bundleContext, AxisObserver.class.getName(), null);
tracker.open();
ServiceReference[] serviceRefs = tracker.getServiceReferences();
if (serviceRefs != null) {
for (ServiceReference serviceRef : serviceRefs) {
if (serviceRef.getProperty(MultitenantConstants.TENANT_ID) != null &&
tenantId == (Integer) serviceRef.getProperty(MultitenantConstants.TENANT_ID)) {
axisConfig.addObservers((AxisObserver) bundleContext.getService(serviceRef));
}
}
}
tracker.close();
}
// Set services dir
String servicesDirName = "axis2services";
File servicesDir = new File(repoLocation + File.separator + servicesDirName);
if (!servicesDir.exists() && !servicesDir.mkdirs()) {
throw new DeploymentException("Could not create services directory " +
servicesDir.getAbsolutePath());
}
axisConfig.addParameter(new Parameter(DeploymentConstants.SERVICE_DIR_PATH,
servicesDirName));
// Set modules dir
String modulesDirName = "axis2modules";
File modulesDir = new File(repoLocation + File.separator + modulesDirName);
if(!modulesDir.exists() && !modulesDir.mkdirs()){
throw new DeploymentException("Could not create modules directory " +
modulesDir.getAbsolutePath());
}
axisConfig.addParameter(new Parameter(DeploymentConstants.MODULE_DRI_PATH,
modulesDirName));
} catch (AxisFault e) {
String msg =
"Cannot add DeploymentConstants.SERVICE_DIR_PATH or " +
"DeploymentConstants.MODULE_DIR_PATH parameters";
log.error(msg, e);
throw new DeploymentException(msg, e);
}
carbonContext.setRegistry(RegistryType.SYSTEM_CONFIGURATION, registry);
try {
// TODO: The governance system registry should be passed into the tenant axis
// configurator like the config system registry - Senaka.
carbonContext.setRegistry(RegistryType.SYSTEM_GOVERNANCE,
CarbonCoreDataHolder.getInstance().getRegistryService()
.getGovernanceSystemRegistry(tenantId));
} catch (Exception ignored) {
// We are not worried about the exception in here.
}
// The following two lines of code are kept for backward compatibility. Remove this once we
// are certain that this is not required. -- Senaka.
// Please also note that we no longer need to set the user realm to the configuration
// explicitly.
setRegistry();
setUserRealm();
// Add the DeploymentInterceptor for the tenant AxisConfigurations
DeploymentInterceptor interceptor = new DeploymentInterceptor();
interceptor.setRegistry(registry);
interceptor.init(axisConfig);
axisConfig.addObservers(interceptor);
setHostName(axisConfig);
//TCCL will be based on OSGi
AxisConfigBuilder builder = new AxisConfigBuilder(in, axisConfig, this);
builder.populateConfig();
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
String msg = "error in closing input stream";
log.error(msg, e);
}
axisConfig.setConfigurator(this);
moduleDeployer = new ModuleDeployer(axisConfig);
new Axis2ModuleRegistry(axisConfig).register(moduleBundles);
new Axis2DeployerRegistry(axisConfig).register(deployerBundles);
return axisConfig;
}
@Override
public void cleanup() {
super.cleanup();
if (CarbonUtils.useRegistryBasedRepository()) {
RegistryBasedRepositoryUpdater.cancelTask(repoLocation);
}
}
private void setRegistry() throws DeploymentException {
Parameter param = new Parameter(WSO2Constants.CONFIG_SYSTEM_REGISTRY_INSTANCE, registry);
try {
axisConfig.addParameter(param);
} catch (AxisFault axisFault) {
throw new DeploymentException(axisFault.getMessage(), axisFault);
}
}
private void setUserRealm() throws DeploymentException {
Parameter param = new Parameter(WSO2Constants.USER_REALM_INSTANCE, registry.getUserRealm());
try {
axisConfig.addParameter(param);
} catch (AxisFault axisFault) {
throw new DeploymentException(axisFault.getMessage(), axisFault);
}
}
private static void setHostName(AxisConfiguration axisConfig) throws DeploymentException {
try {
ServerConfiguration serverConfig = ServerConfiguration.getInstance();
String hostName = serverConfig.getFirstProperty("HostName");
if (hostName != null) {
Parameter param = ParameterUtil.createParameter(HOST_ADDRESS, hostName);
axisConfig.addParameter(param);
}
} catch (AxisFault axisFault) {
throw new DeploymentException(axisFault.getMessage(), axisFault);
}
}
}