/*
* Copyright 2005-2007 WSO2, Inc. (http://wso2.com)
*
* 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.deployment;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import org.apache.axis2.description.AxisDescription;
import org.apache.axis2.description.AxisModule;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.AxisServiceGroup;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.axis2.engine.AxisEvent;
import org.apache.axis2.engine.AxisObserver;
import org.apache.axis2.util.JavaUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.Axis2ModuleNotFound;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.core.RegistryResources;
import org.wso2.carbon.core.internal.CarbonCoreDataHolder;
import org.wso2.carbon.core.multitenancy.SuperTenantCarbonContext;
import org.wso2.carbon.core.persistence.PersistenceFactory;
import org.wso2.carbon.core.util.SystemFilter;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.jdbc.utils.Transaction;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* This deployment interceptor will be called whenever before a module is initialized or service is
* deployed.
*
* @see AxisObserver
*/
public class DeploymentInterceptor implements AxisObserver {
private static final Log log = LogFactory.getLog(DeploymentInterceptor.class);
private final Map<String, Parameter> paramMap = new HashMap<String, Parameter>();
private final HashMap<String, HashMap<String, AxisDescription>> faultyServicesDueToModules =
new HashMap<String, HashMap<String, AxisDescription>>();
private PersistenceFactory pf;
private Registry registry;
private int tenantId = -1;
private String tenantDomain = null;
private CarbonCoreDataHolder dataHolder = CarbonCoreDataHolder.getInstance();
public void setRegistry(Registry registry) {
this.registry = registry;
}
public void init(AxisConfiguration axisConfig) {
extractTenantInfo(axisConfig);
pf = new PersistenceFactory(axisConfig);
try {
if (registry == null) {
registry =
dataHolder.getRegistryService().getConfigSystemRegistry();
}
} catch (Exception e) {
log.error("Error while obtaining registry instance for the deployment interceptor", e);
}
}
private void extractTenantInfo(AxisConfiguration axisConfig) {
SuperTenantCarbonContext carbonContext = SuperTenantCarbonContext.getCurrentContext(axisConfig);
tenantId = carbonContext.getTenantId();
tenantDomain = carbonContext.getTenantDomain();
}
private String getTenantIdAndDomainString() {
return (tenantId != -1 && tenantId != MultitenantConstants.SUPER_TENANT_ID) ?
" {" + tenantDomain + "[" + tenantId + "]}" : " {super-tenant}";
}
public void serviceGroupUpdate(AxisEvent axisEvent, AxisServiceGroup axisServiceGroup) {
SuperTenantCarbonContext.startTenantFlow();
try {
SuperTenantCarbonContext carbonContext = SuperTenantCarbonContext.getCurrentContext();
carbonContext.setTenantId(tenantId);
carbonContext.setTenantDomain(tenantDomain);
// We do not persist Admin service events
if (SystemFilter.isFilteredOutService(axisServiceGroup)) {
return;
}
int eventType = axisEvent.getEventType();
if (eventType == AxisEvent.SERVICE_DEPLOY) {
if (log.isDebugEnabled()) {
log.debug("Deploying service group : " +
axisServiceGroup.getServiceGroupName() + getTenantIdAndDomainString());
}
Resource serviceGroup = null;
try {
serviceGroup = pf.getServiceGroupPM()
.getServiceGroup(axisServiceGroup.getServiceGroupName());
} catch (Exception e) {
log.error("Couldn't read service group resource." +
getTenantIdAndDomainString(), e);
}
if (serviceGroup == null) {
addServiceGroup(axisServiceGroup);
} else {
String hashFromFile = CarbonUtils.computeServiceHash(axisServiceGroup);
// Check whether the artifact has been updated, if so we need to purge all
// database entries and treat this as a new service group addition
String hashFromRegistry = serviceGroup.getProperty(RegistryResources
.ServiceGroupProperties.HASH_VALUE);
if (hashFromFile != null && hashFromRegistry != null &&
!hashFromRegistry.equals(hashFromFile)) {
log.warn("The service artifact of the " +
axisServiceGroup.getServiceGroupName() +
" service group has changed. Removing all registry entries and " +
"handling this as a new service addition." +
getTenantIdAndDomainString());
try {
registry.beginTransaction();
deleteServiceGroup(axisServiceGroup);
addServiceGroup(axisServiceGroup);
if (Transaction.isStarted()) {
// This is a safety measure. We ideally shouldn't be getting here
// since the Persistence Manager running underneath should commit
// the transaction.
registry.commitTransaction();
}
} catch (Exception e) {
String msg = "Unable to remove all registry entries and handle new" +
"service addition [" + axisServiceGroup.getServiceGroupName() +
"]" + getTenantIdAndDomainString();
try {
registry.rollbackTransaction();
// We need to catch the exception that is generated by
// rollbackTransaction(), should there be any, as this method won't
// throw exceptions.
log.error(msg, e);
} catch (Exception ex) {
msg += ". Unable to rollback transaction.";
log.error(msg, ex);
}
}
} else {
try {
pf.getServiceGroupPM()
.handleExistingServiceGroupInit(serviceGroup, axisServiceGroup);
} catch (Axis2ModuleNotFound e) {
addFaultyServiceDueToModule(e.getModuleName(), axisServiceGroup);
stopServiceGroup(axisServiceGroup,
axisServiceGroup.getAxisConfiguration());
log.warn("ServiceGroup: " + axisServiceGroup.getServiceGroupName() +
"is stopped due to the missing module : " + e.getModuleName() +
getTenantIdAndDomainString());
} catch (Exception e) {
String msg = "Could not handle initialization of existing service " +
"group [" + axisServiceGroup.getServiceGroupName() + "]" +
getTenantIdAndDomainString();
log.error(msg, e);
}
}
serviceGroup.discard();
}
} else if (eventType == AxisEvent.SERVICE_REMOVE) {
Parameter svcHistoryParam = axisServiceGroup.getParameter(
CarbonConstants.KEEP_SERVICE_HISTORY_PARAM);
if (svcHistoryParam == null || svcHistoryParam.getValue() == null ||
JavaUtils.isFalse(svcHistoryParam.getValue())) {
if (log.isDebugEnabled()) {
log.debug("Removing service group : " +
axisServiceGroup.getServiceGroupName() +
getTenantIdAndDomainString());
}
deleteServiceGroup(axisServiceGroup);
}
}
} finally {
SuperTenantCarbonContext.endTenantFlow();
}
}
private void addServiceGroup(AxisServiceGroup axisServiceGroup) {
try {
pf.getServiceGroupPM().handleNewServiceGroupAddition(axisServiceGroup);
} catch (Exception e) {
String msg = "Could not handle initialization of new service group [" +
axisServiceGroup.getServiceGroupName() + "]";
log.error(msg, e);
}
}
private void deleteServiceGroup(AxisServiceGroup axisServiceGroup) {
try {
pf.getServiceGroupPM().deleteServiceGroup(axisServiceGroup);
} catch (Exception e) {
log.error("Could not delete service group " + axisServiceGroup.getServiceGroupName() +
getTenantIdAndDomainString(), e);
}
}
public void serviceUpdate(AxisEvent axisEvent, AxisService axisService) {
SuperTenantCarbonContext.startTenantFlow();
try {
SuperTenantCarbonContext carbonContext = SuperTenantCarbonContext.getCurrentContext();
carbonContext.setTenantId(tenantId);
carbonContext.setTenantDomain(tenantDomain);
// We do not persist Admin service events
if (SystemFilter.isFilteredOutService((AxisServiceGroup) axisService.getParent())) {
return;
}
if (axisService.isClientSide()) {
return;
}
int eventType = axisEvent.getEventType();
String serviceName = axisService.getName();
try {
Resource service = pf.getServicePM().getService(axisService);
// if (eventType == AxisEvent.SERVICE_STOP) do nothing
if (eventType == AxisEvent.SERVICE_DEPLOY) {
if (!JavaUtils.isTrue(axisService.getParameterValue(
CarbonConstants.HIDDEN_SERVICE_PARAM_NAME))) {
log.info("Deploying Axis2 service: " + serviceName +
getTenantIdAndDomainString());
} else if (log.isDebugEnabled()) {
log.debug("Deploying hidden Axis2 service : " + serviceName +
getTenantIdAndDomainString());
}
if (service == null) {
pf.getServicePM().handleNewServiceAddition(axisService);
} else {
pf.getServicePM().handleExistingServiceInit(service, axisService);
}
} else if (eventType == AxisEvent.SERVICE_START) {
service.setProperty(RegistryResources.ServiceProperties.ACTIVE, "true");
} else if (eventType == AxisEvent.SERVICE_STOP && service != null) {
// in a shared registry scenario the resource could have been already removed
// by some other node
service.setProperty(RegistryResources.ServiceProperties.ACTIVE, "false");
} else if (eventType == AxisEvent.SERVICE_REMOVE) {
if (service != null) {
try {
Parameter svcHistoryParam = axisService.getParameter(
CarbonConstants.KEEP_SERVICE_HISTORY_PARAM);
if (svcHistoryParam == null || svcHistoryParam.getValue() == null ||
JavaUtils.isFalse(svcHistoryParam.getValue())) {
pf.getServicePM().deleteService(axisService);
}
} catch (Exception e) {
String msg = "Cannot delete service [" + serviceName + "]" +
getTenantIdAndDomainString();
log.error(msg, e);
}
}
}
if (service != null) {
service.discard();
}
} catch (Axis2ModuleNotFound e) {
addFaultyServiceDueToModule(e.getModuleName(), axisService);
stopService(axisService, axisService.getAxisConfiguration());
log.warn("Service " + axisService.getName() +
" is stopped due to the missing module: " + e.getModuleName() +
getTenantIdAndDomainString());
} catch (Exception e) {
String msg = "Exception occurred while handling service update event." +
getTenantIdAndDomainString();
log.error(msg, e);
}
} finally {
SuperTenantCarbonContext.endTenantFlow();
}
}
public void moduleUpdate(AxisEvent axisEvent, AxisModule axisModule) {
SuperTenantCarbonContext.startTenantFlow();
try {
SuperTenantCarbonContext carbonContext = SuperTenantCarbonContext.getCurrentContext();
carbonContext.setTenantId(tenantId);
carbonContext.setTenantDomain(tenantDomain);
//TODO: Check whether we can ignore AdminModules - SystemFilter.isFilteredOutModule
// We ignore admin module events
String moduleName = axisModule.getName();
/*if (moduleName.equals(ServerConstants.ADMIN_MODULE) ||
moduleName.equals(ServerConstants.TRACER_MODULE) ||
moduleName.equals(ServerConstants.STATISTICS_MODULE)) {
return;
}*/
// Handle.MODULE_DEPLOY event. This may be a new or existing module
if (axisEvent.getEventType() == AxisEvent.MODULE_DEPLOY) {
String moduleVersion;
if (axisModule.getVersion() == null) {
log.warn("A valid Version not found for the module : '" + moduleName + "'" +
getTenantIdAndDomainString());
moduleVersion = RegistryResources.ModuleProperties.UNDEFINED;
} else {
moduleVersion = axisModule.getVersion().toString();
}
if (!SystemFilter.isFilteredOutModule(axisModule)) {
log.info("Deploying Axis2 module: " + axisModule.getArchiveName() +
getTenantIdAndDomainString());
}
Resource module = null;
try {
module = pf.getModulePM().getModule(moduleName, moduleVersion);
} catch (Exception e) {
log.error("Couldn't read the module resource" +
getTenantIdAndDomainString(), e);
}
if (module != null) {
try {
pf.getModulePM().handleExistingModuleInit(module, axisModule);
} catch (Exception e) {
log.error("Could not handle initialization of existing module" +
getTenantIdAndDomainString(), e);
}
module.discard();
} else { // this is a new module which has not been registered in the DB yet
try {
pf.getModulePM().handleNewModuleAddition(axisModule, moduleName,
moduleVersion);
} catch (Exception e) {
log.error("Could not handle addition of new module" +
getTenantIdAndDomainString(),
e);
}
}
synchronized (faultyServicesDueToModules) {
//Check whether there are faulty services due to this module
HashMap<String, AxisDescription> faultyServices =
getFaultyServicesDueToModule(moduleName);
//noinspection unchecked
faultyServices = (HashMap<String, AxisDescription>) faultyServices.clone();
// Here iterating a cloned hash-map and modifying the original hash-map.
// To avoid the ConcurrentModificationException.
for (AxisDescription axisDescription : faultyServices.values()) {
removeFaultyServiceDueToModule(moduleName,
(String) axisDescription.getKey());
Resource axisDescriptionResource;
try {
//Recover the faulty serviceGroup or service.
if (axisDescription instanceof AxisServiceGroup) {
AxisServiceGroup axisServiceGroup =
(AxisServiceGroup) axisDescription;
axisDescriptionResource = pf.getServiceGroupPM().getServiceGroup(
axisServiceGroup.getServiceGroupName());
pf.getServiceGroupPM().handleExistingServiceGroupInit(
axisDescriptionResource, axisServiceGroup);
//Start all the services in this serviceGroup and remove the special
// parameter
startServiceGroup(axisServiceGroup,
axisServiceGroup.getAxisConfiguration());
log.info("Recovered and Deployed axis2 service group: " +
axisServiceGroup.getServiceGroupName() +
getTenantIdAndDomainString());
} else if (axisDescription instanceof AxisService) {
AxisService axisService = (AxisService) axisDescription;
axisDescriptionResource = pf.getServicePM().getService(axisService);
pf.getServicePM().handleExistingServiceInit(axisDescriptionResource,
axisService);
//Start this axisService and remove the special parameter.
startService(axisService, axisService.getAxisConfiguration());
log.info("Recovered and Deployed axis2 service: " +
axisService.getName() +
getTenantIdAndDomainString());
}
} catch (Axis2ModuleNotFound e) {
addFaultyServiceDueToModule(e.getModuleName(), axisDescription);
} catch (Exception e) {
String msg = "Could not handle initialization of existing service " +
"group [" + axisDescription.getKey() + "]" +
getTenantIdAndDomainString();
log.error(msg, e);
}
}
}
}
} finally {
SuperTenantCarbonContext.endTenantFlow();
}
}
public void addParameter(Parameter parameter) throws AxisFault {
paramMap.put(parameter.getName(), parameter);
}
public void removeParameter(Parameter param) throws AxisFault {
paramMap.remove(param.getName());
}
public void deserializeParameters(OMElement omElement) throws AxisFault {
//No need to do anything here
}
public Parameter getParameter(String paramName) {
return paramMap.get(paramName);
}
public ArrayList<Parameter> getParameters() {
Collection<Parameter> collection = paramMap.values();
ArrayList<Parameter> arr = new ArrayList<Parameter>();
for (Parameter aCollection : collection) {
arr.add(aCollection);
}
return arr;
}
public boolean isParameterLocked(String paramName) {
return (paramMap.get(paramName)).isLocked();
}
/**
* Updates the map that keeps track of faulty services due to modules
*
* @param moduleName This service has become faulty due this module.
* @param axisDescription Data that are required when recovering the faulty service.
*/
private void addFaultyServiceDueToModule(String moduleName, AxisDescription axisDescription) {
HashMap<String, AxisDescription> faultyServicesMap;
synchronized (faultyServicesDueToModules) {
if (faultyServicesDueToModules.containsKey(moduleName)) {
faultyServicesMap = faultyServicesDueToModules.get(moduleName);
faultyServicesMap.put((String) axisDescription.getKey(), axisDescription);
} else {
faultyServicesMap = new HashMap<String, AxisDescription>();
faultyServicesMap.put((String) axisDescription.getKey(), axisDescription);
faultyServicesDueToModules.put(moduleName, faultyServicesMap);
}
}
}
private HashMap<String, AxisDescription> getFaultyServicesDueToModule(String moduleName) {
if (faultyServicesDueToModules.containsKey(moduleName)) {
return faultyServicesDueToModules.get(moduleName);
}
return new HashMap<String, AxisDescription>(1);
}
private void removeFaultyServiceDueToModule(String moduleName, String serviceGroupName) {
synchronized (faultyServicesDueToModules) {
HashMap<String, AxisDescription> faultyServices =
faultyServicesDueToModules.get(moduleName);
if (faultyServices != null) {
faultyServices.remove(serviceGroupName);
if (faultyServices.isEmpty()) {
faultyServicesDueToModules.remove(moduleName);
}
}
}
}
public void startServiceGroup(AxisServiceGroup serviceGroup,
AxisConfiguration axisConfiguration) {
for (Iterator itr = serviceGroup.getServices(); itr.hasNext();) {
startService((AxisService) itr.next(), axisConfiguration);
}
}
public void stopServiceGroup(AxisServiceGroup serviceGroup,
AxisConfiguration axisConfiguration) {
for (Iterator itr = serviceGroup.getServices(); itr.hasNext();) {
stopService((AxisService) itr.next(), axisConfiguration);
}
}
public void startService(AxisService axisService, AxisConfiguration axisConfiguration) {
String serviceName = axisService.getName();
if (log.isDebugEnabled()) {
log.debug("Activating service: " + serviceName + getTenantIdAndDomainString());
}
try {
axisConfiguration.startService(serviceName);
//Removing the special special property
Parameter param = axisService.getParameter(CarbonConstants.CARBON_FAULTY_SERVICE);
if (param != null) {
axisService.removeParameter(param);
}
} catch (AxisFault e) {
String msg = "Cannot start service : " + serviceName + getTenantIdAndDomainString();
log.error(msg, e);
}
}
public void stopService(AxisService axisService, AxisConfiguration axisConfiguration) {
String serviceName = axisService.getName();
if (log.isDebugEnabled()) {
log.debug("Deactivating service: " + serviceName + getTenantIdAndDomainString());
}
try {
axisConfiguration.stopService(serviceName);
axisService.addParameter(CarbonConstants.CARBON_FAULTY_SERVICE,
CarbonConstants.CARBON_FAULTY_SERVICE_DUE_TO_MODULE);
} catch (AxisFault e) {
String msg = "Cannot stop service: " + serviceName + getTenantIdAndDomainString();
log.error(msg, e);
}
}
}