blob: 30e091a886af3f2564e9c8a316cd1b73c75ec8a5 [file] [log] [blame]
package org.apache.aries.jpa.blueprint.impl;
import static org.osgi.service.jpa.EntityManagerFactoryBuilder.JPA_UNIT_NAME;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
import org.apache.aries.blueprint.ComponentDefinitionRegistry;
import org.apache.aries.blueprint.ComponentDefinitionRegistryProcessor;
import org.apache.aries.blueprint.Interceptor;
import org.apache.aries.blueprint.ParserContext;
import org.apache.aries.blueprint.PassThroughMetadata;
import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
import org.apache.aries.blueprint.mutable.MutableRefMetadata;
import org.apache.aries.blueprint.mutable.MutableReferenceMetadata;
import org.apache.aries.jpa.blueprint.supplier.impl.ServiceProxy;
import org.apache.aries.jpa.supplier.EmSupplier;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.service.blueprint.reflect.ComponentMetadata;
import org.osgi.service.blueprint.reflect.ReferenceMetadata;
import org.osgi.service.coordinator.Coordinator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JpaComponentProcessor implements ComponentDefinitionRegistryProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger(JpaComponentProcessor.class);
private AnnotationScanner annotationScanner;
private ParserContext pc;
public JpaComponentProcessor() {
annotationScanner = new AnnotationScanner();
}
public void setPc(ParserContext pc) {
this.pc = pc;
}
@Override
public void process(ComponentDefinitionRegistry cdr) {
PassThroughMetadata bundleMeta = (PassThroughMetadata)cdr.getComponentDefinition("blueprintBundle");
Bundle bundle = (Bundle)bundleMeta.getObject();
Set<String> components = new HashSet<>(cdr.getComponentDefinitionNames());
for (String component : components) {
ComponentMetadata compDef = cdr.getComponentDefinition(component);
if (compDef instanceof MutableBeanMetadata && !((MutableBeanMetadata)compDef).isProcessor()) {
handleComponent((MutableBeanMetadata)compDef, bundle, cdr);
}
}
System.out.println(cdr.getComponentDefinitionNames());
}
private void handleComponent(MutableBeanMetadata compDef, Bundle bundle, ComponentDefinitionRegistry cdr) {
if (compDef.getClassName() == null) {
LOGGER.warn("No classname for " + compDef.getId());
return;
}
String compName = compDef.getId();
Class<?> compClass;
try {
compClass = bundle.loadClass(compDef.getClassName());
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Bean class not found " + compDef.getClassName());
}
BundleContext context = bundle.getBundleContext();
compDef.setFieldInjection(true);
List<AccessibleObject> jpaAnnotatedMembers = annotationScanner.getJpaAnnotatedMembers(compClass);
for (AccessibleObject member : jpaAnnotatedMembers) {
member.setAccessible(true);
String propName = getName(member);
PersistenceContext pcAnn = member.getAnnotation(PersistenceContext.class);
if (pcAnn != null) {
LOGGER.info("Adding jpa interceptor for bean {}, prop {} with class {}", compName, propName, compClass);
Class<?> iface = getType(member);
if (iface != null) {
MutableRefMetadata emRef = getServiceRef(cdr, pcAnn.unitName(), iface);
compDef.addProperty(propName, emRef);
Interceptor interceptor = createInterceptor(context, pcAnn);
cdr.registerInterceptorWithComponent(compDef, interceptor);
}
}
PersistenceUnit puAnn = member.getAnnotation(PersistenceUnit.class);
if (puAnn != null) {
LOGGER.info("Adding emf proxy for bean {}, prop {} with class {}", compName, propName, compClass);
MutableRefMetadata emfRef = getServiceRef(cdr, puAnn.unitName(), EntityManagerFactory.class);
compDef.addProperty(propName, emfRef);
}
}
}
private MutableRefMetadata getServiceRef(ComponentDefinitionRegistry cdr, String unitName, Class<?> iface) {
ComponentMetadata serviceRef = cdr.getComponentDefinition(getId(unitName, iface));
if (serviceRef == null) {
serviceRef = createServiceRef(unitName, iface);
cdr.registerComponentDefinition(serviceRef);
} else {
LOGGER.info("Using already registered ref " + serviceRef.getId());
}
MutableRefMetadata ref = pc.createMetadata(MutableRefMetadata.class);
ref.setComponentId(serviceRef.getId());
return ref;
}
private Interceptor createInterceptor(BundleContext context, PersistenceContext pcAnn) {
String filter = getFilter(EmSupplier.class, pcAnn.unitName());
EmSupplier supplierProxy = ServiceProxy.create(context, EmSupplier.class, filter);
Coordinator coordinator = ServiceProxy.create(context, Coordinator.class);
Interceptor interceptor = new JpaInterceptor(supplierProxy, coordinator);
return interceptor;
}
private String getName(AccessibleObject member) {
if (member instanceof Field) {
return ((Field)member).getName();
} else if (member instanceof Method) {
Method method = (Method)member;
String name = method.getName();
if (!name.startsWith("set")) {
return null;
}
return name. substring(3, 4).toLowerCase() + name.substring(4);
}
return null;
}
private Class<?> getType(AccessibleObject member) {
if (member instanceof Field) {
return ((Field)member).getType();
} else if (member instanceof Method) {
Method method = (Method)member;
return method.getParameterTypes()[0];
}
return null;
}
@SuppressWarnings("unchecked")
ComponentMetadata createServiceRef(String unitName, Class<?> iface) {
final MutableReferenceMetadata refMeta = pc.createMetadata(MutableReferenceMetadata.class);
refMeta.setActivation(getDefaultActivation(pc));
refMeta.setAvailability(ReferenceMetadata.AVAILABILITY_MANDATORY);
refMeta.setRuntimeInterface(iface);
refMeta.setFilter(String.format("(%s=%s)", JPA_UNIT_NAME, unitName));
refMeta.setTimeout(Integer.parseInt(pc.getDefaultTimeout()));
refMeta.setDependsOn((List<String>)Collections.EMPTY_LIST);
refMeta.setId(getId(unitName, iface));
return refMeta;
}
public String getId(String unitName, Class<?> iface) {
return unitName + "_" + iface.getSimpleName();
}
private int getDefaultActivation(ParserContext ctx) {
return "ACTIVATION_EAGER".equalsIgnoreCase(ctx.getDefaultActivation())
? ReferenceMetadata.ACTIVATION_EAGER : ReferenceMetadata.ACTIVATION_LAZY;
}
private String getFilter(Class<?> clazz, String unitName) {
return String.format("(&(objectClass=%s)(%s=%s))", clazz.getName(), JPA_UNIT_NAME, unitName);
}
}