/*
* Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* 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:
* Nuxeo - initial API and implementation
*
* $Id$
*/
package org.eclipse.ecr.core.schema;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.ecr.core.schema.types.Schema;
import org.eclipse.ecr.core.schema.types.TypeException;
import org.eclipse.ecr.runtime.api.Framework;
import org.eclipse.ecr.runtime.api.ServiceGroup;
import org.eclipse.ecr.runtime.api.ServiceManager;
import org.eclipse.ecr.runtime.model.ComponentContext;
import org.eclipse.ecr.runtime.model.ComponentName;
import org.eclipse.ecr.runtime.model.DefaultComponent;
import org.eclipse.ecr.runtime.model.Extension;
import org.eclipse.ecr.runtime.model.RuntimeContext;
import org.nuxeo.common.utils.FileUtils;
import org.xml.sax.SAXException;
/**
* @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
*
*/
public class TypeService extends DefaultComponent {
public static final ComponentName NAME = new ComponentName(
"org.eclipse.ecr.core.schema.TypeService");
private static final Log log = LogFactory.getLog(TypeService.class);
private SchemaManagerImpl typeManager;
private XSDLoader schemaLoader;
private ComponentContext context;
private TypeConfiguration configuration;
private static SchemaManager schemaManagerInstance;
//TODO: use a static Services class in runtime to use as only entry point to service lookups
// and register singleton services there
// or use a ServiceRef<T> for each singleton service we need to get quickly
public static SchemaManager getSchemaManager() {
return schemaManagerInstance;
}
public SchemaManager getTypeManager() {
return typeManager;
}
public XSDLoader getSchemaLoader() {
return schemaLoader;
}
@Override
public void activate(ComponentContext context) {
this.context = context;
try {
typeManager = new SchemaManagerImpl();
schemaLoader = new XSDLoader(typeManager);
schemaManagerInstance = typeManager;
} catch (Exception e) {
log.error(e, e);
}
}
@Override
public void deactivate(ComponentContext context) {
typeManager.clear();
typeManager = null;
schemaManagerInstance = null;
}
@Override
public void registerExtension(Extension extension) {
String xp = extension.getExtensionPoint();
if ("doctype".equals(xp)) {
Object[] contribs = extension.getContributions();
for (Object contrib : contribs) {
if (contrib instanceof DocumentTypeDescriptor) {
typeManager.registerDocumentType((DocumentTypeDescriptor) contrib);
} else if (contrib instanceof FacetDescriptor) {
typeManager.registerFacet((FacetDescriptor) contrib);
}
}
} else if ("schema".equals(xp)) {
Object[] contribs = extension.getContributions();
for (Object contrib : contribs) {
try {
// use the context of the bundle contributing the extension
// to load schemas
SchemaBindingDescriptor sbd = (SchemaBindingDescriptor) contrib;
sbd.context = extension.getContext();
registerSchema(sbd);
} catch (Exception e) {
log.error(e, e);
}
}
} else if ("configuration".equals(xp)) {
Object[] contribs = extension.getContributions();
if (contribs.length > 0) {
setConfiguration((TypeConfiguration) contribs[0]);
}
} else if ("helper".equals(xp)) {
Object[] contribs = extension.getContributions();
if (contribs.length > 0) {
TypeHelperDescriptor thd = (TypeHelperDescriptor) contribs[0];
try {
typeManager.registerHelper(thd.schema, thd.type, thd.helperClass.newInstance());
} catch (Exception e) {
log.error("Failed to instantiate type helper: "
+ thd.helperClass, e);
}
}
} else if ("provider".equals(xp)) {
Object[] contribs = extension.getContributions();
if (contribs.length > 0) {
TypeProviderDescriptor tpd = (TypeProviderDescriptor) contribs[0];
ServiceManager sm = Framework.getLocalService(
ServiceManager.class);
// the JNDI lookup should be done in the ear class loader context
// otherwise we can have class loading problems (e.g. TypeProvider not found)
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(TypeService.class.getClassLoader());
TypeProvider provider = null;
if (tpd.uri != null) {
provider = (TypeProvider) sm.getService(tpd.uri);
} else if (tpd.group != null) {
ServiceGroup group = sm.getGroup(tpd.group);
if (group != null) {
provider = group.getService(TypeProvider.class);
} else {
log.warn("Invalid type provider extension contribued by: "
+ extension.getComponent().getName()
+ ". no such service group: " + tpd.group);
}
} else {
log.warn("Invalid type provider extension contribued by: "
+ extension.getComponent().getName());
}
if (provider != null) {
if (provider != typeManager) {
log.info("Importing types from external provider");
typeManager.importTypes(provider);
}
} else {
log.warn("Could not instatiate or locate the type provider contributed by: "
+ extension.getComponent().getName());
}
} catch (Exception e) {
log.error("Failed to register type provider", e);
} finally {
Thread.currentThread().setContextClassLoader(cl); //restore initial class loader
}
}
}
}
@Override
public void unregisterExtension(Extension extension) {
String xp = extension.getExtensionPoint();
if ("doctype".equals(xp)) {
Object[] contribs = extension.getContributions();
for (Object contrib : contribs) {
if (contrib instanceof DocumentTypeDescriptor) {
typeManager.unregisterDocumentType(((DocumentTypeDescriptor) contrib).name);
} else if (contrib instanceof FacetDescriptor) {
typeManager.unregisterFacet(((FacetDescriptor) contrib).name);
}
}
} else if ("schema".equals(xp)) {
Object[] contribs = extension.getContributions();
for (Object contrib : contribs) {
typeManager.unregisterSchema(((SchemaBindingDescriptor) contrib).name);
}
} else if ("helper".equals(xp)) {
Object[] contribs = extension.getContributions();
if (contribs.length > 0) {
TypeHelperDescriptor thd = (TypeHelperDescriptor) contribs[0];
typeManager.unregisterHelper(thd.schema, thd.type);
}
} else if ("provider".equals(xp)) {
// ignore provider removal
}
}
protected void registerSchema(SchemaBindingDescriptor sd)
throws IOException, TypeException, SAXException {
if (sd.src != null && sd.src.length() > 0) {
RuntimeContext schemaContext = sd.context == null ? context.getRuntimeContext()
: sd.context;
URL url = schemaContext.getLocalResource(sd.src);
if (url == null) { // try asking the class loader
url = schemaContext.getResource(sd.src);
}
if (url != null) {
InputStream in = url.openStream();
try {
File file = new File(typeManager.getSchemaDirectory(),
sd.name + ".xsd");
FileUtils.copyToFile(in, file); // may overwrite
Schema oldschema = typeManager.getSchema(sd.name);
// loadSchema also (re)registers it with the typeManager
schemaLoader.loadSchema(sd.name, sd.prefix, file, sd.override);
if (oldschema == null) {
log.info("Registered schema: " + sd.name + " from " + url.toString());
} else {
log.info("Reregistered schema: " + sd.name);
}
} finally {
in.close();
}
} else {
log.error("XSD Schema not found: " + sd.src);
}
} else {
log.error("INLINE Schemas ARE NOT YET IMPLEMENTED!");
}
}
public void setConfiguration(TypeConfiguration configuration) {
this.configuration = configuration;
if (typeManager != null) {
typeManager.setPrefetchInfo(new PrefetchInfo(configuration.prefetchInfo));
}
}
public TypeConfiguration getConfiguration() {
return configuration;
}
@Override
@SuppressWarnings("unchecked")
public <T> T getAdapter(Class<T> adapter) {
if (SchemaManager.class.isAssignableFrom(adapter)) {
return (T) typeManager;
} else if (TypeProvider.class.isAssignableFrom(adapter)) {
return (T) typeManager;
}
return null;
}
}