/******************************************************************************* * Copyright (c) 2007-2008 Cambridge Semantics Incorporated. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Cambridge Semantics Incorporated *******************************************************************************/ package org.openanzo.execution; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.openanzo.client.AnzoClient; import org.openanzo.client.pool.AnzoClientPool; import org.openanzo.client.pool.RestrictedAnzoClient; import org.openanzo.exceptions.AnzoException; import org.openanzo.exceptions.AnzoRuntimeException; import org.openanzo.exceptions.ExceptionConstants; import org.openanzo.exceptions.LogUtils; import org.openanzo.ontologies.execution.SemanticOperation; import org.openanzo.ontologies.execution.SemanticService; import org.openanzo.ontologies.execution.SemanticServiceFactory; import org.openanzo.ontologies.execution.StateStyleEnum; import org.openanzo.ontologies.openanzo.AnzoFactory; import org.openanzo.ontologies.openanzo.Dataset; import org.openanzo.ontologies.openanzo.DatasetListener; import org.openanzo.ontologies.openanzo.NamedGraph; import org.openanzo.osgi.registry.RegistryDataset; import org.openanzo.rdf.IDataset; import org.openanzo.rdf.Statement; import org.openanzo.rdf.URI; import org.openanzo.rdf.vocabulary.RDF; import org.openanzo.services.AnzoPrincipal; import org.openanzo.services.IOperationContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Base Service Executor * * @author Ben Szekely ( <a href="mailto:ben@cambridgesemantics.com">ben@cambridgesemantics.com </a>) * */ public abstract class BaseServiceExecutor implements ISemanticServiceExecutor { private static final Logger log = LoggerFactory.getLogger(BaseServiceExecutor.class); private Map<URI, ServiceInfo> servicesInfo = null; private SemanticServiceExecutionService hostExecutionService = null; private AnzoClientPool anzoClientPool = null; protected RegistryDataset serviceRegistry = null; protected org.openanzo.ontologies.openanzo.Dataset dataset = null; protected final DatasetListener listener = new DsListener(); /** * Initialize the service * * @param service * Service to initialize * @param anzoClient * client used to initialize * @return true if initialized * @throws AnzoException */ public abstract boolean initializeService(SemanticService service, AnzoClient anzoClient) throws AnzoException; /** * Stop the service * * @param serviceUri * uri of the service * @param anzoClient * client used to stop the service * @throws AnzoException */ public abstract void stopService(URI serviceUri, AnzoClient anzoClient) throws AnzoException; /** * Verify that the operation is valid * * @param serviceUri * uri of the service * @param operationUri * uri of the operation to verify * @throws AnzoException */ public abstract void verifyOperation(URI serviceUri, URI operationUri) throws AnzoException; /** * Execute the service * * @param serviceUri * uri of the service * @param operationUri * uri of the operation * @param executionContext * context of execution * @param request * dataset containing the request * @param response * dataset containg the response * @throws AnzoException */ public abstract void executeService(URI serviceUri, URI operationUri, IExecutionContext executionContext, IDataset request, IDataset response) throws AnzoException; /** * The registry is reset * * @param registry * registry * @throws AnzoException */ public abstract void registryReset(RegistryDataset registry) throws AnzoException; /** * Load service from registry * * @param serviceRegistry * registry containing service definition * @throws AnzoException */ public void loadServices(RegistryDataset serviceRegistry) throws AnzoException { try { if (dataset != null) { dataset.unregisterListener(listener); } this.servicesInfo = new HashMap<URI, ServiceInfo>(); this.serviceRegistry = serviceRegistry; URI serviceTypeUri = getServiceTypeUri(); Collection<Statement> stmts = serviceRegistry.find(null, RDF.TYPE, serviceTypeUri); for (Statement stmt : stmts) { URI serviceUri = (URI) stmt.getSubject(); SemanticService service = SemanticServiceFactory.getSemanticService(serviceUri, serviceRegistry); if (service.isRDFType(SemanticService.TYPE)) { loadService(service); } else { log.error(LogUtils.LIFECYCLE_MARKER, "There is a problem, service " + serviceUri.toString() + " is not of correct type"); } } dataset = AnzoFactory.createDataset(serviceRegistry.getURI(), serviceRegistry); dataset.registerListener(listener); } catch (Exception e) { throw new AnzoException(ExceptionConstants.EXECUTION.SERVICE_INITIALIZATION_ERROR, e); } } /** * Stop the services * * @param bundleStopping * @throws AnzoException */ public void stopServices(boolean bundleStopping) throws AnzoException { Set<URI> servicesToStop = new HashSet<URI>(); for (URI uri : servicesInfo.keySet()) { servicesToStop.add(uri); } for (URI uri : servicesToStop) { stopService(uri, bundleStopping); } servicesInfo.clear(); } /** * * @param uri * @param bundleStopping * @throws AnzoException */ public void stopService(URI uri, boolean bundleStopping) throws AnzoException { ServiceInfo serviceInfo = servicesInfo.get(uri); if (serviceInfo == null) { // this means the service isn't owned by this executor return; } RestrictedAnzoClient anzoClient = null; try { if (serviceInfo.anzoClient != null) { anzoClient = serviceInfo.anzoClient; } else { anzoClient = getServiceClient(false, serviceInfo.username, uri.toString()); } stopService(uri, anzoClient); servicesInfo.remove(uri); } finally { // we'll be closing either the client associated with a long running service, // or a client we just instantiated for the stop() call. if (anzoClient != null) { anzoClientPool.returnAnzoClient(anzoClient, bundleStopping); } } } /** * Set the anzo client pool * * @param anzoClientPool */ public void setAnzoClientPool(AnzoClientPool anzoClientPool) { this.anzoClientPool = anzoClientPool; } public void setHostExecutionService(SemanticServiceExecutionService executionService) { hostExecutionService = executionService; // register any services that have been loaded thus far for (URI uri : servicesInfo.keySet()) { hostExecutionService.registerService(uri, getServiceTypeUri()); } } protected IDataset getServiceRegistry() { return serviceRegistry; } protected boolean serviceLoaded(URI serviceUri) { return servicesInfo.containsKey(serviceUri); } protected void loadService(SemanticService service) throws AnzoException { if (serviceLoaded((URI) service.resource())) { return; } boolean closeClient = true; RestrictedAnzoClient anzoClient = null; try { ServiceInfo serviceInfo = new ServiceInfo(); String username = service.getServiceUser(); if (username != null) { serviceInfo.username = username; } boolean longRunning = false; if (service.getStateStyle().resource().equals(StateStyleEnum.LongRunningStyle)) { longRunning = true; } anzoClient = getServiceClient(longRunning, serviceInfo.username, service.uri()); //What are we doing here? anzoClient.begin(); anzoClient.commit(); if (serviceInfo.username == null) { serviceInfo.username = anzoClient.getServiceUser(); } boolean serviceReady = initializeService(service, anzoClient); if (serviceReady) { // if the service isn't ready, then it will have to call us back // later to load itself. URI serviceUri = (URI) service.resource(); servicesInfo.put(serviceUri, serviceInfo); for (SemanticOperation operation : service.getOperation()) { URI opuri = (URI) operation.resource(); verifyOperation(serviceUri, opuri); serviceInfo.operations.add(opuri); } // If necessary, instantiate an AnzoClient that the service will use to perform its function. if (longRunning) { serviceInfo.anzoClient = anzoClient; closeClient = false; } serviceInfo.stateStyle = (URI) service.getStateStyle().resource(); if (hostExecutionService != null) { hostExecutionService.registerService(serviceUri, getServiceTypeUri()); } } } catch (AnzoException e) { throw new AnzoException(ExceptionConstants.EXECUTION.SERVICE_INITIALIZATION_ERROR, e); } finally { if (closeClient && anzoClient != null) { anzoClientPool.returnAnzoClient(anzoClient, true); } } } protected RestrictedAnzoClient getServiceClient(boolean longRunning, String user, String userDescription) throws AnzoException { RestrictedAnzoClient anzoClient = anzoClientPool.getAnzoClient(longRunning, userDescription); if (user != null) { anzoClient.setServiceUser(user); } return anzoClient; } public void executeService(IOperationContext context, URI serviceUri, URI operationUri, boolean requestDefinedService, IDataset request, IDataset response) throws AnzoException { ServiceInfo serviceInfo = servicesInfo.get(serviceUri); if (serviceInfo == null) { if (!requestDefinedService) { throw new AnzoException(ExceptionConstants.EXECUTION.UNKNOWN_SERVICE_ERROR, serviceUri.toString()); } else { serviceInfo = new ServiceInfo(); serviceInfo.stateStyle = StateStyleEnum.ConnectionStyle; } } RestrictedAnzoClient anzoClient = getServiceClient(false, serviceInfo.username, serviceUri.toString() + ":" + operationUri.toString()); try { if (anzoClient.namedGraphExists(serviceUri)) { anzoClient.setServiceUser(context.getOperationPrincipal().getName()); boolean canExecService = anzoClient.canReadNamedGraph(serviceUri); if (!canExecService) { //TODO: Should this throw an error saying no permission throw new AnzoException(ExceptionConstants.EXECUTION.UNKNOWN_SERVICE_ERROR, serviceUri.toString()); } anzoClient.setServiceUser(serviceInfo.username); if (anzoClient.namedGraphExists(operationUri)) { anzoClient.setServiceUser(context.getOperationPrincipal().getName()); boolean canExecOp = anzoClient.canReadNamedGraph(operationUri); if (!canExecOp) { //TODO: Should this throw an error saying no permission throw new AnzoException(ExceptionConstants.EXECUTION.UNKNOWN_OPERATION_ERROR, serviceUri.toString(), operationUri.toString()); } } } } finally { anzoClientPool.returnAnzoClient(anzoClient, true); } RestrictedAnzoClient execClient = null; if (serviceInfo.stateStyle.equals(StateStyleEnum.LongRunningStyle)) { execClient = serviceInfo.anzoClient; } else if (serviceInfo.stateStyle.equals(StateStyleEnum.ConnectionStyle)) { try { execClient = anzoClientPool.getAnzoClient(false, serviceUri.toString() + ":" + operationUri.toString()); execClient.setServiceUser(serviceInfo.username); } catch (Exception e) { throw new AnzoException(ExceptionConstants.EXECUTION.EXECUTION_ERROR, e); } } ExecutionContext ec = new ExecutionContext(serviceInfo, context, serviceUri, operationUri, execClient); try { executeService(serviceUri, operationUri, ec, request, response); } finally { if (serviceInfo.stateStyle.equals(StateStyleEnum.ConnectionStyle)) { try { anzoClientPool.returnAnzoClient(execClient, true); } catch (Exception e) { throw new AnzoException(ExceptionConstants.EXECUTION.EXECUTION_ERROR, e); } } } } static class ServiceInfo { RestrictedAnzoClient anzoClient; Set<URI> operations = new HashSet<URI>(); String username; URI stateStyle; } /** * * @author bszekely * */ static class ExecutionContext implements IExecutionContext { ServiceInfo serviceInfo = null; IOperationContext operationContext = null; RestrictedAnzoClient anzoClient = null; URI serviceUri = null; URI operationUri = null; ExecutionContext(ServiceInfo serviceInfo, IOperationContext operationContext, URI serviceUri, URI operationUri, RestrictedAnzoClient anzoClient) { this.serviceInfo = serviceInfo; this.operationContext = operationContext; this.operationUri = operationUri; this.serviceUri = serviceUri; this.anzoClient = anzoClient; } public void executeAsRequestUser() { try { if (anzoClient != null) { anzoClient.setServiceUser(operationContext.getOperationPrincipal().getName()); } } catch (AnzoException e) { throw new AnzoRuntimeException(e); } } public void executeAsServiceUser() { try { if (anzoClient != null) { anzoClient.setServiceUser(serviceInfo.username); } } catch (AnzoException e) { throw new AnzoRuntimeException(e); } } public AnzoClient getAnzoClient() { return anzoClient; } public URI getOperationURI() { return operationUri; } public AnzoPrincipal getRequestUser() { return operationContext.getOperationPrincipal(); } public URI getServiceURI() { return serviceUri; } public IOperationContext getOperationContext() { return operationContext; } } class DsListener implements DatasetListener { public void namedGraphAdded(org.openanzo.ontologies.openanzo.Dataset source, NamedGraph newValue) { log.debug("!!!! Named Graph Added: " + this + " " + newValue.resource()); //System.err.println("!!!! Named Graph Added: " + BaseServiceExecutor.this + " " + newValue.resource()); URI newServiceUri = (URI) newValue.resource(); SemanticService service = SemanticServiceFactory.getSemanticService(newServiceUri, BaseServiceExecutor.this.serviceRegistry); try { if (service == null || !service.isRDFType(getServiceTypeUri())) { return; } loadService(service); } catch (Exception e) { log.error(LogUtils.LIFECYCLE_MARKER, "Error loading service:" + newServiceUri.toString(), e); } } public void namedGraphRemoved(org.openanzo.ontologies.openanzo.Dataset source, NamedGraph oldValue) { URI oldServiceUri = (URI) oldValue.resource(); try { stopService(oldServiceUri, true); } catch (Exception e) { log.error(LogUtils.LIFECYCLE_MARKER, "Error stopping service:" + oldServiceUri.toString(), e); } } public void defaultNamedGraphAdded(Dataset source, NamedGraph newValue) { namedGraphAdded(source, newValue); } public void defaultNamedGraphRemoved(Dataset source, NamedGraph oldValue) { namedGraphRemoved(source, oldValue); } public void defaultGraphAdded(org.openanzo.ontologies.openanzo.Dataset source, NamedGraph newValue) { } public void defaultGraphRemoved(org.openanzo.ontologies.openanzo.Dataset source, NamedGraph oldValue) { } public void includeMetadataGraphsChanged(Dataset source) { } } }