/*
* Copyright (c) 2013 Technische Universitat Wien (TUW), Distributed Systems Group. http://dsg.tuwien.ac.at
*
* This work was partially supported by the European Commission in terms of the CELAR FP7 project (FP7-ICT-2011-8 #317790), http://www.celarcloud.eu/
*
* 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 at.ac.tuwien.dsg.cloud.elise.master.RESTImp;
import at.ac.tuwien.dsg.cloud.elise.master.QueryManagement.neo4jAccess.ArtifactRepository;
import at.ac.tuwien.dsg.cloud.elise.master.QueryManagement.neo4jAccess.ConnectToInstanceRelationshipRepository;
import at.ac.tuwien.dsg.cloud.elise.master.QueryManagement.neo4jAccess.HostOnInstanceRelationshipRepository;
import at.ac.tuwien.dsg.cloud.elise.master.QueryManagement.neo4jAccess.ProviderRepository;
import at.ac.tuwien.dsg.cloud.elise.master.QueryManagement.neo4jAccess.ServiceTemplateRepository;
import at.ac.tuwien.dsg.cloud.salsa.domainmodels.types.ServiceCategory;
import at.ac.tuwien.dsg.cloud.elise.master.QueryManagement.neo4jAccess.UnitInstanceRepository;
import at.ac.tuwien.dsg.cloud.elise.master.QueryManagement.utils.EliseConfiguration;
import at.ac.tuwien.dsg.cloud.elise.master.RESTService.EliseManager;
import at.ac.tuwien.dsg.cloud.salsa.messaging.model.Elise.EliseQuery;
import at.ac.tuwien.dsg.cloud.salsa.messaging.model.Elise.EliseQueryRule;
import at.ac.tuwien.dsg.cloud.elise.model.relationships.ConnectToRelationshipInstance;
import at.ac.tuwien.dsg.cloud.elise.model.relationships.HostOnRelationshipInstance;
import at.ac.tuwien.dsg.cloud.elise.model.runtime.GlobalIdentification;
import at.ac.tuwien.dsg.cloud.elise.model.runtime.LocalIdentification;
import at.ac.tuwien.dsg.cloud.elise.model.runtime.UnitInstance;
import at.ac.tuwien.dsg.cloud.elise.model.generic.ExtensibleModel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Service;
import at.ac.tuwien.dsg.cloud.elise.master.RESTService.EliseRepository;
import at.ac.tuwien.dsg.cloud.elise.model.provider.Artifact;
import at.ac.tuwien.dsg.cloud.elise.model.provider.Provider;
import at.ac.tuwien.dsg.cloud.elise.model.provider.ServiceTemplate;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
/**
*
* @author Duc-Hung Le
*/
@Service
@Configurable
public class EliseRepositoryImpl implements EliseRepository {
Logger logger = EliseConfiguration.logger;
@Autowired
UnitInstanceRepository repo;
@Autowired
ConnectToInstanceRelationshipRepository connectToRepo;
@Autowired
HostOnInstanceRelationshipRepository hostOnRepo;
@Autowired
ProviderRepository pdrepo;
@Autowired
ArtifactRepository artifactRepo;
@Autowired
ServiceTemplateRepository serviceTemplateRepo;
@Override
public Set<UnitInstance> readAllUnitInstances(String name, String category, String state, String hostedOnID) {
Set<UnitInstance> theFullSet = repo.listUnitInstance();
Set<UnitInstance> theResult = new HashSet<>();
if (theFullSet != null) {
logger.debug("Getting list of the instance, size: {}", theFullSet.size());
for (UnitInstance instance : theFullSet) {
if ((name != null && instance.getName().equals(name))
|| (category != null && instance.getCategory().toString().equals(category))
|| (state != null && instance.getState().toString().toLowerCase().equals(state))
|| (hostedOnID != null && instance.getHostedOn() != null && instance.getHostedOn().getUuid().equals(hostedOnID))) {
theResult.add(instance);
}
}
return theResult;
} else {
logger.error("Getting list of the instance: FAILED.");
return null;
}
}
@Override
public UnitInstance readUnitInstance(String uniqueID) {
UnitInstance instance = repo.findByUniqueID(uniqueID);
if (instance != null) {
logger.debug("Get unit instance in elise DB, found name={},category={}", instance.getName(), instance.getCategory());
} else {
logger.error("Cannot get instance with id: {}", uniqueID);
}
return instance;
}
@Override
public UnitInstance saveUnitInstance(UnitInstance unitInstance) {
logger.debug("Save UnitInstance: " + unitInstance.getName());
UnitInstance existedInstance = null;
List<String> uuids = updateComposedIdentification(unitInstance);
StringBuilder result = new StringBuilder();
for (String uuid : uuids) {
result.append(uuid).append(" ");
//String uuid = updateComposedIdentification(unitInstance);
logger.debug("Found an instance can be merged with UUID: " + uuid);
existedInstance = this.repo.findByUniqueID(uuid);
logger.debug("SHOULD PASS THIS LINE 1");
// if unit is in data base, merge and save new one
// TODO: check Neo4j for better query to update node
if (existedInstance != null) {
//logger.debug("Deleting instance unit... ");
//this.repo.delete(existedInstance);
logger.debug("Deleting done..., now merging instance ...");
existedInstance.mergeWith(unitInstance);
// this.repo.deleteUnitByID(existedInstance.getId());
} else {
logger.debug("Found no existing instance, this saving instance will be the new one !");
existedInstance = unitInstance;
}
logger.debug("Start saving. Json: " + existedInstance.toJson());
UnitInstance u = this.repo.save(existedInstance);
logger.debug("Saved ...");
if (u != null) {
logger.debug("Saved unit instance:" + u.getUuid() + ", name: " + u.getName());
} else {
logger.debug("Fail to save unit instance: " + unitInstance.getUuid() + ", name: " + unitInstance.getName());
}
}
return existedInstance;
}
@Override
public Set<UnitInstance> readUnitInstanceByExtension(List<ExtensibleModel> extra) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Set<UnitInstance> query(EliseQuery query) {
logger.debug("Find instance by category: " + query.getCategory());
Set<UnitInstance> instances = repo.findByCategory(query.getCategory().toString());
Set<UnitInstance> result = filterInstance(instances, query);
logger.debug("Found " + result.size() + " of the query: " + query.toJson());
return result;
}
@Override
public Set<String> getUnitCategory() {
Set<String> set = new HashSet();
for (ServiceCategory c : ServiceCategory.values()) {
set.add(c.toString());
}
return set;
}
private List<String> updateComposedIdentification(UnitInstance instance) {
EliseManager eliseManager = ((EliseManager) JAXRSClientFactory.create(EliseConfiguration.getRESTEndpointLocal(), EliseManager.class, Collections.singletonList(new JacksonJsonProvider())));
//LocalIdentification si = LocalIdentification.fromJson(instance.getIdentification());
// unit instance carry the global iden of other elise, should be mix here
GlobalIdentification gi = instance.getIdentification();// GlobalIdentification.fromJson(instance.getIdentification());
// TODO: may scan all the local iden. Here just consider the first local iden.
if (gi == null || gi.getLocalIDs() == null || gi.getLocalIDs().isEmpty()) {
this.logger.error("The unit instance " + instance.getName() + " contains no identification attribute ! It cannot be add into database.");
return null;
}
LocalIdentification li = gi.getLocalIDs().get(0);
logger.debug("Updating identification for instance: " + instance.getName());
logger.debug("Local ID extracted: " + li.toJson());
// if there is no global ID exist, the instance.getId() will be the new ID
List<GlobalIdentification> globals = eliseManager.updateComposedIdentification(li, instance.getUuid());
if (globals.isEmpty()) {
this.logger.error("Cannot get the UUID of the composed-identification. That is impossible to happen !");
return null;
}
logger.debug("Global ID after query: {} IDs", globals.size());
// instance.setId(global.getUuid());
// instance.setIdentification(global.toJson());
List<String> listOfGlobalID = new ArrayList<>();
for (GlobalIdentification gl : globals) {
listOfGlobalID.add(gl.getUuid());
}
return listOfGlobalID;
}
private Set<UnitInstance> filterInstance(Set<UnitInstance> instances, EliseQuery query) {
Set<UnitInstance> filtered = new HashSet<>();
logger.debug("Filter " + instances.size() + " of the category: " + query.getCategory().toString());
int rulefulfill = 0; // 0: N/A, 1: fulfill, -1: violate
for (UnitInstance u : instances) {
logger.debug("Checking instance: " + u.getUuid() + "/" + u.getName());
Set<ExtensibleModel> extras = u.getExtra();
for (ExtensibleModel extra : extras) {
//for (Map.Entry<String, Object> entry : extra.entrySet()) {
// for (Metric value : u.findAllMetricValues()) {
for (EliseQueryRule rule : query.getRules()) {
logger.debug("Comparing unit(" + extra.getClazz().getSimpleName() + "=" + rule.getMetric() + " with the rule " + rule.toString());
if (extra.getClazz().getSimpleName().equals(rule.getMetric())) { // if the metric name is match
if (rule.isFulfilled(rule.getMetric())) { // check if value is fulfill
logger.debug("One rule fulfilled !");
rulefulfill += 1; // add one to the counting of fulfilled value
} else {
logger.debug("A rule is violated ! BREAK !");
rulefulfill -= 1; // or reduce it and break as a rule is violated
break;
}
}
}
// if all the condition is fulfill, fulfill = rule.size()
if (rulefulfill == query.getRules().size()) { // if rules are fulfilled
logger.debug("Fullfill all rules, now checking unit instance if fullfill. Fulfilled count: " + rulefulfill + " with no. of rules: " + query.getRules().size());
Set<String> capas = u.findAllCapabilities(); // also check capability
if (capas.containsAll(query.getHasCapabilities())) {
filtered.add(u);
}
}
}
}
return filtered;
}
@Override
public void deleteUnitInstance(String uniqueID) {
UnitInstance existedInstance = this.repo.findByUniqueID(uniqueID);
if (existedInstance != null) {
logger.debug("Deleting unit instance ID {}", uniqueID);
repo.delete(existedInstance);
} else {
logger.debug("Cannot delete the instance unit from GraphDB with ID: {}", uniqueID);
}
}
@Override
public void saveRelationshipHostOn(HostOnRelationshipInstance hostOnRela) {
logger.debug("Saving relationship between: " + hostOnRela.getFrom().getUuid() + " and " + hostOnRela.getTo().getUuid() + ". Json: " + hostOnRela.toJson());
// this.hostOnRepo.createRelationshipBetween(hostOnRela.getFrom(), hostOnRela.getTo(), HostOnRelationshipInstance.class, "HostOn");
if (this.hostOnRepo == null) {
logger.error("hostOnRepo is null !!");
return;
}
this.hostOnRepo.save(hostOnRela);
}
@Override
public void saveRelationshipConnectTo(ConnectToRelationshipInstance connectToRela) {
logger.debug("Saving relationship between: " + connectToRela.getFrom().getUuid() + " and " + connectToRela.getTo().getUuid() + ". Json: " + connectToRela.toJson());
// this.connectToRepo.createRelationshipBetween(connectToRela.getFrom(), connectToRela.getTo(), ConnectToRelationshipInstance.class, "ConnectTo");
if (this.connectToRepo == null) {
logger.error("connectToRepo is null !!");
return;
}
this.connectToRepo.save(connectToRela);
}
@Override
public Provider readProvider(String uniqueID) {
return pdrepo.findByUniqueID(uniqueID);
}
@Override
public Set<Provider> readAllProviders() {
return pdrepo.listProviders();
}
@Override
public String saveProvider(Provider provider) {
if (pdrepo == null) {
logger.error("Cannot load ProviderRepository !");
return null;
}
logger.debug("Prepare to add provider: ID=" + provider.getUuid());
if (provider.getOffering() != null) {
logger.debug("This provider has " + provider.getOffering().size() + " OSU(s)");
}
// for (GenericServiceUnit u : provider.getOffering()) {
// logger.debug("Prepare to add offering: " + u.getId() + " - " + u.getCategory() );
// offerServiceDAO.addOfferServiceUnitForProvider(u, provider.getId());
// }
Provider r = pdrepo.save(provider);
return "Saved the provider to graph with id: " + r.getUuid();
}
@Override
public void deleteProvider(String uniqueID) {
this.pdrepo.deleteProviderCompletelyByID(uniqueID);
}
@Override
public ServiceTemplate readServiceTemplate(String uniqueID) {
return serviceTemplateRepo.findByUniqueID(uniqueID);
}
@Override
public Set<ServiceTemplate> readAllServiceTemplates() {
return serviceTemplateRepo.listServiceTemplate();
}
@Override
public ServiceTemplate saveServiceTemplate(ServiceTemplate serviceTemplate) {
ServiceTemplate existed = serviceTemplateRepo.findByUniqueID(serviceTemplate.getUuid());
if (existed != null) {
serviceTemplate.setGraphID(existed.getGraphID());
}
return serviceTemplateRepo.save(serviceTemplate);
}
@Override
public void deleteServiceTemplate(String uniqueID) {
ServiceTemplate s = serviceTemplateRepo.findByUniqueID(uniqueID);
if (s != null) {
serviceTemplateRepo.delete(s);
}
}
/**
* MANAGE ARTIFACT *
*/
@Override
public Set<Artifact> readArtifact(String name, String version, String type) {
Set<Artifact> arts = artifactRepo.findByName(name);
for (Artifact a : arts) {
if ((version != null && !version.equals(a.getVersion()))
|| (type != null && !type.equals(a.getType().toString()))) {
arts.remove(a);
}
}
return arts;
}
@Override
public Artifact saveArtifact(Artifact artifact) {
System.out.println("Saving artifact...: " + artifact.writeToJson());
logger.debug("Saving artifact...: " + artifact.writeToJson());
return artifactRepo.save(artifact);
}
@Override
public void deleteArtifact(Artifact artifact) {
artifactRepo.delete(artifact);
}
public String health() {
return "Service is alive !";
}
}