You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ti...@apache.org on 2010/02/04 13:01:46 UTC
svn commit: r906462 - in /incubator/aries/trunk/jpa/jpa-container-context:
./ src/main/java/org/apache/aries/jpa/container/context/
src/main/java/org/apache/aries/jpa/container/context/impl/
src/main/java/org/apache/aries/jpa/container/context/namespac...
Author: timothyjward
Date: Thu Feb 4 12:01:45 2010
New Revision: 906462
URL: http://svn.apache.org/viewvc?rev=906462&view=rev
Log:
ARIES-127 : Add logging to the JPA components
Modified:
incubator/aries/trunk/jpa/jpa-container-context/pom.xml
incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/GlobalPersistenceManager.java
incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/PersistenceManager.java
incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java
incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManager.java
incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/namespace/NSHandler.java
incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java
incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistry.java
Modified: incubator/aries/trunk/jpa/jpa-container-context/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/pom.xml?rev=906462&r1=906461&r2=906462&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/pom.xml (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/pom.xml Thu Feb 4 12:01:45 2010
@@ -42,11 +42,6 @@
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>org.apache.aries.jpa</groupId>
- <artifactId>jpa-container</artifactId>
- <version>1.0.0-incubating-SNAPSHOT</version>
- </dependency>
- <dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jpa_2.0_spec</artifactId>
</dependency>
@@ -67,6 +62,10 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/GlobalPersistenceManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/GlobalPersistenceManager.java?rev=906462&r1=906461&r2=906462&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/GlobalPersistenceManager.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/GlobalPersistenceManager.java Thu Feb 4 12:01:45 2010
@@ -29,21 +29,30 @@
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.SynchronousBundleListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Class that coordinates PersistenceContextManagers across multiple (nested) OSGi frameworks.
*/
public class GlobalPersistenceManager implements PersistenceManager, SynchronousBundleListener {
-
+ /** Logger */
+ private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container.context");
+
private JTAPersistenceContextRegistry registry;
- /** The list of persistence context managers. Each is valid for exactly one framework
+ /**
+ * The list of persistence context managers. Each is valid for exactly one framework
* as identified by the respective system bundle. This allows us to work properly in
* a multi (nested) framework environment without using the (deprecated) CompositeBundle API.
*/
private Map<Bundle, PersistenceContextManager> managers =
new HashMap<Bundle, PersistenceContextManager>();
+ /**
+ * This Map relates persistence context clients to persistence contexts. A bundle may be
+ * a client of more than one persistence context.
+ */
private Map<Bundle, Set<String>> persistenceContexts =
new HashMap<Bundle, Set<String>>();
@@ -53,54 +62,86 @@
}
public void registerContext(String unitName, Bundle client, HashMap<String, Object> properties) {
+ if (_logger.isDebugEnabled()) {
+ _logger.debug("Registering bundle {} as a client of persistence unit {} with properties {}.",
+ new Object[] {client.getSymbolicName() + "_" + client.getVersion(), unitName, properties});
+ }
+ //Find the framework for this bundle (we may be in a composite)
Bundle frameworkBundle = client.getBundleContext().getBundle(0);
PersistenceContextManager manager = null;
boolean newManager = false;
+ //Synchronize to update internal state atomically
synchronized (this) {
+ //If we already have a manager use it
if (managers.containsKey(frameworkBundle)) {
manager = managers.get(frameworkBundle);
} else {
+ if (_logger.isDebugEnabled()) {
+ _logger.debug("No existing manager for the framework with identity hash code {}. Creating a new one.",
+ new Object[] {System.identityHashCode(frameworkBundle)});
+ }
manager = new PersistenceContextManager(frameworkBundle.getBundleContext(), registry);
managers.put(frameworkBundle, manager);
+ //Remember to listen to this new framework so that we know when bundles are starting/stopping
frameworkBundle.getBundleContext().addBundleListener(this);
newManager = true;
}
+ //Register the new bundle as a client
if (!persistenceContexts.containsKey(client)) {
persistenceContexts.put(client, new HashSet<String>());
}
persistenceContexts.get(client).add(unitName);
}
-
+ //Remember to start the manager if it was new. This MUST occur outside the synchronized block.
if (newManager)
manager.open();
manager.registerContext(unitName, client, properties);
}
+ /**
+ * This method is used to track the lifecycle of bundles inside composites
+ */
public void bundleChanged(BundleEvent event) {
Bundle bundle = event.getBundle();
- if (event.getType() == event.STOPPING) {
+ //We only care about bundles stopping
+ if (event.getType() == BundleEvent.STOPPING) {
Set<String> contextsToBeRemoved = Collections.emptySet();
Bundle frameworkBundle = bundle.getBundleContext().getBundle(0);
PersistenceContextManager manager = null;
boolean removeManager = false;
+ //Synchronize to update internal state atomically
synchronized (this) {
if (persistenceContexts.containsKey(bundle)) {
- contextsToBeRemoved = persistenceContexts.get(bundle);
- persistenceContexts.remove(bundle);
+ //This is a client, find the contexts to remove
+ contextsToBeRemoved = persistenceContexts.remove(bundle);
+
+ if (_logger.isDebugEnabled()) {
+ _logger.debug("The bundle {} in framework {}, which is a client of the persistence contexts {} is stopping.",
+ new Object[] {bundle.getSymbolicName() + "_" + bundle.getVersion(),
+ System.identityHashCode(frameworkBundle), contextsToBeRemoved});
+ }
manager = managers.get(frameworkBundle);
- if (manager == null)
+ if (manager == null) {
+ _logger.error("There was no context manager for framework {}. This should never happen");
throw new IllegalStateException();
+ }
} else if (managers.containsKey(bundle)) {
+ //The framework is stopping, tidy up the manager
+ if (_logger.isDebugEnabled()) {
+ _logger.debug("The framework {} is stopping.",
+ new Object[] {bundle.getSymbolicName() + "_" + bundle.getVersion(),
+ System.identityHashCode(frameworkBundle)});
+ }
removeManager = true;
- manager = managers.remove(bundle);
+ managers.remove(bundle);
bundle.getBundleContext().removeBundleListener(this);
}
}
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/PersistenceManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/PersistenceManager.java?rev=906462&r1=906461&r2=906462&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/PersistenceManager.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/PersistenceManager.java Thu Feb 4 12:01:45 2010
@@ -23,5 +23,13 @@
import org.osgi.framework.Bundle;
public interface PersistenceManager {
+ /**
+ * This method will be called whenever a persistence context element is processed by the jpa
+ * blueprint namespace handler.
+ *
+ * @param unitName The name of the persistence unit
+ * @param client The blueprint bundle that declares the dependency
+ * @param properties Properties that should be used to create the persistence unit
+ */
void registerContext(String unitName, Bundle client, HashMap<String,Object> properties);
}
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java?rev=906462&r1=906461&r2=906462&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java Thu Feb 4 12:01:45 2010
@@ -31,11 +31,18 @@
import org.apache.aries.jpa.container.context.transaction.impl.JTAEntityManager;
import org.apache.aries.jpa.container.context.transaction.impl.JTAPersistenceContextRegistry;
import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
- * A service factory that can lazily create persistence contexts
+ * A factory that can lazily create managed persistence contexts.
+ * This is registered in the Service registry to be looked up by blueprint.
+ * The EntityManagerFactory interface is used to ensure a shared class space
+ * with the client. Only the createEntityManager() method is supported.
*/
public class ManagedPersistenceContextFactory implements EntityManagerFactory {
-
+ /** Logger */
+ private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container.context");
+
private final ServiceReference emf;
private final Map<String, Object> properties;
private final JTAPersistenceContextRegistry registry;
@@ -50,13 +57,17 @@
}
public EntityManager createEntityManager() {
+ if(_logger.isDebugEnabled()) {
+ _logger.debug("Creating a container managed entity manager for the perstence unit {} with the following properties {}",
+ new Object[] {emf, properties});
+ }
EntityManagerFactory factory = (EntityManagerFactory) emf.getBundle().getBundleContext().getService(emf);
PersistenceContextType type = (PersistenceContextType) properties.get(PersistenceContextManager.PERSISTENCE_CONTEXT_TYPE);
if(type == PersistenceContextType.TRANSACTION || type == null)
return new JTAEntityManager(factory, properties, registry);
else {
- //TODO add support, or log the failure
+ _logger.error("There is currently no support for extended scope EntityManagers");
return null;
}
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManager.java?rev=906462&r1=906461&r2=906462&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManager.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManager.java Thu Feb 4 12:01:45 2010
@@ -39,12 +39,18 @@
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
- * This class is responsible for managing all of the persistence contexts at a defined scope
- * It will automatically manage the lifecycle of all registered persistence contexts
+ * This class is responsible for managing all of the persistence contexts at a defined scope,
+ * i.e. for a single framework or composite. It will automatically manage the lifecycle of all
+ * registered persistence contexts.
*/
public class PersistenceContextManager extends ServiceTracker{
+ /** Logger */
+ private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container.context");
+
/** The key to use when storing the {@link PersistenceContextType} for this context */
public static final String PERSISTENCE_CONTEXT_TYPE = "org.apache.aries.jpa.context.type";
/** The filter this tracker uses to select Persistence Units. */
@@ -52,12 +58,15 @@
static {
Filter f = null;
try {
+ //Create a filter to select container managed persistence units that
+ //are not proxies for managed persistence contexts
f = FrameworkUtil.createFilter("(&(" + Constants.OBJECTCLASS
+ "=" + "javax.persistence.EntityManagerFactory" + ")(" +
- PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))" );
+ PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true)(!("
+ + NSHandler.PROXY_FACTORY_EMF_ATTRIBUTE + "=*)))" );
} catch (InvalidSyntaxException e) {
- // TODO This should never ever happen!
- e.printStackTrace();
+ _logger.error("There was an exception creating the EntityManagerFactory filter. This should never happen.", e);
+ throw new RuntimeException(e);
}
filter = f;
}
@@ -101,6 +110,10 @@
@Override
public Object addingService(ServiceReference reference) {
+ if(_logger.isDebugEnabled()) {
+ _logger.debug("A new managed persistence unit, {}, has been detected.", new Object[] {reference});
+ }
+
String unitName = (String) reference.getProperty(PersistenceUnitConstants.OSGI_UNIT_NAME);
if(unitName == null)
unitName = "";
@@ -111,8 +124,8 @@
//If we already track a unit with the same name then we are in trouble!
//only one unit with a given name should exist at a single scope
if(persistenceUnits.containsKey(unitName)) {
- //TODO log a big warning here!
- //Stop tracking the duplicate unit.
+ _logger.warn("The persistence unit {} exists twice at the same framework scope. " +
+ "The second service will be ignored", new Object[] {reference});
return null;
}
//If this is a new unit, then add it, and check whether we have any waiting
@@ -129,6 +142,10 @@
public void removedService(ServiceReference ref, Object o)
{
+ if(_logger.isDebugEnabled()) {
+ _logger.debug("A managed persistence unit, {}, has been unregistered.", new Object[] {ref});
+ }
+
String unitName = (String) ref.getProperty(PersistenceUnitConstants.OSGI_UNIT_NAME);
if(unitName == null)
unitName = "";
@@ -148,7 +165,10 @@
* This must contain the {@link PersistenceContextType}
*/
public void registerContext(String name, Bundle client, HashMap<String, Object> properties) {
-
+ if (_logger.isDebugEnabled()) {
+ _logger.debug("Registering bundle {} as a client of persistence unit {} with properties {}.",
+ new Object[] {client.getSymbolicName() + "_" + client.getVersion(), name, properties});
+ }
HashMap<String, Object> oldProps;
boolean register;
//Use a synchronized to get an atomic view
@@ -167,7 +187,8 @@
oldProps = persistenceContextDefinitions.put(name, properties);
if(oldProps != null) {
if(!!!oldProps.equals(properties)) {
- //TODO log an error and use the old properties
+ _logger.warn("The bundle {} depends on a managed persistence context {} with properties {}, but the context already exists with properties {}. The existing properties will be used.",
+ new Object[] {client.getSymbolicName() + "_" + client.getVersion(), name, properties, oldProps});
persistenceContextDefinitions.put(name, oldProps);
}
}
@@ -187,6 +208,10 @@
*/
public void unregisterContext(String name, Bundle client)
{
+ if (_logger.isDebugEnabled()) {
+ _logger.debug("Unregistering the bundle {} as a client of persistence unit {}.",
+ new Object[] {client.getSymbolicName() + "_" + client.getVersion(), name});
+ }
boolean unregister = false;
//Keep an atomic view of our state
synchronized (this) {
@@ -226,6 +251,9 @@
alreadyRegistered = true;
return;
}
+ if(_logger.isDebugEnabled()) {
+ _logger.debug("Registering a managed persistence context for persistence unit {}", new Object[] {name});
+ }
//Block other threads from trying to register by adding the key
entityManagerRegistrations.put(name, null);
@@ -234,8 +262,12 @@
Map<String, Object> props = persistenceContextDefinitions.get(name);
//If either of these things is undefined then the context cannot be registered
- if(props == null || unit == null)
+ if(props == null || unit == null) {
+ _logger.error("The managed persistence context {} cannot be registered for persistence unit {} and properties {}.",
+ new Object[] {name, unit, props});
+ //The finally block will clear the entityManagerRegistrations key
return;
+ }
//Create the service factory
entityManagerServiceFactory = new ManagedPersistenceContextFactory(unit, props, persistenceContextRegistry);
@@ -268,10 +300,12 @@
//If the key still exists then all is well
if(entityManagerRegistrations.containsKey(name)) {
entityManagerRegistrations.put(name, reg);
- //Else we were in a potential live-lock and the service could not be unregistered
- //earlier. This means we have to do it (but outside the synchronized. Make sure we
- //also remove the registration key!
} else {
+ //Else we were in a potential live-lock and the service could not be unregistered
+ //earlier. This means we have to do it (but outside the synchronized. Make sure we
+ //also remove the registration key!
+ _logger.warn("Recovering from a potential live-lock registering a container managed peristence context for persistence unit {}.",
+ new Object[] {name});
entityManagerRegistrations.remove(name);
recoverFromLiveLock = true;
}
@@ -329,8 +363,7 @@
try {
this.wait(500);
} catch (InterruptedException e) {
- // TODO Log this properly
- e.printStackTrace();
+ _logger.warn("The Aries JPA container was interrupted when waiting for managed persistence context {} to be unregistered", new Object[] {unitName});
}
//Increment the loop to prevent us from live-locking
tries++;
@@ -341,7 +374,8 @@
if(!found) {
//Possible Live lock, just remove the key
entityManagerRegistrations.remove(unitName);
- //TODO log the potential issue
+ _logger.warn("The JPA container detected a possible live lock whilst unregistering the managed persistence context {}. The service cannot be unregistered immediately so the context may become unusable before being unregistered.",
+ new Object[] {unitName});
}
}
//If we found the registration then unregister it outside the synchronized.
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/namespace/NSHandler.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/namespace/NSHandler.java?rev=906462&r1=906461&r2=906462&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/namespace/NSHandler.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/namespace/NSHandler.java Thu Feb 4 12:01:45 2010
@@ -26,8 +26,10 @@
import java.util.Map;
import java.util.Set;
+import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContextType;
+import javax.persistence.PersistenceUnit;
import org.apache.aries.blueprint.NamespaceHandler;
import org.apache.aries.blueprint.ParserContext;
@@ -36,6 +38,7 @@
import org.apache.aries.blueprint.mutable.MutableRefMetadata;
import org.apache.aries.blueprint.mutable.MutableReferenceMetadata;
import org.apache.aries.jpa.container.PersistenceUnitConstants;
+import org.apache.aries.jpa.container.context.GlobalPersistenceManager;
import org.apache.aries.jpa.container.context.PersistenceManager;
import org.osgi.framework.Bundle;
import org.osgi.service.blueprint.reflect.BeanArgument;
@@ -49,60 +52,94 @@
import org.osgi.service.blueprint.reflect.ReferenceMetadata;
import org.osgi.service.blueprint.reflect.Target;
import org.osgi.service.blueprint.reflect.ValueMetadata;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+/**
+ * This class handles the JPA namespace in blueprint xml files, it configures
+ * injection for managed persistence units and managed persistence contexts.
+ * The namespace handler also registers clients of managed persistence contexts
+ * with the {@link GlobalPersistenceManager}.
+ */
public class NSHandler implements NamespaceHandler {
+ /** Logger */
+ private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container.context");
+ /** The JPA namespace */
public static final String NS_URI = "http://aries.apache.org/xmlns/jpa/v1.0.0";
+ /** The standard blueprint namespace */
private static final String BLUEPRINT_NS = "http://www.osgi.org/xmlns/blueprint/v1.0.0";
+ /** The element name for an injected persistence unit (see {@link PersistenceUnit}) */
private static final String TAG_UNIT = "unit";
+ /** The element name for an injected persistence context (see {@link PersistenceContext}) */
private static final String TAG_CONTEXT = "context";
+ /** The element name for a blueprint map */
private static final String TAG_MAP = "map";
+ /** The jpa attribute for property injection, provides the injection site */
private static final String ATTR_PROPERTY = "property";
+ /** The {@link PersistenceContextType} of a persistence context */
private static final String ATTR_TYPE = "type";
+ /** The name of the persistence unit */
private static final String ATTR_UNIT_NAME = "unitname";
-
- private static final String TYPE_JTA = "TRANSACTION";
+ /** The default name to use if no unit name is specified */
private static final String DEFAULT_UNIT_NAME = "";
+ /** A filter to find persistence units that specify an empty name */
public static final String EMPTY_UNIT_NAME_FILTER =
"(" + PersistenceUnitConstants.EMPTY_PERSISTENCE_UNIT_NAME + "=true)";
+ /** The service property indicating that a registered EMF is used to create managed persistence contexts */
public static final String PROXY_FACTORY_EMF_ATTRIBUTE = "org.apache.aries.jpa.proxy.factory";
+ /** The blueprint attribute value to make a bean eager */
private static final String ACTIVATION_EAGER = "EAGER";
-
+ /** The {@link PersistenceManager} to register contexts with */
private PersistenceManager manager;
public void setManager(PersistenceManager manager) {
this.manager = manager;
}
+ /**
+ * Called by blueprint when we meet a JPA namespace element
+ */
public ComponentMetadata decorate(Node node, ComponentMetadata component, ParserContext context) {
- if (node.getNodeType() != Node.ELEMENT_NODE)
+ //The node should always be an element
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ _logger.error("The JPA namespace handler does not understand the DOM node {}.", new Object[] {node});
throw new IllegalArgumentException();
+ }
Element element = (Element) node;
-
- if (!(component instanceof BeanMetadata))
+ //The surrounding component should always be a bean
+ if (!(component instanceof BeanMetadata)) {
+ _logger.error("The JPA namespace should only be used to inject properties into a bean. The surrounding component was {}.", new Object[] {component});
throw new IllegalArgumentException();
+ }
final BeanMetadata bean = (BeanMetadata) component;
- if (!NS_URI.equals(element.getNamespaceURI()))
+ if (!NS_URI.equals(element.getNamespaceURI())) {
+ _logger.error("The JPA namespace handler should not be called for the namespace {}.", new Object[] {element.getNamespaceURI()});
throw new IllegalArgumentException();
+ }
- if (!TAG_UNIT.equals(element.getLocalName()) && !TAG_CONTEXT.equals(element.getLocalName()))
+ if (!TAG_UNIT.equals(element.getLocalName()) && !TAG_CONTEXT.equals(element.getLocalName())) {
+ _logger.error("The JPA namespace handler did not recognize the element named {}.", new Object[] {element.getLocalName()});
throw new IllegalArgumentException();
+ }
+ //Create an injection point for the JPA resource (a blueprint property)
final BeanProperty beanProperty = createInjectMetadata(element,
TAG_UNIT.equals(element.getLocalName()),
context);
-
+
+ //If this is a persistence context then register it with the manager
if (TAG_CONTEXT.equals(element.getLocalName())) {
Bundle client = getBlueprintBundle(context);
String unitName = parseUnitName(element);
@@ -114,12 +151,14 @@
manager.registerContext(unitName, client, properties);
}
+ // Create a new Bean to replace the one passed in
return new BeanMetadata() {
public String getId() {
return bean.getId();
}
+ @SuppressWarnings("unchecked")
public List<String> getDependsOn() {
return bean.getDependsOn();
}
@@ -132,7 +171,9 @@
return bean.getScope();
}
+ @SuppressWarnings("unchecked")
public List<BeanProperty> getProperties() {
+ //Remember to add the jpa injection property
ArrayList<BeanProperty> result = new ArrayList<BeanProperty>(bean.getProperties());
result.add(beanProperty);
return result;
@@ -158,13 +199,16 @@
return bean.getClassName();
}
+ @SuppressWarnings("unchecked")
public List<BeanArgument> getArguments() {
return bean.getArguments();
}
};
}
+ @SuppressWarnings("unchecked")
public Set<Class> getManagedClasses() {
+ //This is a no-op
return null;
}
@@ -174,28 +218,49 @@
public Metadata parse(Element element, ParserContext context) {
/*
- * The namespace does not any top-level elements, so we should never get here.
+ * The namespace does not define any top-level elements, so we should never get here.
* In case we do -> explode.
*/
+ _logger.error("The JPA namespace handler was called to parse a top level element.");
throw new UnsupportedOperationException();
}
+ /**
+ * Create a BeanProperty that will inject a JPA resource into a bean
+ * @param element The element being parsed
+ * @param isPersistenceUnit true if this is a persistence unit
+ * @param ctx The current parser context
+ * @return
+ */
private BeanProperty createInjectMetadata(Element element, boolean isPersistenceUnit, ParserContext ctx) {
String unitName = parseUnitName(element);
- final String property = parseProperty(element);
+ final String property = element.getAttribute(ATTR_PROPERTY);
+ if(_logger.isDebugEnabled()) {
+ if(isPersistenceUnit)
+ _logger.debug("Creating blueprint injection metadata to inject the unit {} into bean property {}",
+ new Object[] {unitName, property});
+ else
+ _logger.debug("Creating blueprint injection metadata to inject the context {} into bean property {}",
+ new Object[] {unitName, property});
+ }
+
+ //Create a service reference for the EMF (it is an EMF for persistence contexts and units)
final MutableReferenceMetadata refMetadata = (MutableReferenceMetadata) ctx.createMetadata(ReferenceMetadata.class);
refMetadata.setActivation(ACTIVATION_EAGER.equalsIgnoreCase(ctx.getDefaultActivation()) ?
ReferenceMetadata.ACTIVATION_EAGER : ReferenceMetadata.ACTIVATION_LAZY);
refMetadata.setAvailability(ReferenceMetadata.AVAILABILITY_MANDATORY);
refMetadata.setInterface(EntityManagerFactory.class.getName());
+ //Pick the right EMF by looking for the presence, or absence, of the PROXY_FACTORY service property
StringBuilder filter = new StringBuilder("(&");
+ //Persistence units do not have the property, persistence contexts do
if (isPersistenceUnit)
filter.append("(!(").append(PROXY_FACTORY_EMF_ATTRIBUTE).append("=*))");
else
filter.append("(").append(PROXY_FACTORY_EMF_ATTRIBUTE).append("=*)");
-
+
+ //Add the empty name filter if necessary
if (!"".equals(unitName))
filter.append("(" + PersistenceUnitConstants.OSGI_UNIT_NAME + "=" + unitName + ")");
else
@@ -207,7 +272,8 @@
refMetadata.setTimeout(Integer.parseInt(ctx.getDefaultTimeout()));
refMetadata.setDependsOn((List<String>) Collections.EMPTY_LIST);
refMetadata.setId(ctx.generateId());
-
+
+ //Finally, if this is a persistence context we need to create the entity manager as the Target
final Metadata target = isPersistenceUnit ? refMetadata
: createInjectionBeanMetedata(ctx, refMetadata);
@@ -222,7 +288,19 @@
};
}
+ /**
+ * This method turns a persistence context factory into an {@link EntityManager} using blueprint
+ * factories
+ * @param ctx the {@link ParserContext}
+ * @param factory the reference bean for the persistence context factory
+ * @return
+ */
private Metadata createInjectionBeanMetedata(ParserContext ctx, ReferenceMetadata factory) {
+
+ if(_logger.isDebugEnabled())
+ _logger.debug("Creating a managed persistence context definition for injection");
+
+ //Register the factory bean, and then create an entitymanager from it
ctx.getComponentDefinitionRegistry().registerComponentDefinition(factory);
MutableBeanMetadata meta = (MutableBeanMetadata) ctx.createMetadata(BeanMetadata.class);
@@ -237,6 +315,11 @@
return meta;
}
+ /**
+ * Get hold of the blueprint bundle using the built in components
+ * @param context
+ * @return
+ */
private Bundle getBlueprintBundle(ParserContext context) {
PassThroughMetadata metadata = (PassThroughMetadata) context.getComponentDefinitionRegistry()
.getComponentDefinition("blueprintBundle");
@@ -248,15 +331,12 @@
return result;
}
-
- private String parseProperty(Element element) {
- return element.getAttribute(ATTR_PROPERTY);
- }
+
private PersistenceContextType parseType(Element element) {
- String typeName = element.hasAttribute(ATTR_TYPE) ? element.getAttribute(ATTR_TYPE) : TYPE_JTA;
-
- return PersistenceContextType.valueOf(typeName);
+ if(element.hasAttribute(ATTR_TYPE))
+ return PersistenceContextType.valueOf(element.getAttribute(ATTR_TYPE));
+ else return PersistenceContextType.TRANSACTION;
}
private String parseUnitName(Element element) {
@@ -264,10 +344,16 @@
element.getAttribute(ATTR_UNIT_NAME) : DEFAULT_UNIT_NAME;
}
+ /**
+ * Parse any properties for creating the persistence context
+ * @param element
+ * @param context
+ * @return
+ */
private Map<String, Object> parseJPAProperties(Element element, ParserContext context) {
Map<String, Object> result = new HashMap<String, Object>();
NodeList ns = element.getElementsByTagNameNS(BLUEPRINT_NS, TAG_MAP);
-
+ //Use the parser context to parse the map for us
for (int i=0; i<ns.getLength(); i++) {
MapMetadata metadata = context.parseElement(MapMetadata.class, null, (Element) ns.item(i));
for (MapEntry entry : (List<MapEntry>) metadata.getEntries()) {
@@ -277,6 +363,7 @@
result.put(key.getStringValue(), value.getStringValue());
} else {
+ _logger.error("There was a problem parsing a map of JPA properties");
throw new UnsupportedOperationException();
}
}
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java?rev=906462&r1=906461&r2=906462&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java Thu Feb 4 12:01:45 2010
@@ -37,9 +37,16 @@
*/
public class JTAEntityManager implements EntityManager {
+ /** The {@link EntityManagerFactory} that can create new {@link EntityManager} instances */
private final EntityManagerFactory emf;
+ /** The map of properties to pass when creating EntityManagers */
private final Map<String, Object> props;
+ /** A registry for creating new persistence contexts */
private final JTAPersistenceContextRegistry reg;
+ /**
+ * The entity manager to use when there is no transaction. Note that there is one of these
+ * per injection site.
+ */
private EntityManager detachedManager = null;
public JTAEntityManager(EntityManagerFactory factory,
@@ -76,7 +83,6 @@
if (temp != null)
temp.close();
}
-
return detachedManager;
}
}
@@ -105,7 +111,7 @@
public void close()
{
//TODO add a message here
- throw new IllegalStateException();
+ throw new IllegalStateException("It is forbidden to call close on a container managed EntityManager");
}
public boolean contains(Object arg0)
@@ -169,8 +175,7 @@
public EntityTransaction getTransaction()
{
- //TODO add a message here
- throw new IllegalStateException();
+ throw new IllegalStateException("Transaction management is not available for container managed EntityManagers");
}
public boolean isOpen()
@@ -331,9 +336,6 @@
public void setProperty(String arg0, Object arg1)
{
- /*
- * TODO check whether we need to change the properies as well
- */
getPersistenceContext(false).setProperty(arg0, arg1);
}
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistry.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistry.java?rev=906462&r1=906461&r2=906462&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistry.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistry.java Thu Feb 4 12:01:45 2010
@@ -29,11 +29,16 @@
import javax.transaction.Synchronization;
import javax.transaction.TransactionSynchronizationRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* This class is used to manage the lifecycle of JTA peristence contexts
*/
public class JTAPersistenceContextRegistry {
-
+ /** Logger */
+ private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container.context");
+
/**
* The transaction synchronization registry, used to determine the currently
* active transaction, and to register for post-commit cleanup.
@@ -67,10 +72,9 @@
Object transactionKey = tranRegistry.getTransactionKey();
- //TODO Globalize and log this problem
//Throw the error on to the client
if(transactionKey == null) {
- throw new TransactionRequiredException();
+ throw new TransactionRequiredException("No transaction currently active");
}
//Get hold of the Map. If there is no Map already registered then add one.
@@ -86,8 +90,7 @@
tranRegistry.registerInterposedSynchronization(new EntityManagerClearUp(transactionKey));
} catch (IllegalStateException e) {
persistenceContextRegistry.remove(transactionKey);
- //TODO add a message
- throw new TransactionRequiredException();
+ throw new TransactionRequiredException("Unable to synchronize with transaction " + transactionKey);
}
}
@@ -98,9 +101,9 @@
toReturn = (properties == null) ? persistenceUnit.createEntityManager() : persistenceUnit.createEntityManager(properties);
contextsForTransaction.put(persistenceUnit, toReturn);
} else {
- //TODO maybe add debug
+ if(_logger.isDebugEnabled())
+ _logger.debug("Re-using a persistence context for transaction " + transactionKey);
}
-
return toReturn;
}
@@ -144,7 +147,7 @@
try {
em.close();
} catch (Exception e) {
- //TODO Log this, but continue
+ _logger.warn("There was an error when the container closed an EntityManager", em);
}
}
}