package org.easysoa.registry;
import org.apache.log4j.Logger;
import org.easysoa.registry.types.Endpoint;
import org.easysoa.registry.types.InformationService;
import org.easysoa.registry.types.ServiceImplementation;
import org.nuxeo.ecm.core.api.ClientException;
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.event.Event;
import org.nuxeo.ecm.core.event.EventContext;
import org.nuxeo.ecm.core.event.EventListener;
import org.nuxeo.ecm.core.event.impl.DocumentEventContext;
import org.nuxeo.runtime.api.Framework;
/**
*
* @author mkalam-alami
*
*/
public class SoaNodeMatchingListener implements EventListener {
private static Logger logger = Logger.getLogger(SoaNodeMatchingListener.class);
@Override
public void handleEvent(Event event) throws ClientException {
// Ensure event nature
EventContext context = event.getContext();
if (!(context instanceof DocumentEventContext)) {
return;
}
DocumentEventContext documentContext = (DocumentEventContext) context;
DocumentModel sourceDocument = documentContext.getSourceDocument();
CoreSession documentManager = documentContext.getCoreSession();
if (sourceDocument.isVersion()) {
// ex. "documentCreated" because new version created :
// can't match better above now, not seen by more below until updateToVersion()
return;
}
// TODO check isSoaNode() ??
DocumentModel previousDocumentModel = (DocumentModel) documentContext.getProperty("previousDocumentModel");
// TODO check matching properties changes, in order to match only if they changed ??
// TODO compute spnode props if subproject changed ??? NO would require to save (which would trigger event loop)
match(documentManager, sourceDocument);
}
private void match(CoreSession documentManager, DocumentModel sourceDocument) throws ClientException {
DocumentService documentService;
ServiceMatchingService serviceMatchingService;
EndpointMatchingService endpointMatchingService;
try {
documentService = Framework.getService(DocumentService.class);
serviceMatchingService = Framework.getService(ServiceMatchingService.class);
endpointMatchingService = Framework.getService(EndpointMatchingService.class);
} catch (Exception e) {
logger.error("Document service unavailable, aborting");
return;
}
documentManager.save(); // so the just created ex. IS can be found in reverse from existing impl
// Endpoint: Link to service implementation
if (documentService.isTypeOrSubtype(documentManager, sourceDocument.getType(), Endpoint.DOCTYPE)) {
findAndMatchServiceImplementation(documentManager, documentService, endpointMatchingService, sourceDocument);
}
// Service impl: Link to information service and endpoints
if (documentService.isTypeOrSubtype(documentManager, sourceDocument.getType(), ServiceImplementation.DOCTYPE)
// NOT for placeholder impls, else when saved loops on finding matching endpoints
// TODO better : lock placeholder impls, merge placeholder impls...
&& ((Boolean) sourceDocument.getPropertyValue(ServiceImplementation.XPATH_ISPLACEHOLDER)) != true) {
DocumentModel serviceImpl = sourceDocument;
findAndMatchInformationService(documentManager, serviceMatchingService, serviceImpl);
// notify compatible unmatched endpoints that they may have found a match
// (only required if impls not versioned, since impls should have been discovered before endpoints)
DocumentModelList foundEndpoints = endpointMatchingService.findEndpointsCompatibleWithImplementation(documentManager, serviceImpl);
if (foundEndpoints.size() > 0) {
for (DocumentModel foundEndpoint : foundEndpoints) {
findAndMatchServiceImplementation(documentManager, documentService, endpointMatchingService, foundEndpoint);
}
}
// NB. created placeholder impls :
// - can't be matched by existing endpoints (since they already have impls, if placeholder ones)
// - can't be further merged here since they are only created if no existing matching impl
// - will have to be merged when new impls appear
}
// Information service: Find matching serviceimpls
if (documentService.isTypeOrSubtype(documentManager, sourceDocument.getType(), InformationService.DOCTYPE)) {
// notify compatible unmatched serviceImpls that they may have found a match
DocumentModelList foundServiceImpls = serviceMatchingService.findImplementationsCompatibleWithService(documentManager, sourceDocument);
if (foundServiceImpls.size() > 0) {
for (DocumentModel serviceImpl : foundServiceImpls) {
findAndMatchInformationService(documentManager, serviceMatchingService, serviceImpl);
}
}
// TODO notify compatible unmatched endpoints without impl that they may have found a match through aplaceholder
// (only required if ISes (and impls) are not versioned, since IS should have been defined before endpoints)
// TODO merge "placeholder" (i.e. created from source) service with Specifications one when
// referred Specifications change (add (remove) updateToVersion)
}
}
private void findAndMatchServiceImplementation(CoreSession documentManager,
DocumentService docService, EndpointMatchingService endpointMatchingService,
DocumentModel endpointDocument) throws ClientException {
if (endpointMatchingService.isEndpointAlreadyMatched(endpointDocument, documentManager)) {
return;
}
DocumentModelList foundImpls = endpointMatchingService.findServiceImplementations(
documentManager, endpointDocument, null, false, true);
if (foundImpls.size() == 1) {
try { // endpointMatchingService IMPROVE THAT called 4 times when links endpoints : endpoint created, impl modified, ..., endpoint proxy created
endpointMatchingService.linkServiceImplementation(documentManager,
docService.createSoaNodeId(endpointDocument),
docService.createSoaNodeId(foundImpls.get(0)), true);
// TODO if impl still unmatched and endpoint enriches impl with platform metas, trigger again IS match
}
catch (Exception e) {
logger.error(e);
}
}
else { //if (foundImpls.size() == 0) { // TODO better : find IS only among foundImpls if any
DocumentModelList foundIS = endpointMatchingService.findInformationServices(
documentManager, endpointDocument, null, true);
if (foundIS.size() == 1) {
try {
endpointMatchingService.linkInformationServiceThroughPlaceholder(documentManager,
endpointDocument, foundIS.get(0), true);
}
catch (Exception e) {
logger.error(e);
}
}
}
}
private void findAndMatchInformationService(CoreSession documentManager,
ServiceMatchingService serviceMatchingService, DocumentModel implDocument)
throws ClientException {
if (serviceMatchingService.isServiceImplementationAlreadyMatched(implDocument)) {
return;
}
DocumentModelList foundInformationServices = serviceMatchingService.findInformationServices(
documentManager, implDocument, null, false, true);
if (foundInformationServices.size() == 1) {
serviceMatchingService.linkInformationService(documentManager, implDocument,
foundInformationServices.get(0).getId(), true);
}
}
}