/*******************************************************************************
* 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 19, 2008
* Revision: $Id$
*
* Contributors:
* Cambridge Semantics Incorporated - initial API and implementation
*******************************************************************************/
package org.openanzo.osgi.registry.internal;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.StringTokenizer;
import org.openanzo.client.AnzoClient;
import org.openanzo.client.pool.AnzoClientPool;
import org.openanzo.client.pool.RestrictedAnzoClient;
import org.openanzo.datasource.IDatasourceListener;
import org.openanzo.exceptions.AnzoException;
import org.openanzo.exceptions.AnzoRuntimeException;
import org.openanzo.exceptions.LogUtils;
import org.openanzo.osgi.IStatusProvider;
import org.openanzo.osgi.OsgiConfigurationUtils;
import org.openanzo.osgi.ServiceLifecycleState;
import org.openanzo.osgi.registry.RegistryDataset;
import org.openanzo.rdf.Constants;
import org.openanzo.rdf.RDFFormat;
import org.openanzo.rdf.Statement;
import org.openanzo.rdf.URI;
import org.openanzo.rdf.Constants.OSGI;
import org.openanzo.rdf.utils.ReadWriteUtils;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.framework.ServiceRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com</a>)
*
*/
class RegistryManifestLoader implements BundleListener, IDatasourceListener, IStatusProvider {
private static final Logger log = LoggerFactory.getLogger(RegistryManifestLoader.class);
private static final String REGISTRY_INITIALIZATION_RESOURCE = "Registry-Init-Resources";
private static final String TEMPLATE_FILE = "template.trig";
private static final String FILE_EXTENSION = ".trig";
private static final URI loaded = Constants.valueFactory.createURI("http://openanzo.org/internal/registryManifest#isLoaded");
private static final URI fileLoaded = Constants.valueFactory.createURI("http://openanzo.org/internal/registryManifest#fileLoaded");
private static final URI rml = org.openanzo.rdf.Constants.valueFactory.createURI("http://openanzo.org/internal/registryManifest");
private final BundleContext context;
private final AnzoClientPool clientPool;
private final HashSet<Long> bundles = new HashSet<Long>();
private ServiceLifecycleState state = ServiceLifecycleState.CREATED;
private final ServiceRegistration reg;
private String currentlyLoading = null;
private RegistryDataset registry = null;
private final ArrayList<String> loadedFiles = new ArrayList<String>();
protected RegistryManifestLoader(BundleContext context, AnzoClientPool clientPool, RegistryProvider registryProvider) {
this.context = context;
this.clientPool = clientPool;
try {
this.registry = registryProvider.openRegistry(OSGI.OSGI, "RegistryManifestLoader-Registry");
this.registry.addNamedGraph(org.openanzo.rdf.Constants.OSGI.OSGI);
} catch (AnzoException ae) {
log.error(LogUtils.LIFECYCLE_MARKER, "Error loading osgi registry dataset", ae);
throw new AnzoRuntimeException(ae);
}
reg = context.registerService(IStatusProvider.class.getName(), this, null);
}
public String getCurrentStatus(boolean html) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
if (html) {
String statusString = null;
switch (state) {
case CREATED:
statusString = "<font color='#0000cc'>" + state.toString() + "</font>";
break;
case STARTED:
statusString = "<font color='#00cc00'>" + state.toString() + "</font>";
break;
case STARTING:
statusString = "<font color='#FFFF00'>" + state.toString() + "</font>";
break;
case STOPPED:
statusString = "<font color='#cc0000'>" + state.toString() + "</font>";
break;
case STOPPING:
statusString = "<font color='#FF9900'>" + state.toString() + "</font>";
break;
}
pw.println("<div id='registryResourceProvider'>");
pw.println("<h2>org.openanzo.osgi.registry.RegistryResourceDataLoader" + " - " + statusString + "</h2><div id='subRegistryResourceProvider'> Loads registry init resource data into server");
pw.println("<br/>Bundle: [" + context.getBundle().getBundleId() + "] " + context.getBundle().getLocation());
if (currentlyLoading != null) {
pw.println("<br/>Currently Loading:<br/>");
pw.println(currentlyLoading);
}
if (loadedFiles.size() > 0) {
pw.println("<br/>Loaded Files:<br/>");
for (String file : loadedFiles) {
pw.println("<li>" + file + "</li>");
}
}
pw.println("</div></div><hr width='100%' size='1' />");
} else {
pw.println("**********************************************************");
pw.println("RegistryResourceDataLoader:");
pw.println(getState());
if (currentlyLoading != null) {
pw.println("Currently Loading:\n");
pw.println(currentlyLoading);
}
if (loadedFiles.size() > 0) {
pw.println("Loaded Files:\n");
for (String file : loadedFiles) {
pw.println(file + "\n");
}
}
}
pw.flush();
sw.flush();
return sw.toString();
}
public ServiceLifecycleState getState() {
return state;
}
protected void open() {
state = ServiceLifecycleState.STARTING;
clientPool.registerDatasourceListener(this);
processBundles();
context.addBundleListener(this);
state = ServiceLifecycleState.STARTED;
}
public void resetStarting() throws AnzoException {
}
public void reset() throws AnzoException {
bundles.clear();
}
public void postReset() throws AnzoException {
this.registry.addNamedGraph(org.openanzo.rdf.Constants.OSGI.OSGI);
processBundles();
}
public void resetFinished() throws AnzoException {
}
protected void close(boolean bundleStopping) {
clientPool.unregisterDatasourceListener(this);
context.removeBundleListener(this);
state = ServiceLifecycleState.STOPPED;
if (bundleStopping && reg != null) {
reg.unregister();
}
}
public void bundleChanged(BundleEvent event) {
Bundle bundle = event.getBundle();
if (Bundle.ACTIVE == bundle.getState()) {
try {
registry.beginUpdatingRegistry();
addingBundle(bundle);
registry.commitRegistry();
} catch (AnzoException ae) {
log.error(LogUtils.LIFECYCLE_MARKER, "Error updating bundle's registry data", ae);
}
}
}
private void processBundles() {
try {
registry.beginUpdatingRegistry();
Bundle[] bundles = context.getBundles();
for (Bundle bundle : bundles) {
if (Bundle.ACTIVE == bundle.getState()) {
addingBundle(bundle);
}
}
registry.commitRegistry();
} catch (AnzoException ae) {
log.error(LogUtils.LIFECYCLE_MARKER, "Error processing bundles' registry data", ae);
}
}
@SuppressWarnings("unchecked")
private void addingBundle(Bundle bundle) {
if (!bundles.contains(bundle.getBundleId())) {
bundles.add(bundle.getBundleId());
try {
String symbolicName = bundle.getSymbolicName();
URI uri = Constants.valueFactory.createURI(OSGI.BUNDLE + symbolicName);
if (registry.contains(rml, loaded, uri, org.openanzo.rdf.Constants.OSGI.OSGI)) {
return;
}
Dictionary<String, String> headers = bundle.getHeaders();
String initPath = headers.get(REGISTRY_INITIALIZATION_RESOURCE);
if (initPath != null) {
log.info(LogUtils.LIFECYCLE_MARKER, "Loading registry init files: " + bundle.getSymbolicName() + " " + initPath);
RestrictedAnzoClient client = this.clientPool.getAnzoClient(false, "RegistryManifestLoader-BundleLoader");
try {
StringTokenizer st = new StringTokenizer(initPath, ",");
Collection<Statement> stmts = new HashSet<Statement>();
Collection<Statement> templateStatements = new HashSet<Statement>();
while (st.hasMoreTokens()) {
String token = st.nextToken();
token = OsgiConfigurationUtils.preprocessString(token, bundle.getBundleContext());
if (token.endsWith(".trig")) {
processFile(bundle, token, stmts, templateStatements);
} else if (token.endsWith("/")) {
processDirectory(bundle, token, false, client);
} else if (token.endsWith("/*")) {
processDirectory(bundle, token, true, client);
}
}
importStatements(client, stmts, templateStatements);
} finally {
this.clientPool.returnAnzoClient(client);
currentlyLoading = null;
}
}
registry.add(rml, loaded, uri, org.openanzo.rdf.Constants.OSGI.OSGI);
} catch (AnzoException ae) {
log.error(LogUtils.LIFECYCLE_MARKER, "Error loading bundle's registry data:" + bundle.getSymbolicName(), ae);
}
}
}
private void importStatements(AnzoClient client, Collection<Statement> statements, Collection<Statement> templateStatements) throws AnzoException {
if (templateStatements.size() == 0) {
client.importStatements(statements, AnzoClient.REVISIONED_NAMED_GRAPH);
} else {
client.importStatements(statements, templateStatements);
}
}
@SuppressWarnings("unchecked")
private void processDirectory(Bundle bundle, String directoryName, boolean subDirs, AnzoClient client) throws AnzoException {
Enumeration entries = bundle.getEntryPaths(directoryName);
if (entries != null) {
Collection<Statement> stmts = new HashSet<Statement>();
Collection<Statement> templateStatements = new HashSet<Statement>();
while (entries.hasMoreElements()) {
String entry = (String) entries.nextElement();
if (entry.endsWith(FILE_EXTENSION)) {
processFile(bundle, entry, stmts, templateStatements);
} else if (subDirs && entry.endsWith("/")) {
processDirectory(bundle, entry, subDirs, client);
}
}
importStatements(client, stmts, templateStatements);
}
}
private void processFile(Bundle bundle, String file, Collection<Statement> stmts, Collection<Statement> templateStatements) {
try {
currentlyLoading = file;
URL initResource = bundle.getEntry(file);
if (initResource != null) {
if (file.endsWith(TEMPLATE_FILE)) {
templateStatements.addAll(ReadWriteUtils.loadStatements(new InputStreamReader(initResource.openStream(), Constants.byteEncoding), RDFFormat.forFileName(file), ""));
} else {
stmts.addAll(ReadWriteUtils.loadStatements(new InputStreamReader(initResource.openStream(), Constants.byteEncoding), RDFFormat.forFileName(file), ""));
}
registry.add(rml, fileLoaded, Constants.valueFactory.createURI(initResource.toURI().toString()), org.openanzo.rdf.Constants.OSGI.OSGI);
loadedFiles.add(file);
}
} catch (URISyntaxException ae) {
log.error(LogUtils.LIFECYCLE_MARKER, "IOException while loading registry file:" + file, ae);
} catch (IOException ae) {
log.error(LogUtils.LIFECYCLE_MARKER, "IOException while loading registry file:" + file, ae);
} catch (AnzoException ae) {
log.error(LogUtils.LIFECYCLE_MARKER, "AnzoException loading registry file:" + file, ae);
} finally {
currentlyLoading = null;
}
}
}