/*
* 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.governance.api.services;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.OMText;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.governance.api.common.dataobjects.GovernanceArtifact;
import org.wso2.carbon.governance.api.exception.GovernanceException;
import org.wso2.carbon.governance.api.services.dataobjects.Service;
import org.wso2.carbon.governance.api.util.GovernanceConstants;
import org.wso2.carbon.governance.api.util.GovernanceUtils;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.utils.RegistryUtils;
import javax.xml.namespace.QName;
import java.util.*;
/**
* This provides the management functionality for service artifacts stored on the registry.
*/
public class ServiceManager {
private static final Log log = LogFactory.getLog(ServiceManager.class);
private Registry registry;
private String serviceMediaType = GovernanceConstants.SERVICE_MEDIA_TYPE;
private String type = "service";
/**
* Constructor accepting an instance of the registry to use.
*
* @param registry the instance of the registry.
*/
public ServiceManager(Registry registry) {
this.registry = registry;
}
/**
* Constructor accepting an instance of the registry, and also details on the type of manager.
*
* @param registry the instance of the registry.
* @param mediaType the media type of resources being saved or fetched.
* @param type the type of manager used.
*/
protected ServiceManager(Registry registry, String mediaType, String type) {
this.registry = registry;
this.serviceMediaType = mediaType;
this.type = type;
}
/**
* Creates a new service artifact from the given qualified name.
*
* @param qName the qualified name of this service.
*
* @return the artifact added.
* @throws GovernanceException if the operation failed.
*/
public Service newService(QName qName) throws GovernanceException {
String serviceId = UUID.randomUUID().toString();
Service service = new Service(serviceId, qName);
service.associateRegistry(registry);
return service;
}
/**
* Creates a new service artifact from the given content.
*
* @param content the service content.
*
* @return the artifact added.
* @throws GovernanceException if the operation failed.
*/
public Service newService(OMElement content) throws GovernanceException {
String serviceId = UUID.randomUUID().toString();
Service service = new Service(serviceId, content);
service.associateRegistry(registry);
return service;
}
/**
* Adds the given service artifact to the registry.
*
* @param service the service artifact.
*
* @throws GovernanceException if the operation failed.
*/
public void addService(Service service) throws GovernanceException {
// adding the attributes for name, namespace + service
if (service.getQName() == null) {
String msg = "Name is not set. It have to be set as an qname.";
log.error(msg);
throw new GovernanceException(msg);
}
String serviceName = service.getQName().getLocalPart();
service.setAttributes(GovernanceConstants.SERVICE_NAME_ATTRIBUTE,
new String[]{serviceName});
// namespace can be null
String serviceNamespace = service.getQName().getNamespaceURI();
service.setAttributes(GovernanceConstants.SERVICE_NAMESPACE_ATTRIBUTE,
new String[]{serviceNamespace});
service.associateRegistry(registry);
boolean succeeded = false;
try {
registry.beginTransaction();
String serviceId = service.getId();
Resource serviceResource = registry.newResource();
serviceResource.setMediaType(serviceMediaType);
setContent(service, serviceResource);
serviceResource.setProperty(GovernanceConstants.ARTIFACT_ID_PROP_KEY, serviceId);
// the service will not actually stored in the tmp path.
String tmpPath = "/" + serviceName;
registry.put(tmpPath, serviceResource);
// GovernanceUtils.writeOwnerAssociations(registry, service);
// GovernanceUtils.writeConsumerAssociations(registry, service);
succeeded = true;
} catch (RegistryException e) {
String msg = "Failed to add artifact: artifact id: " + service.getId() +
", path: " + service.getPath() + ". " + e.getMessage();
log.error(msg, e);
throw new GovernanceException(msg, e);
} finally {
if (succeeded) {
try {
registry.commitTransaction();
} catch (RegistryException e) {
String msg =
"Error in committing transactions. Failed to add artifact: artifact " +
"id: " + service.getId() + ", path: " + service.getPath() + ".";
log.error(msg, e);
}
} else {
try {
registry.rollbackTransaction();
} catch (RegistryException e) {
String msg =
"Error in rolling back transactions. Failed to add artifact: " +
"artifact id: " + service.getId() + ", path: " +
service.getPath() + ".";
log.error(msg, e);
}
}
}
}
/**
* Updates the given service artifact on the registry.
*
* @param service the service artifact.
*
* @throws GovernanceException if the operation failed.
*/
public void updateService(Service service) throws GovernanceException {
boolean succeeded = false;
try {
registry.beginTransaction();
Service oldService = getService(service.getId());
// first check for the old service and remove it.
if (oldService != null) {
QName oldQname = oldService.getQName();
if (!oldQname.equals(service.getQName())) {
// then it is analogue to moving the resource for the new location
String oldPath = oldService.getPath();
// so just delete the old path
registry.delete(oldPath);
}
}
addService(service);
service.updatePath();
succeeded = true;
} catch (RegistryException e) {
String msg = "Error in updating the artifact, artifact id: " + service.getId() +
", artifact path: " + service.getPath() + ".";
log.error(msg, e);
throw new GovernanceException(msg, e);
} finally {
if (succeeded) {
try {
registry.commitTransaction();
} catch (RegistryException e) {
String msg =
"Error in committing transactions. Update artifact failed: artifact " +
"id: " + service.getId() + ", path: " + service.getPath() + ".";
log.error(msg, e);
}
} else {
try {
registry.rollbackTransaction();
} catch (RegistryException e) {
String msg =
"Error in rolling back transactions. Update artifact failed: " +
"artifact id: " + service.getId() + ", path: " +
service.getPath() + ".";
log.error(msg, e);
}
}
}
}
/**
* Fetches the given service artifact on the registry.
*
* @param serviceId the identifier of the service artifact.
*
* @return the service artifact.
* @throws GovernanceException if the operation failed.
*/
public Service getService(String serviceId) throws GovernanceException {
GovernanceArtifact artifact =
GovernanceUtils.retrieveGovernanceArtifactById(registry, serviceId);
if (artifact != null && !(artifact instanceof Service)) {
String msg = "The artifact request is not a " + type + ". id: " + serviceId + ".";
log.error(msg);
throw new GovernanceException(msg);
}
return (Service) artifact;
}
/**
* Removes the given service artifact from the registry.
*
* @param serviceId the identifier of the service artifact.
*
* @throws GovernanceException if the operation failed.
*/
public void removeService(String serviceId) throws GovernanceException {
GovernanceUtils.removeArtifact(registry, serviceId);
}
/**
* Sets content of the given service artifact to the given resource on the registry.
*
* @param service the service artifact.
* @param serviceResource the content resource.
*
* @throws GovernanceException if the operation failed.
*/
protected void setContent(Service service, Resource serviceResource) throws
GovernanceException {
try {
OMNamespace namespace = OMAbstractFactory.getOMFactory().
createOMNamespace(GovernanceConstants.SERVICE_ELEMENT_NAMESPACE, "");
Map<String, OMElement> elementsMap = new HashMap<String, OMElement>();
String[] attributeKeys = service.getAttributeKeys();
if (attributeKeys != null) {
OMElement contentElement =
OMAbstractFactory.getOMFactory().createOMElement(
GovernanceConstants.SERVICE_ELEMENT_ROOT, namespace);
for (String aggregatedKey : attributeKeys) {
String[] keys = aggregatedKey.split("_");
String elementsMapKey = null;
OMElement parentKeyElement = contentElement;
for (int i = 0; i < keys.length - 1; i++) {
String key = keys[i];
elementsMapKey = (elementsMapKey == null ? "" : elementsMapKey + "_") + key;
OMElement keyElement = elementsMap.get(elementsMapKey);
if (keyElement == null) {
keyElement = OMAbstractFactory.getOMFactory()
.createOMElement(key, namespace);
parentKeyElement.addChild(keyElement);
elementsMap.put(elementsMapKey, keyElement);
}
parentKeyElement = keyElement;
}
String[] attributeValues = service.getAttributes(aggregatedKey);
String elementName = keys[keys.length - 1];
for (String value : attributeValues) {
OMElement keyElement = OMAbstractFactory.getOMFactory()
.createOMElement(elementName, namespace);
OMText textElement = OMAbstractFactory.getOMFactory().createOMText(value);
keyElement.addChild(textElement);
parentKeyElement.addChild(keyElement);
}
}
String updatedContent = GovernanceUtils.serializeOMElement(contentElement);
serviceResource.setContent(updatedContent);
}
} catch (RegistryException e) {
String msg = "Error in saving attributes for the artifact. id: " + service.getId() +
", path: " + service.getPath() + ".";
log.error(msg, e);
throw new GovernanceException(msg, e);
}
}
/**
* Finds all service artifacts matching the given filter criteria.
*
* @param criteria the filter criteria to be matched.
*
* @return the service artifacts that match.
* @throws GovernanceException if the operation failed.
*/
public Service[] findServices(ServiceFilter criteria) throws GovernanceException {
List<Service> services = new ArrayList<Service>();
for (Service service : getAllServices()) {
if (service != null) {
if (criteria.matches(service)) {
services.add(service);
}
}
}
return services.toArray(new Service[services.size()]);
}
/**
* Finds all service artifacts on the registry.
*
* @return all service artifacts on the registry.
* @throws GovernanceException if the operation failed.
*/
public Service[] getAllServices() throws GovernanceException {
List<String> servicePaths =
Arrays.asList(GovernanceUtils.getResultPaths(registry,
serviceMediaType));
Collections.sort(servicePaths, new Comparator<String>() {
public int compare(String o1, String o2) {
long l1 = -1;
long l2 = -1;
String temp1 = RegistryUtils.getParentPath(o1);
String temp2 = RegistryUtils.getParentPath(o2);
try {
l1 = Long.parseLong(
RegistryUtils.getResourceName(temp1));
l2 = Long.parseLong(
RegistryUtils.getResourceName(temp2));
} catch (NumberFormatException ignore) {
}
// First order by name
int result = RegistryUtils.getResourceName(temp1).compareToIgnoreCase(
RegistryUtils.getResourceName(temp2));
if (result != 0) {
return result;
}
// Then order by namespace
result = temp1.compareToIgnoreCase(temp2);
if (result != 0) {
return result;
}
// Finally by version
return (l1 > l2) ? -1 : 1;
}
});
List<Service> services = new ArrayList<Service>();
for (String servicePath : servicePaths) {
GovernanceArtifact artifact =
GovernanceUtils.retrieveGovernanceArtifactByPath(registry, servicePath);
services.add((Service) artifact);
}
return services.toArray(new Service[services.size()]);
}
/**
* Finds all identifiers of the service artifacts on the registry.
*
* @return an array of identifiers of the service artifacts.
* @throws GovernanceException if the operation failed.
*/
public String[] getAllServiceIds() throws GovernanceException {
List<String> serviceIds = new ArrayList<String>();
for (Service service : getAllServices()) {
serviceIds.add(service.getId());
}
return serviceIds.toArray(new String[serviceIds.size()]);
}
}