package net.enilink.komma.em; import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.util.Map; import java.util.WeakHashMap; import net.enilink.composition.ClassDefiner; import net.enilink.composition.ClassResolver; import net.enilink.composition.CompositionModule; import net.enilink.composition.DefaultObjectFactory; import net.enilink.composition.ObjectFactory; import net.enilink.composition.mappers.ComposedRoleMapper; import net.enilink.composition.mappers.RoleMapper; import net.enilink.composition.mappers.TypeFactory; import net.enilink.composition.properties.PropertyMapper; import net.enilink.composition.properties.behaviours.PropertyMapperProcessor; import net.enilink.composition.properties.sparql.SparqlBehaviourMethodProcessor; import com.google.inject.AbstractModule; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Provides; import com.google.inject.Singleton; import com.google.inject.TypeLiteral; import net.enilink.vocab.rdfs.RDFS; import net.enilink.komma.em.internal.ByteArrayConverter; import net.enilink.komma.em.internal.behaviours.EntitySupport; import net.enilink.komma.literals.IConverter; import net.enilink.komma.literals.LiteralConverter; import net.enilink.komma.core.ILiteralFactory; import net.enilink.komma.core.KommaModule; import net.enilink.komma.core.LiteralFactory; import net.enilink.komma.core.URI; import net.enilink.komma.core.URIs; public class ManagerCompositionModule extends AbstractModule { private static Map<ClassLoader, WeakReference<ClassLoader>> classLoaders = new WeakHashMap<ClassLoader, WeakReference<ClassLoader>>(); private static Map<ClassLoader, WeakReference<ClassDefiner>> definers = new WeakHashMap<ClassLoader, WeakReference<ClassDefiner>>(); private KommaModule module; public ManagerCompositionModule(KommaModule module) { this.module = module; } @Override protected void configure() { install(new CompositionModule<URI>() { @Override protected void initBindings() { super.initBindings(); getBehaviourClassProcessorBinder().addBinding() .to(PropertyMapperProcessor.class).in(Singleton.class); getBehaviourMethodProcessorBinder().addBinding() .to(SparqlBehaviourMethodProcessor.class) .in(Singleton.class); } @Override protected RoleMapper<URI> createRoleMapper(TypeFactory<URI> typeFactory) { return new ComposedRoleMapper<URI>( typeFactory); } @Override protected void initRoleMapper(RoleMapper<URI> roleMapper, TypeFactory<URI> typeFactory) { super.initRoleMapper(roleMapper, typeFactory); for (KommaModule.Association e : module.getAnnotations()) { roleMapper.addAnnotation(e.getJavaClass(), typeFactory.createType(e.getRdfType())); } for (KommaModule.Association e : module.getConcepts()) { if (e.getRdfType() == null) { roleMapper.addConcept(e.getJavaClass()); } else { roleMapper.addConcept(e.getJavaClass(), typeFactory.createType(e.getRdfType())); } } for (KommaModule.Association e : module.getBehaviours()) { if (e.getRdfType() == null) { roleMapper.addBehaviour(e.getJavaClass()); } else { roleMapper.addBehaviour(e.getJavaClass(), typeFactory.createType(e.getRdfType())); } } roleMapper .addBehaviour(EntitySupport.class, RDFS.TYPE_RESOURCE); } @Override protected void bindClassDefiner() { // do not bind the class definer here } }); bind(new Key<ObjectFactory<URI>>() { }).to(new TypeLiteral<DefaultObjectFactory<URI>>() { }); bind(new TypeLiteral<ClassResolver<URI>>() { }).in(Singleton.class); } @Provides @Singleton protected TypeFactory<URI> provideTypeFactory() { return new TypeFactory<URI>() { @Override public URI createType(String type) { return URIs.createURI(type); } @Override public String toString(URI type) { return type.toString(); } }; } @Provides @Singleton protected PropertyMapper providePropertyMapper(ClassLoader cl) { return new PropertyMapper(cl, true); } @Provides @Singleton protected ClassLoader provideClassLoader() { return module.getClassLoader(); } @Provides @Singleton protected LiteralConverter provideLiteralConverter(Injector injector) { LiteralConverter literalConverter = new LiteralConverter(); injector.injectMembers(literalConverter); for (KommaModule.Association e : module.getDatatypes()) { literalConverter.addDatatype(e.getJavaClass(), URIs.createURI(e.getRdfType())); } // record additional converter for Base64 encoded byte arrays IConverter<?> converter = new ByteArrayConverter(); literalConverter.registerConverter(converter.getJavaClassName(), converter); literalConverter.recordType(byte[].class, converter.getDatatype()); return literalConverter; } @Provides @Singleton protected ILiteralFactory provideLiteralFactory() { return new LiteralFactory(); } @Provides @Singleton protected ClassDefiner provideSharedClassDefiner(ClassLoader cl) { ClassDefiner definer = null; synchronized (definers) { WeakReference<ClassDefiner> ref = definers.get(cl); if (ref != null) { definer = ref.get(); } if (definer == null) { ClassLoader internedLoader = null; synchronized (classLoaders) { Reference<ClassLoader> loaderRef = classLoaders.get(cl); if (loaderRef != null) { internedLoader = loaderRef.get(); } if (internedLoader == null) { classLoaders.put(internedLoader, new WeakReference<ClassLoader>(internedLoader)); internedLoader = cl; } } definer = new ClassDefiner(internedLoader); definers.put(internedLoader, new WeakReference<ClassDefiner>( definer)); } } return definer; } }