/*
* Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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 org.wso2.carbon.core.persistence;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.om.util.AXIOMUtil;
import org.apache.axis2.AxisFault;
import org.apache.axis2.description.AxisDescription;
import org.apache.axis2.description.AxisModule;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.neethi.Policy;
import org.apache.neethi.PolicyEngine;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.CarbonException;
import org.wso2.carbon.context.RegistryType;
import org.wso2.carbon.core.RegistryResources;
import org.wso2.carbon.core.multitenancy.SuperTenantCarbonContext;
import org.wso2.carbon.core.util.ParameterUtil;
import org.wso2.carbon.registry.core.Collection;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamWriter;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
/**
* Provides common logic for all extending PersistenceManager classes.
*/
public abstract class AbstractPersistenceManager {
private static final Log log = LogFactory.getLog(AbstractPersistenceManager.class);
/**
* The lock object used to synchronize database write locks.
*/
// TODO: See whether a cluster-wide lock needs to be created in here - Senaka.
protected static final Object WRITE_LOCK = new Object();
/**
* The Configuration registry instance in which all configuration data are stored.
*/
protected Registry configRegistry;
protected AxisConfiguration axisConfig;
/**
* Constructor gets the axis config and create reference to the config registry instances.
*
* @param axisConfig - AxisConfiguration
* @throws AxisFault - if the config registry is not found
*/
protected AbstractPersistenceManager(AxisConfiguration axisConfig) throws AxisFault {
this.axisConfig = axisConfig;
try {
configRegistry =
(Registry) SuperTenantCarbonContext.getCurrentContext(axisConfig).
getRegistry(RegistryType.SYSTEM_CONFIGURATION);
} catch (Exception e) {
log.error("Error while retrieving config registry from Axis configuration", e);
}
if (configRegistry == null) {
throw new AxisFault("Configuration Registry is not available");
}
}
/**
* If the parameter already exists, persist new value. Otherwise create a parameter resource
* and set the value
*
* @param path - param path to store
* @param parameter - parameter instance
* @throws RegistryException - on registry error
*/
protected void updateParameter(String path, Parameter parameter) throws RegistryException {
String paramResourcePath = path + RegistryResources.PARAMETERS + parameter.getName();
String paramName = parameter.getName();
int paramType = parameter.getParameterType();
if (paramName != null && paramName.trim().length() != 0) {
if (parameter.getParameterElement() == null && parameter.getValue() != null
&& parameter.getValue() instanceof String) {
try {
parameter = ParameterUtil.createParameter(paramName.trim(),
(String) parameter.getValue());
} catch (AxisFault ignore) {}
}
if (parameter.getParameterElement() != null) {
configRegistry.beginTransaction();
Resource paramResource;
if (!configRegistry.resourceExists(paramResourcePath)) {
paramResource = configRegistry.newResource();
} else {
paramResource = configRegistry.get(paramResourcePath);
}
paramResource.addProperty(RegistryResources.ParameterProperties.NAME, paramName);
paramResource.addProperty(RegistryResources.ParameterProperties.TYPE, Integer
.toString(paramType));
paramResource.setContent(parameter.getParameterElement().toString());
configRegistry.put(paramResourcePath, paramResource);
paramResource.discard();
configRegistry.commitTransaction();
}
}
}
/**
* Remove a parameter at the given path from the registry
*
* @param path - parameter path
* @param paramName - parameter name
* @throws Exception - on error
*/
protected void removeParameter(String path, String paramName) throws Exception {
removeResource(path + RegistryResources.PARAMETERS + paramName);
}
/**
* Remove a resource at the given path
*
* @param path - resource path
* @throws Exception - on registry error
*/
protected void removeResource(String path) throws Exception {
try {
configRegistry.beginTransaction();
if (configRegistry.resourceExists(path)) {
configRegistry.delete(path);
}
configRegistry.commitTransaction();
} catch (Throwable e) {
handleExceptionWithRollback("Unable to remove the resource at " + path, e);
}
}
/**
* Engage or disengage module at the given resource path.
*
* @param module - AxisModule instance
* @param resourcePath - registry path of a service group, service, operation etc
* @param engage - engage or disengage
* @throws Exception - on registry transaction errors
*/
protected void handleModuleForAxisDescription(AxisModule module, String resourcePath,
boolean engage) throws Exception {
configRegistry.beginTransaction();
String moduleResourcePath = PersistenceUtils.getResourcePath(module);
if (engage) {
configRegistry.addAssociation(resourcePath, moduleResourcePath,
RegistryResources.Associations.ENGAGED_MODULES);
} else {
configRegistry.removeAssociation(resourcePath, moduleResourcePath,
RegistryResources.Associations.ENGAGED_MODULES);
}
configRegistry.commitTransaction();
}
/**
* Load parameters for the given AxisDescription instance from registry
*
* @param ad - AxisDescription instance
* @param adPath - corresponding registry path
* @throws Exception - on error
*/
protected void loadParameters(AxisDescription ad, String adPath) throws Exception {
String adParamPath = adPath + RegistryResources.PARAMETERS;
Parameter skipParamInit = ad.getParameter(CarbonConstants.SKIP_PARAM_INIT);
if (skipParamInit == null || !(Boolean)skipParamInit.getValue()) {
if (configRegistry.resourceExists(adParamPath)) {
Collection adParameters = (Collection) configRegistry.get(adParamPath);
for (String paramPath : adParameters.getChildren()) {
Resource param = configRegistry.get(paramPath);
if (!(param instanceof Collection)) {
StAXOMBuilder builder = new StAXOMBuilder(param.getContentStream());
Parameter parameter = ParameterUtil.createParameter(builder
.getDocumentElement());
Parameter p = ad
.getParameter(param.getProperty(RegistryResources.NAME));
// don't override the param if it already exists and locked..
if (!(p != null && p.isLocked())) {
ad.addParameter(parameter);
}
}
param.discard();
}
adParameters.discard();
}
}
}
/**
* Write list of parameters to the registry
*
* @param paramList - Parameter list
* @param adPath - resource path to be written
* @throws Exception - on error
*/
protected void writeParameters(ArrayList<Parameter> paramList, String adPath) throws Exception {
for (Object o : paramList) {
Parameter parameter = (Parameter) o;
String paramName = parameter.getName();
if (paramName != null && paramName.trim().length() != 0) {
if (parameter.getParameterElement() == null && parameter.getValue() != null
&& parameter.getValue() instanceof String) {
parameter = ParameterUtil.createParameter(paramName.trim(),
(String) parameter.getValue());
}
if (parameter.getParameterElement() != null) {
Resource paramResource = configRegistry.newResource();
paramResource.setContent(parameter.getParameterElement().toString());
paramResource.addProperty(RegistryResources.NAME, parameter.getName());
configRegistry.put(adPath + RegistryResources.PARAMETERS
+ parameter.getName(), paramResource);
paramResource.discard();
}
}
}
}
/**
* Writes any AxisDescription instance to the registry with it's documentation and name as
* properties
*
* @param ad - AxisDescription instance
* @param nameProperty - name to be set
* @param path - path to store AxisDescription
* @throws RegistryException - error on registry operations
*/
protected void writeAxisDescription(AxisDescription ad, String nameProperty,
String path) throws RegistryException {
Collection collection = configRegistry.newCollection();
String doc = ad.getDocumentation();
if (doc != null) {
collection.setProperty(RegistryResources.ServiceProperties.DOCUMENTATION, doc);
}
collection.setProperty(RegistryResources.NAME, nameProperty);
configRegistry.put(path, collection);
}
/**
* Get all the values against a property of a given resource path
*
* @param resourcePath - resource path
* @param property - property name
* @return - list of values
* @throws RegistryException - on registry error
*/
protected List getPropertyValues(String resourcePath, String property) throws RegistryException {
Resource resource = configRegistry.get(resourcePath);
List values = resource.getPropertyValues(property);
resource.discard();
return values;
}
/**
* Load the documentation of an AxisDescription instance
*
* @param ad - AxisDescription instance to set the documentation
* @param resourcePath - resource path of the AxisDescription
* @throws RegistryException - on registry error
*/
protected void loadDocumentation(AxisDescription ad, String resourcePath)
throws RegistryException {
Resource resource = configRegistry.get(resourcePath);
String documentation = resource
.getProperty(RegistryResources.ServiceProperties.DOCUMENTATION);
if (documentation != null) {
try {
// tries to build an OMNode from the documentation
ad.setDocumentation(AXIOMUtil.stringToOM(documentation));
} catch (Exception e) {
ad.setDocumentation(documentation);
}
}
}
/**
* Load policies from the registry and attach to the AxisDescription instance.
*
* @param ad - AxisDescription instance
* @param policyIdList - list of policy UUIDs
* @param servicePath - all policies are stored at service level. Therefore, fetch the
* actual policy from service level
* @throws RegistryException - registry transaction errors
*/
protected void loadPolicies(AxisDescription ad, List policyIdList,
String servicePath) throws RegistryException {
// if AxisDescription is null, return
if (ad == null) {
return;
}
ad.getPolicySubject().clear();
if (policyIdList != null) {
for (Object servicePolicy : policyIdList) {
String currentPolicyUUID = (String) servicePolicy;
String policyResourcePath = servicePath + RegistryResources.POLICIES
+ currentPolicyUUID;
if (configRegistry.resourceExists(policyResourcePath)) {
Resource policyResource = configRegistry.get(policyResourcePath);
if (!(policyResource instanceof Collection)) {
Policy policy = PolicyEngine.getPolicy(policyResource.getContentStream());
ad.getPolicySubject().attachPolicy(policy);
}
policyResource.discard();
} else {
log.error("Failed to load Policy with ID " + currentPolicyUUID
+ ". The Policy does not exist.");
}
}
}
}
/**
* Checks whether the provided module is globally engaged. This is done using a property in
* the module resource
*
* @param resourcePath - module resource path
* @return - true if globally engaged, else false
* @throws RegistryException - error on reading registry
*/
protected boolean isGloballyEngaged(String resourcePath) throws RegistryException {
if (configRegistry.resourceExists(resourcePath)) {
Resource resource = configRegistry.get(resourcePath);
boolean globallyEngaged = Boolean.parseBoolean(resource
.getProperty(RegistryResources.ModuleProperties.GLOBALLY_ENGAGED));
resource.discard();
return globallyEngaged;
}
return false;
}
/**
* Creates a registry Resource for a given Policy
*
* @param policy - Policy instance
* @param policyId - policy uuid
* @param policyType - policy type
* @return - created policy resource
* @throws Exception - error on serialization
*/
protected Resource createPolicyResource(Policy policy,
String policyId, int policyType) throws Exception {
Resource policyResource = configRegistry.newResource();
policyResource.setProperty(RegistryResources.ServiceProperties.POLICY_UUID, policyId);
// Set the policy as a string in the resource
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
XMLStreamWriter writer = XMLOutputFactory.newInstance().createXMLStreamWriter(outputStream);
policy.serialize(writer);
writer.flush();
policyResource.setContent(outputStream.toString());
policyResource.setProperty(RegistryResources.ServiceProperties.POLICY_TYPE,
"" + policyType);
return policyResource;
}
/**
* Finds the existing AxisModule instance for a particular module. If the given module path
* exists in the registry, we just check the AxisConfig for that module. If it is not found,
* we search for a different version of the same module. If any of the versions exists in the
* system, return the found AxisModule instance.
*
* @param modulePath - current module path
* @return - AxisModule instance
* @throws Exception - on errors while accessing registry or on module not found
*/
protected AxisModule getExistingAxisModule(String modulePath) throws Exception {
// if there is an ending '/' remove it first
if (modulePath.endsWith("/")) {
modulePath = modulePath.substring(0, modulePath.length() -1);
}
AxisModule existingModule = null;
if (configRegistry.resourceExists(modulePath)) {
Resource givenResource = configRegistry.get(modulePath);
existingModule = getAxisModule(givenResource);
givenResource.discard();
}
// if the existingModule is null, check whether there are new versions..
if (existingModule == null) {
String temp = modulePath.substring(0, modulePath.lastIndexOf('/'));
if (configRegistry.resourceExists(temp)) {
Collection moduleVersions = (Collection) configRegistry.get(temp);
// we iterate through all the version of the module and finds on which currently
// exists in the system
for (String versionPath : moduleVersions.getChildren()) {
Resource versionResource = configRegistry.get(versionPath);
existingModule = getAxisModule(versionResource);
if (existingModule != null) {
versionResource.discard();
break;
}
versionResource.discard();
}
moduleVersions.discard();
}
}
if (existingModule == null) {
throw new CarbonException("Axis Module not found for resource path : " + modulePath);
}
return existingModule;
}
/**
* Handles exception and rollbacks an already started transaction. Don't use this method if
* you haven't already started a registry transaction
*
* @param msg - Message to log
* @param e - original exception
* @throws CarbonException - carbon exception to throw
*/
protected void handleExceptionWithRollback(String msg, Throwable e) throws Exception {
log.error(msg, e);
try {
configRegistry.rollbackTransaction();
} catch (RegistryException re) {
log.error("Transaction rollback failed", re);
}
throw new CarbonException(msg, e);
}
protected void handleException(String msg, Throwable e) throws Exception {
log.error(msg, e);
throw new CarbonException(msg, e);
}
protected void handleException(String msg) throws Exception {
log.error(msg);
throw new CarbonException(msg);
}
private AxisModule getAxisModule(Resource moduleResource) {
String modName = moduleResource.getProperty(RegistryResources.ModuleProperties.NAME);
String modVersion = moduleResource
.getProperty(RegistryResources.ModuleProperties.VERSION);
return axisConfig.getModule(modName, modVersion);
}
}