/******************************************************************************* * Copyright (c) 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 * * File: $Source$ * Created by: Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com </a>) * Created on: Aug 15, 2008 * Revision: $Id$ * * Contributors: * Cambridge Semantics Incorporated - initial API and implementation *******************************************************************************/ package org.openanzo.datasource.manager.internal; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Arrays; import java.util.Collection; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; import org.eclipse.osgi.framework.console.CommandProvider; import org.openanzo.datasource.IDatasource; import org.openanzo.datasource.IDatasourceListener; import org.openanzo.datasource.manager.IDatasourceManager; import org.openanzo.exceptions.AnzoException; import org.openanzo.exceptions.LogUtils; import org.openanzo.execution.java.IBundledSemanticService; import org.openanzo.ontologies.openanzo.AnzoFactory; import org.openanzo.ontologies.openanzo.Dataset; import org.openanzo.ontologies.system.Datasource; import org.openanzo.ontologies.system.SystemFactory; import org.openanzo.osgi.ConfiguredServiceActivator; import org.openanzo.osgi.GenericObjectClassDef; import org.openanzo.osgi.IServiceTrackerListener; import org.openanzo.osgi.OsgiServiceTracker; import org.openanzo.osgi.attributes.ServicesAttributes; import org.openanzo.osgi.registry.IRegistryProvider; import org.openanzo.osgi.registry.RegistryDataset; import org.openanzo.rdf.INamedGraph; import org.openanzo.rdf.URI; import org.openanzo.rdf.utils.Collections; import org.openanzo.services.IStatisticsProvider; import org.openanzo.services.ServicesDictionary; import org.osgi.framework.BundleContext; import org.osgi.service.metatype.AttributeDefinition; import org.osgi.service.metatype.ObjectClassDefinition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Activator for the DatasourceManager * * @author Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com</a>) * */ public class DatasourceManagerActivator extends ConfiguredServiceActivator implements IDatasourceManager { private static final Logger log = LoggerFactory.getLogger(DatasourceManagerActivator.class); private OsgiServiceTracker<IDatasource> datasourceTracker = null; private final ConcurrentHashMap<URI, IDatasource> datasources = new ConcurrentHashMap<URI, IDatasource>(); /** Service PID for the DatasourceManager */ public static final String SERVICE_PID = "org.openanzo.datasource.DatasourceManager"; private RegistryDataset registry = null; private org.openanzo.ontologies.openanzo.Dataset registryDataset = null; private IDatasourceListener resetListener = null; private InitResourceListener initResourceListener = null; GenericObjectClassDef classDef; DatasourceService service; public ObjectClassDefinition getObjectClassDefinition(String id, String locale) { return classDef != null ? classDef : (classDef = new GenericObjectClassDef(SERVICE_PID, getBundleName(), getBundleDescription(), new AttributeDefinition[] { ServicesAttributes.Enabled }, null)); } private ReentrantLock resetLock = new ReentrantLock(); private boolean resetting = false; @Override public String getServicePid() { return SERVICE_PID; } @Override public String[] getDependencies() { return new String[] { IRegistryProvider.class.getName() }; } @Override public void start(BundleContext bundleContext) throws Exception { super.start(bundleContext); context.registerService(new String[] { CommandProvider.class.getName() }, new DatasourceManagerCommand(this), null); } @Override public void start() { try { resetListener = new RegistryResetListener(); registry = getDependency(IRegistryProvider.class).openRegistry(DATASOURCE_REGISTRY_URI, "DatasourceManagerActivator"); registry.registerDatasourceListener(resetListener); } catch (AnzoException ae) { log.error(LogUtils.SERVER_INTERNAL_MARKER, "Error starting datasource manager", ae); } setupRegistry(); Properties props = new Properties(); props.put(org.osgi.framework.Constants.SERVICE_PID, SERVICE_PID); props.put(org.osgi.framework.Constants.SERVICE_DESCRIPTION, "Datasource Manager/Registry"); context.registerService(IDatasourceManager.class.getName(), this, props); datasourceTracker = new OsgiServiceTracker<IDatasource>(new IServiceTrackerListener<IDatasource>() { public void unregisterService(IDatasource datasource) { unregisterDatasource(datasource); } public void registerService(IDatasource datasource) { if (!resetting) { registerDatasource(datasource); } else { datasources.put(datasource.getInstanceURI(), datasource); } } public Class<IDatasource> getComponentType() { return IDatasource.class; } }, context); datasourceTracker.open(); initResourceListener = new InitResourceListener(context, getDependency(IRegistryProvider.class)); log.debug(LogUtils.DATASOURCE_MARKER, "Registering datasource service"); service = new DatasourceService(this, ServicesDictionary.getUser(configProperties, null)); context.registerService(new String[] { IBundledSemanticService.class.getName(), IStatisticsProvider.class.getName() }, service, null); } private void setupRegistry() { resetLock.lock(); try { registry.beginUpdatingRegistry(); registryDataset = AnzoFactory.createDataset(DATASOURCE_REGISTRY_URI, registry); for (IDatasource datasource : datasources.values()) { log.debug(LogUtils.DATASOURCE_MARKER, "setting up registry for : " + datasource.getInstanceURI() + " " + datasource.isSelfDescribing()); if (datasource.isSelfDescribing()) { if (!registry.contains(DATASOURCE_REGISTRY_URI, Dataset.namedGraphProperty, datasource.getInstanceURI(), DATASOURCE_REGISTRY_URI)) { log.debug(LogUtils.DATASOURCE_MARKER, "Adding datasource to registry: " + datasource.getInstanceURI()); INamedGraph capabilities = datasource.getCapabilities(); Datasource datasourceComp = SystemFactory.createDatasource(datasource.getInstanceURI(), datasource.getInstanceURI(), registry); datasourceComp.setIsPrimary(datasource.isPrimary()); if (capabilities != null) { datasourceComp.graph().add(capabilities.getStatements()); } registryDataset.addNamedGraph(datasource.getInstanceURI()); } } } registry.commitRegistry(); } catch (AnzoException ae) { if (registry.inTransaction()) { registry.abortRegistry(); } log.error(LogUtils.DATASOURCE_MARKER, "Error setting up datasource manager registry", ae); } finally { resetLock.unlock(); } } @Override public void stop(boolean bundleStopping) { if (datasourceTracker != null) { datasourceTracker.close(); datasourceTracker = null; } if (initResourceListener != null) { initResourceListener.stop(bundleStopping); initResourceListener = null; } } public IDatasource getDatasource(URI datasourceURI) { IDatasource ds = datasources.get(datasourceURI); if (ds == null) { log.debug(LogUtils.DATASOURCE_MARKER, "Datasource is null for:" + datasourceURI + ":" + Arrays.toString(datasources.keySet().toArray())); } return ds; } public Collection<IDatasource> getDatasources() { return Collections.copyCollection(datasources.values()); } private void registerDatasource(IDatasource datasource) { resetLock.lock(); try { log.debug(LogUtils.DATASOURCE_MARKER, "Registering datasource: " + datasource.getInstanceURI()); datasources.put(datasource.getInstanceURI(), datasource); if (datasource.isSelfDescribing()) { log.debug(LogUtils.DATASOURCE_MARKER, "Datasource: " + datasource.getInstanceURI() + ": is self describing"); if (!registry.contains(DATASOURCE_REGISTRY_URI, Dataset.namedGraphProperty, datasource.getInstanceURI(), DATASOURCE_REGISTRY_URI)) { try { log.debug(LogUtils.DATASOURCE_MARKER, "Adding datasource to registry (osgi event) : " + datasource.getInstanceURI()); registry.beginUpdatingRegistry(); INamedGraph capabilities = datasource.getCapabilities(); Datasource datasourceComp = SystemFactory.createDatasource(datasource.getInstanceURI(), datasource.getInstanceURI(), registry); datasourceComp.setIsPrimary(datasource.isPrimary()); if (capabilities != null) { datasourceComp.graph().add(capabilities.getStatements()); } registryDataset.addNamedGraph(datasource.getInstanceURI()); registry.commitRegistry(); } catch (AnzoException ae) { log.error(LogUtils.DATASOURCE_MARKER, "Error registring datasource with manager:" + datasource.getInstanceURI(), ae); if (registry.inTransaction()) { registry.abortRegistry(); } } } else { log.debug(LogUtils.DATASOURCE_MARKER, "Datasource already in registry:" + datasource.getInstanceURI()); } } } finally { resetLock.unlock(); } } @Override public String getExtraStatus(boolean html) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); if (html) { pw.println("<h4><font color='#00cc00'>Registered Datasources:</font></h4>"); for (URI ds : datasources.keySet()) { pw.println("<li>" + ds.toString() + "</li>"); } } else { pw.println("Registered Datasources:"); for (URI ds : datasources.keySet()) { pw.println(ds.toString()); } } pw.flush(); sw.flush(); return sw.toString(); } private void unregisterDatasource(IDatasource datasource) { resetLock.lock(); try { log.debug(LogUtils.DATASOURCE_MARKER, "Unregisterring datasource: " + datasource.getInstanceURI()); datasources.remove(datasource.getInstanceURI()); } finally { resetLock.unlock(); } } class RegistryResetListener implements IDatasourceListener { public void resetStarting() throws AnzoException { resetting = true; } public void reset() throws AnzoException { } public void postReset() throws AnzoException { } public void resetFinished() throws AnzoException { setupRegistry(); resetting = false; } } @Override public boolean registerFrameworkStoppingListener() { return true; } @Override protected void frameworkStopping() { stop(false); } }