package org.easysoa.registry.dashboard.rest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import org.apache.log4j.Logger;
import org.easysoa.registry.DocumentService;
import org.easysoa.registry.EndpointMatchingService;
import org.easysoa.registry.ServiceMatchingService;
import org.easysoa.registry.SoaMetamodelService;
import org.easysoa.registry.rest.EasysoaModuleRoot;
import org.easysoa.registry.rest.samples.DashboardMatchingSamples;
import org.easysoa.registry.types.Component;
import org.easysoa.registry.types.Endpoint;
import org.easysoa.registry.types.InformationService;
import org.easysoa.registry.types.ServiceImplementation;
import org.easysoa.registry.types.SubprojectNode;
import org.easysoa.registry.utils.ContextData;
import org.easysoa.registry.utils.NXQLQueryHelper;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.core.api.IdRef;
import org.nuxeo.ecm.platform.query.nxql.NXQLQueryBuilder;
import org.nuxeo.ecm.webengine.jaxrs.session.SessionFactory;
import org.nuxeo.ecm.webengine.model.Template;
import org.nuxeo.ecm.webengine.model.WebObject;
import org.nuxeo.runtime.api.Framework;
/**
*
* @author mkalam-alami
*
*/
@WebObject(type = "dashboard")
@Path("easysoa/dashboard")
public class MatchingDashboard extends EasysoaModuleRoot {
private static Logger logger = Logger.getLogger(MatchingDashboard.class);
@GET
public Template viewDashboard(@QueryParam("subprojectId") String subprojectId,
@QueryParam("visibility") String visibility) {
CoreSession session = SessionFactory.getSession(request);
try {
DocumentService docService = Framework.getService(DocumentService.class);
Template view = getView("index");
String subprojectCriteria = NXQLQueryHelper.buildSubprojectCriteria(session, subprojectId, visibility);
// All information services
List<DocumentModel> allInfoServices = docService.getInformationServicesInCriteria(session, subprojectCriteria);
Map<String, DocumentModel> infoServicesById = new HashMap<String, DocumentModel>();
for (DocumentModel infoService : allInfoServices) {
infoServicesById.put(infoService.getId(), infoService);
}
view.arg("infoServicesById", infoServicesById);
// Find matched impls & their infoservice
DocumentModelList matchedImpls = docService.query(session, DocumentService.NXQL_SELECT_FROM
+ ServiceImplementation.DOCTYPE + subprojectCriteria + DocumentService.NXQL_AND
+ ServiceImplementation.XPATH_PROVIDED_INFORMATION_SERVICE + " IS NOT NULL ",
true, false);
view.arg("matchedImpls", matchedImpls);
// List unimplemented services
Map<String, DocumentModel> unimplementedServsMap = new HashMap<String, DocumentModel>(infoServicesById);
for (DocumentModel matchedImpl : matchedImpls) {
unimplementedServsMap.remove(
matchedImpl.getPropertyValue(ServiceImplementation.XPATH_PROVIDED_INFORMATION_SERVICE)
);
}
view.arg("unimplementedServs", unimplementedServsMap.values());
// Find matched endpoints & their impls
DocumentModelList matchedEndpoints = docService.query(session,
DocumentService.NXQL_SELECT_FROM + Endpoint.DOCTYPE + subprojectCriteria
+ DocumentService.NXQL_AND + Endpoint.XPATH_PARENTSIDS + " LIKE '%"
+ ServiceImplementation.DOCTYPE + ":%' ", true, false);
view.arg("matchedEndpoints", matchedEndpoints);
// List endpoints without impls
DocumentModelList unmatchedEndpoints = docService.query(session,
DocumentService.NXQL_SELECT_FROM + Endpoint.DOCTYPE + subprojectCriteria
+ DocumentService.NXQL_AND + Endpoint.XPATH_PARENTSIDS + " NOT LIKE '%"
+ ServiceImplementation.DOCTYPE + ":%' ", true, false); // TODO not updated on delete endpoint proxy ?!!
view.arg("endpointWithoutImpl", unmatchedEndpoints);
// List impls without infoservice
DocumentModelList servWithoutSpecs = docService.query(session,
DocumentService.NXQL_SELECT_FROM + ServiceImplementation.DOCTYPE + subprojectCriteria
+ DocumentService.NXQL_AND + ServiceImplementation.XPATH_PROVIDED_INFORMATION_SERVICE
+ " IS NULL ", true, false);
view.arg("servWithoutSpecs", servWithoutSpecs)
.arg("new_f", new freemarker.template.utility.ObjectConstructor())
.arg("subprojectId", subprojectId)
.arg("visibility", visibility)
.arg("contextInfo", ContextData.getVersionData(session, subprojectId));
return view;
} catch (Exception e) {
logger.debug(e);
return getView("error").arg("error", e);
}
}
@GET
@Path("components/{uuid}")
public Template suggestComponents(@PathParam("uuid") String uuid,
@QueryParam("subprojectId") String subprojectId,
@QueryParam("visibility") String visibility) throws Exception {
CoreSession session = SessionFactory.getSession(request);
Template view = viewDashboard(subprojectId, visibility);
DocumentModel modelElement = session.getDocument(new IdRef(uuid));
List<DocumentModel> suggestedComponents = fetchComponents(session, modelElement);
view.arg("components", suggestedComponents)
.arg("selectedModel", uuid)
.arg("new_f", new freemarker.template.utility.ObjectConstructor())
.arg("subprojectId", subprojectId)
.arg("visibility", visibility)
.arg("contextInfo", ContextData.getVersionData(session, subprojectId));
return view;
}
@GET
@Path("suggest/{uuid}")
public Template suggestServices(@PathParam("uuid") String uuid,
@QueryParam("subprojectId") String subprojectId,
@QueryParam("visibility") String visibility) throws Exception {
CoreSession session = SessionFactory.getSession(request);
DocumentModel model = session.getDocument(new IdRef(uuid));
Template view = viewDashboard(subprojectId, visibility);
// Args: suggestions
List<DocumentModel> suggestions = fetchSuggestions(session, model, null, false);
view.arg("suggestions", suggestions);
List<DocumentModel> anyPlatformSuggestions = fetchSuggestions(session, model, null, true);
if (suggestions.size() == 0) {
view.arg("anyPlatformSuggestions", anyPlatformSuggestions);
}
else {
view.arg("anyPlatformSuggestionsCount", anyPlatformSuggestions.size() - suggestions.size());
}
// Arg: selected document
view.arg("selectedModel", uuid)
.arg("new_f", new freemarker.template.utility.ObjectConstructor())
.arg("subprojectId", subprojectId)
.arg("visibility", visibility)
.arg("contextInfo", ContextData.getVersionData(session, subprojectId));
return view;
}
@GET
@Path("suggest/{uuid}/{componentUuid}")
public Template suggestServicesFromComponent(@PathParam("uuid") String uuid,
@PathParam("componentUuid") String componentUuid,
@QueryParam("subprojectId") String subprojectId,
@QueryParam("visibility") String visibility) throws Exception {
CoreSession session = SessionFactory.getSession(request);
DocumentModel model = session.getDocument(new IdRef(uuid));
Template view = viewDashboard(subprojectId, visibility);
// Args: components
List<DocumentModel> components = fetchComponents(session, model);
view.arg("components", fetchComponents(session, model));
for (DocumentModel component : components) {
if (component.getId().equals(componentUuid)) {
view.arg("selectedComponentTitle", component.getTitle());
break;
}
}
// Args: suggestions
List<DocumentModel> suggestions = fetchSuggestions(session, model, componentUuid, false);
view.arg("suggestions", suggestions);
List<DocumentModel> anyPlatformSuggestions = fetchSuggestions(session, model, componentUuid, true);
if (suggestions.size() == 0) {
view.arg("anyPlatformSuggestions", anyPlatformSuggestions);
}
else {
view.arg("anyPlatformSuggestionsCount", anyPlatformSuggestions.size() - suggestions.size());
}
if (anyPlatformSuggestions.size() == 0) {
String targetDoctype = Endpoint.DOCTYPE.equals(model.getType()) ?
ServiceImplementation.DOCTYPE :
InformationService.DOCTYPE;
String modelElementSubprojectId = (String) model.getPropertyValue(SubprojectNode.XPATH_SUBPROJECT);
String subprojectCriteria = NXQLQueryHelper.buildSubprojectCriteria(session, modelElementSubprojectId, true);
// TODO or according to model element type ??
// TODO or both subproject criteria intersected ?
// NXQLQueryHelper.buildSubprojectPathCriteria(session, subprojectId, visibility));
String infoServicesQuery = NXQLQueryBuilder.getQuery(DocumentService.NXQL_SELECT_FROM
+ "?" + subprojectCriteria + DocumentService.NXQL_AND + "? = '?'",
new Object[] {
targetDoctype,
Component.XPATH_COMPONENT_ID,
componentUuid
}, false, true);
DocumentService docService = Framework.getService(DocumentService.class);
view.arg("allFromComponent", docService.query(session, infoServicesQuery, true, false));
}
// Arg: selected document
view.arg("selectedModel", uuid)
.arg("new_f", new freemarker.template.utility.ObjectConstructor())
.arg("subprojectId", subprojectId)
.arg("visibility", visibility)
.arg("contextInfo", ContextData.getVersionData(session, subprojectId));
return view;
}
@POST
public Object submit(@FormParam("unmatchedModelId") String unmatchedModelId,
@FormParam("targetId") String targetId,
@QueryParam("subprojectId") String subprojectId,
@QueryParam("visibility") String visibility) {
try {
if (unmatchedModelId != null && !unmatchedModelId.isEmpty()) {
// Fetch impl
CoreSession session = SessionFactory.getSession(request);
DocumentModel model = session.getDocument(new IdRef(unmatchedModelId));
String doctype = model.getType();
DocumentService docService = Framework.getService(DocumentService.class);
SoaMetamodelService soaMetamodelService = Framework.getService(SoaMetamodelService.class);
boolean isServiceImplementation = soaMetamodelService.isAssignable(doctype, ServiceImplementation.DOCTYPE);
boolean isEndpoint = soaMetamodelService.isAssignable(doctype, Endpoint.DOCTYPE);
// Compute new link value
String newTargetId;
if (targetId != null && !targetId.isEmpty()) {
newTargetId = targetId; // Create link
}
else {
// No targetId, meaning it's rather a "delete link" command.
// Checking that there is a parent SOA node to unlink from :
if (isServiceImplementation && docService.getParentInformationService(model) == null) {
// no parent iserv, meaning it's not a "delete link command" but a UI bug
throw new Exception("Information Service not selected");
}
else if (isEndpoint && docService.getParentServiceImplementation(model) == null) {
// no parent serviceimpl, meaning it's not a "delete link command" but a UI bug
throw new Exception("Service Implementation not selected");
}
newTargetId = null; // Destroy link
}
// Apply on document
if (isServiceImplementation) {
ServiceMatchingService matchingService = Framework.getService(ServiceMatchingService.class);
matchingService.linkInformationService(session, model, newTargetId, true);
}
else { // isEndpoint
EndpointMatchingService matchingService = Framework.getService(EndpointMatchingService.class);
DocumentModel targetModel = (newTargetId != null) ? session.getDocument(new IdRef(targetId)) : null;
if (targetModel != null && soaMetamodelService.isAssignable(targetModel.getType(), ServiceImplementation.DOCTYPE)) {
matchingService.linkServiceImplementation(session, docService.createSoaNodeId(model),
((newTargetId != null) ? docService.createSoaNodeId(session.getDocument(new IdRef(newTargetId))) : null),
true/*, "strict"*/);
} else { // InformationService target through placeholder, or delete
matchingService.linkInformationServiceThroughPlaceholder(session, model, targetModel, true);
}
}
return viewDashboard(subprojectId, visibility);
}
else {
// error Service Implementation not selected, merely redisplay the page
return viewDashboard(subprojectId, visibility);
}
} catch (Exception e) {
logger.debug(e);
return getView("error").arg("error", e);
}
}
@POST
@Path("samples")
public Object submit(@QueryParam("subprojectId") String subprojectId,
@QueryParam("visibility") String visibility) throws Exception {
new DashboardMatchingSamples(this.getContext().getBaseURL()).run();
return viewDashboard(subprojectId, visibility);
}
/**
* TODO refactor as ComponentMatchingService.findComponents() ?
* @param session whose subproject will be used as point of view / perspective
* to find components
* @param modelElement
* @return
* @throws Exception
*/
private List<DocumentModel> fetchComponents(CoreSession session,
DocumentModel modelElement) throws Exception {
String modelElementSubprojectId = (String) modelElement.getPropertyValue(SubprojectNode.XPATH_SUBPROJECT);
String subprojectCriteria = NXQLQueryHelper.buildSubprojectCriteria(session, modelElementSubprojectId, true);
// TODO or according to model element type ??
// TODO or both subproject criteria intersected ?
// NXQLQueryHelper.buildSubprojectPathCriteria(session, subprojectId, visibility));
DocumentService docService = Framework.getService(DocumentService.class);
return docService.getComponentsInCriteria(session, subprojectCriteria);
}
private List<DocumentModel> fetchSuggestions(CoreSession session, DocumentModel model, String componentUuid,
boolean skipPlatformMatching) throws Exception {
if (model != null) {
// Run matching service according to doctype
if (Endpoint.DOCTYPE.equals(model.getType())) {
EndpointMatchingService matchingService = Framework.getService(EndpointMatchingService.class);
List<DocumentModel> matchingImpls = matchingService.findServiceImplementations(session,
model, componentUuid, skipPlatformMatching, false);
ServiceMatchingService serviceMatchingService = Framework.getService(ServiceMatchingService.class);
List<DocumentModel> matchingServices = serviceMatchingService.findInformationServices(session,
model, componentUuid, skipPlatformMatching, false);
List<DocumentModel> res = new ArrayList<DocumentModel>(matchingImpls.size() + matchingServices.size());
res.addAll(matchingImpls);
res.addAll(matchingServices);
return res;
}
else { // ServiceImplementation
ServiceMatchingService matchingService = Framework.getService(ServiceMatchingService.class);
return matchingService.findInformationServices(session,
model, componentUuid, skipPlatformMatching, false);
}
}
else {
return new ArrayList<DocumentModel>();
}
}
}