Return-Path: Delivered-To: apmail-aries-commits-archive@www.apache.org Received: (qmail 88277 invoked from network); 27 Feb 2011 18:08:45 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 27 Feb 2011 18:08:45 -0000 Received: (qmail 94289 invoked by uid 500); 27 Feb 2011 18:08:44 -0000 Delivered-To: apmail-aries-commits-archive@aries.apache.org Received: (qmail 94208 invoked by uid 500); 27 Feb 2011 18:08:43 -0000 Mailing-List: contact commits-help@aries.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@aries.apache.org Delivered-To: mailing list commits@aries.apache.org Received: (qmail 94190 invoked by uid 99); 27 Feb 2011 18:08:42 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 27 Feb 2011 18:08:42 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 27 Feb 2011 18:08:38 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id A71602388A40; Sun, 27 Feb 2011 18:08:18 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1075099 [2/7] - in /aries/tags/jpa-0.1-incubating: ./ jpa-api/ jpa-api/src/ jpa-api/src/main/ jpa-api/src/main/java/ jpa-api/src/main/java/org/ jpa-api/src/main/java/org/apache/ jpa-api/src/main/java/org/apache/aries/ jpa-api/src/main/java... Date: Sun, 27 Feb 2011 18:08:17 -0000 To: commits@aries.apache.org From: zoe@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20110227180818.A71602388A40@eris.apache.org> Added: aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/PersistenceUnitConstants.java URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/PersistenceUnitConstants.java?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/PersistenceUnitConstants.java (added) +++ aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/PersistenceUnitConstants.java Sun Feb 27 18:08:10 2011 @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.aries.jpa.container; + +import javax.persistence.spi.PersistenceProvider; + +/** + * Constants used when registering Persistence Units in the service registry + */ +public interface PersistenceUnitConstants { + /** The service property key mapped to the persistence unit name */ + public static final String OSGI_UNIT_NAME = "osgi.unit.name"; + /** The version of the persistence bundle as a {@link Version} object*/ + public static final String OSGI_UNIT_VERSION = "osgi.unit.version"; + /** The service property key mapped to the {@link PersistenceProvider} implementation class name */ + public static final String OSGI_UNIT_PROVIDER = "osgi.unit.provider"; + /** The service property key mapped to a Boolean indicating whether this persistence unit is container managed */ + public static final String CONTAINER_MANAGED_PERSISTENCE_UNIT = "org.apache.aries.jpa.container.managed"; + /** The service property key mapped to a Boolean indicating whether this persistence unit has the default (empty string) unit name + * This allows clients to filter for empty string persistence unit names. + */ + public static final String EMPTY_PERSISTENCE_UNIT_NAME = "org.apache.aries.jpa.default.unit.name"; +} Added: aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/context/PersistenceContextProvider.java URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/context/PersistenceContextProvider.java?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/context/PersistenceContextProvider.java (added) +++ aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/context/PersistenceContextProvider.java Sun Feb 27 18:08:10 2011 @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.aries.jpa.container.context; + +import java.util.HashMap; + +import javax.persistence.PersistenceContextType; + +import org.osgi.framework.Bundle; + +public interface PersistenceContextProvider { + + /** 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 service property key 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"; + + /** + * 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 properties); +} Added: aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/ParsedPersistenceUnit.java URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/ParsedPersistenceUnit.java?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/ParsedPersistenceUnit.java (added) +++ aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/ParsedPersistenceUnit.java Sun Feb 27 18:08:10 2011 @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.aries.jpa.container.parsing; + +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.osgi.framework.Bundle; + +/** + * This interface provides access to the information defined by a + * persistence unit in a persistence descriptor. + * + * Implementations of this interface will be returned by calls to + * {@link PersistenceDescriptorParser}. + */ +public interface ParsedPersistenceUnit { + /* + * Keys for use in the PersistenceXml Map + * Stored values are Strings unless otherwise specified, and all values + * other than the schema version and unit name may be null. A null value + * indicates that the element/attribute was not present in the xml. + */ + + /** The version of the JPA schema being used */ + public static final String SCHEMA_VERSION = "org.apache.aries.jpa.schema.version"; + /** The name of the persistence unit */ + public static final String UNIT_NAME = "org.apache.aries.jpa.unit.name"; + /** The Transaction type of the persistence unit */ + public static final String TRANSACTION_TYPE = "org.apache.aries.jpa.transaction.type"; + /** A {@link List} of {@link String} mapping file names */ + public static final String MAPPING_FILES = "org.apache.aries.jpa.mapping.files"; + /** A {@link List} of {@link String} jar file names */ + public static final String JAR_FILES = "org.apache.aries.jpa.jar.files"; + /** A {@link List} of {@link String} managed class names */ + public static final String MANAGED_CLASSES = "org.apache.aries.jpa.managed.classes"; + /** A {@link Properties} object containing the properties from the persistence unit */ + public static final String PROPERTIES = "org.apache.aries.jpa.properties"; + /** The provider class name */ + public static final String PROVIDER_CLASSNAME = "org.apache.aries.jpa.provider"; + /** The jta-datasource name */ + public static final String JTA_DATASOURCE = "org.apache.aries.jpa.jta.datasource"; + /** The non-jta-datasource name */ + public static final String NON_JTA_DATASOURCE = "org.apache.aries.jpa.non.jta.datasource"; + /** A {@link Boolean} indicating whether unlisted classes should be excluded */ + public static final String EXCLUDE_UNLISTED_CLASSES = "org.apache.aries.jpa.exclude.unlisted"; + + /* JPA 2 extensions */ + + /** The caching type of the persistence unit. This will only be available for JPA2 persistence units. */ + public static final String SHARED_CACHE_MODE = "org.apache.aries.jpa2.shared.cache.mode"; + /** The validation mode of the persistence unit. This will only be available for JPA2 persistence units. */ + public static final String VALIDATION_MODE = "org.apache.aries.jpa2.validation.mode"; + + + /* End of Map keys */ + + /** This property is used in the JPA properties to indicate a provider version range */ + public static final String JPA_PROVIDER_VERSION = "org.apache.aries.jpa.provider.version"; + + /** + * Return the persistence bundle that defines this persistence unit + * @return + */ + public Bundle getDefiningBundle(); + + /** + * Returns a deep copy of the persistence metadata, modifications to the + * returned {@link Map} will not be reflected in future calls. + * @return + */ + public Map getPersistenceXmlMetadata(); +} Added: aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/PersistenceDescriptor.java URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/PersistenceDescriptor.java?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/PersistenceDescriptor.java (added) +++ aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/PersistenceDescriptor.java Sun Feb 27 18:08:10 2011 @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.aries.jpa.container.parsing; + +import java.io.InputStream; + +/** + * This is a utility interface that is used by the {@link PersistenceDescriptorParser}. + * + * This interfaces provides access to a single {@link InputStream} that returns the bytes + * of the persistence descriptor, and a String denoting the location of the persistence + * descriptor as present in the persistence bundle's Meta-Persistence header. + */ +public interface PersistenceDescriptor { + + /** + * Get the location of the persistence descriptor as it appears in the + * Meta-Persistence header. The default location should be returned as + * "META-INF/persistence.xml". + * @return + */ + public String getLocation(); + + /** + * Get an {@link InputStream} to the persistence descriptor. This method need not return a + * new {@link InputStream} each time, and it is undefined for multiple clients to attempt to use + * the {@link InputStream} from this {@link PersistenceDescriptor}. It is also undefined for a + * client to try to retrieve multiple {@link InputStream} objects from this method. + * + * @return An {@link InputStream} to the persistence descriptor. + */ + public InputStream getInputStream(); + +} \ No newline at end of file Added: aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/PersistenceDescriptorParser.java URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/PersistenceDescriptorParser.java?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/PersistenceDescriptorParser.java (added) +++ aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/PersistenceDescriptorParser.java Sun Feb 27 18:08:10 2011 @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.aries.jpa.container.parsing; + +import java.util.Collection; + +import org.osgi.framework.Bundle; + +/** + * A utility service for parsing JPA persistence descriptors + */ +public interface PersistenceDescriptorParser { + + /** + * Parse the supplied {@link PersistenceDescriptor} + * + * @param b The bundle that contains the persistence descriptor + * @param descriptor The descriptor + * + * @return A collection of {@link ParsedPersistenceUnit} + * @throws PersistenceDescriptorParserException if any error occurs in parsing + */ + public abstract Collection parse(Bundle b, + PersistenceDescriptor descriptor) + throws PersistenceDescriptorParserException; + +} \ No newline at end of file Added: aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/PersistenceDescriptorParserException.java URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/PersistenceDescriptorParserException.java?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/PersistenceDescriptorParserException.java (added) +++ aries/tags/jpa-0.1-incubating/jpa-api/src/main/java/org/apache/aries/jpa/container/parsing/PersistenceDescriptorParserException.java Sun Feb 27 18:08:10 2011 @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.aries.jpa.container.parsing; + +/** + * This Exception will be thrown when there was an error parsing a PersistenceDescriptor + * It will use the standard chaining mechanism to wrap the Exception thrown by the parser. + */ +public class PersistenceDescriptorParserException extends Exception { + + /** + * Construct a PersistenceDescriptorException + * @param string + * @param e the exception to wrap + */ + public PersistenceDescriptorParserException(String string, Exception e) { + super(string, e); + } + + /** + * Construct a PersistenceDescriptorException + * @param string + */ + public PersistenceDescriptorParserException(String string) { + super(string); + } + + /** + * For Serialization + */ + private static final long serialVersionUID = -8960763303021136544L; + +} Added: aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/pom.xml URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/pom.xml?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/pom.xml (added) +++ aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/pom.xml Sun Feb 27 18:08:10 2011 @@ -0,0 +1,102 @@ + + + + + jpa + org.apache.aries.jpa + 0.1-incubating + + Aries JPA Container blueprint integration for Aries blueprint + 4.0.0 + org.apache.aries.jpa.blueprint.aries + bundle + + + + org.osgi + org.osgi.core + provided + + + org.osgi + org.osgi.compendium + provided + + + org.apache.geronimo.specs + geronimo-jpa_2.0_spec + provided + + + org.apache.aries.blueprint + org.apache.aries.blueprint + provided + + + org.apache.aries.jpa + org.apache.aries.jpa.api + provided + + + org.slf4j + slf4j-api + + + junit + junit + test + + + org.apache.aries.testsupport + org.apache.aries.testsupport.unit + test + + + org.slf4j + slf4j-simple + test + + + + + + org.apache.felix + maven-bundle-plugin + + + ${pom.artifactId} + + javax.persistence;version="[1.0.0,3.0.0)", + org.apache.aries.jpa.container.context;version="[0.1.0,1.1.0)", + org.apache.aries.blueprint;version="[0.1.0,1.1.0)", + * + + + org.apache.aries.blueprint.NamespaceHandler;osgi.service.blueprint.namespace=http://aries.apache.org/xmlns/jpa/v1.0.0 + + <_versionpolicy>[$(version;==;$(@)),$(version;+;$(@))) + <_removeheaders>Ignore-Package,Include-Resource,Private-Package,Bundle-DocURL + + + + + + + Added: aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/main/java/org/apache/aries/jpa/blueprint/aries/impl/NSHandler.java URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/main/java/org/apache/aries/jpa/blueprint/aries/impl/NSHandler.java?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/main/java/org/apache/aries/jpa/blueprint/aries/impl/NSHandler.java (added) +++ aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/main/java/org/apache/aries/jpa/blueprint/aries/impl/NSHandler.java Sun Feb 27 18:08:10 2011 @@ -0,0 +1,411 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.aries.jpa.blueprint.aries.impl; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.PersistenceContext; +import javax.persistence.PersistenceContextType; +import javax.persistence.PersistenceUnit; + +import org.apache.aries.blueprint.ExtendedBeanMetadata; +import org.apache.aries.blueprint.NamespaceHandler; +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.container.PersistenceUnitConstants; +import org.apache.aries.jpa.container.context.PersistenceContextProvider; +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceReference; +import org.osgi.service.blueprint.reflect.BeanMetadata; +import org.osgi.service.blueprint.reflect.BeanProperty; +import org.osgi.service.blueprint.reflect.ComponentMetadata; +import org.osgi.service.blueprint.reflect.MapEntry; +import org.osgi.service.blueprint.reflect.MapMetadata; +import org.osgi.service.blueprint.reflect.Metadata; +import org.osgi.service.blueprint.reflect.RefMetadata; +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.blueprint.aries"); + + /** 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"; + /** 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 blueprint attribute value to make a bean eager */ + private static final String ACTIVATION_EAGER = "EAGER"; + /** The {@link PersistenceManager} to register contexts with */ + private PersistenceContextProvider manager; + /** Used to indicate whether the PersistenceContextProvider is available */ + private final AtomicBoolean contextsAvailable = new AtomicBoolean(); + + public void setManager(PersistenceContextProvider manager) { + this.manager = manager; + } + + /** + * Called by blueprint when we meet a JPA namespace element + */ + public ComponentMetadata decorate(Node node, ComponentMetadata component, + ParserContext context) { + // 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(node.toString()); + } + + Element element = (Element) node; + // 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(component.toString()); + } + + if (!(component instanceof MutableBeanMetadata)) { + _logger.error("The JPA namespace should only be used to inject properties into beans " + + "that implement the MutableBeanMetadata interface. " + + "The surrounding component was {}.", new Object[] { component }); + throw new IllegalArgumentException(component.toString()); + } + + MutableBeanMetadata bean = (MutableBeanMetadata) component; + + 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())) { + _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); + + if (client != null) { + HashMap properties = new HashMap(); + // Remember to add the PersistenceContextType so that we can create + // the correct type of + // EntityManager + properties.put(PersistenceContextProvider.PERSISTENCE_CONTEXT_TYPE, + parseType(element)); + properties.putAll(parseJPAProperties(element, context)); + if(contextsAvailable.get()) { + manager.registerContext(unitName, client, properties); + } else { + _logger.warn("The bundle {} is a client of persistence unit {} with properties {}, but no PersistenceContextProvider is available in the runtime. " + + "The blueprint for this bundle will not start correctly unless the managed persistence context is registered through some other mechanism", + new Object[] {client.getSymbolicName() + "_" + client.getVersion(), unitName, properties}); + } + } else { + _logger.debug("No bundle: this must be a dry, parse only run."); + } + } + + bean.addProperty(beanProperty); + + return bean; + } + + @SuppressWarnings("unchecked") + public Set getManagedClasses() { + // This is a no-op + return null; + } + + public URL getSchemaLocation(String namespace) { + if(NS_URI.equals(namespace)) + return getClass().getResource("/org/apache/aries/jpa/blueprint/namespace/jpa.xsd"); + else + return null; + } + + public Metadata parse(Element element, ParserContext context) { + /* + * 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(); + } + + /** + * Called when a {@link PersistenceContextProvider} is available + * @param ref + */ + public void contextAvailable(ServiceReference ref) { + boolean log = contextsAvailable.compareAndSet(false, true); + + if(log && _logger.isDebugEnabled()) + _logger.debug("Managed persistence context support is now available for use with the Aries Blueprint container"); + } + + /** + * Called when a {@link PersistenceContextProvider} is no longer available + * @param ref + */ + public void contextUnavailable(ServiceReference ref) { + contextsAvailable.set(false); + _logger.warn("Managed persistence context support is no longer available for use with the Aries Blueprint container"); + } + + /** + * 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 = 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(PersistenceContextProvider.PROXY_FACTORY_EMF_ATTRIBUTE) + .append("=*))"); + else + filter.append("(").append(PersistenceContextProvider.PROXY_FACTORY_EMF_ATTRIBUTE) + .append("=*)"); + + // Add the empty name filter if necessary + if (!"".equals(unitName)) + filter.append("(" + PersistenceUnitConstants.OSGI_UNIT_NAME + "=" + + unitName + ")"); + else + filter.append(EMPTY_UNIT_NAME_FILTER); + + filter.append(")"); + + refMetadata.setFilter(filter.toString()); + refMetadata.setTimeout(Integer.parseInt(ctx.getDefaultTimeout())); + refMetadata.setDependsOn((List) 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); + + return new BeanProperty() { + public Metadata getValue() { + return target; + } + + public String getName() { + return property; + } + }; + } + + /** + * 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); + MutableRefMetadata ref = (MutableRefMetadata) ctx + .createMetadata(RefMetadata.class); + ref.setComponentId(factory.getId()); + meta.setFactoryComponent(ref); + meta.setActivation(factory.getActivation()); + meta.setFactoryMethod("createEntityManager"); + meta.setScope(BeanMetadata.SCOPE_PROTOTYPE); + meta.setDestroyMethod("internalClose"); + + 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"); + + Bundle result = null; + if (metadata != null) { + result = (Bundle) metadata.getObject(); + } + + return result; + } + + private PersistenceContextType parseType(Element element) { + if (element.hasAttribute(ATTR_TYPE)) + return PersistenceContextType.valueOf(element + .getAttribute(ATTR_TYPE)); + else + return PersistenceContextType.TRANSACTION; + } + + private String parseUnitName(Element element) { + return element.hasAttribute(ATTR_UNIT_NAME) ? element + .getAttribute(ATTR_UNIT_NAME) : DEFAULT_UNIT_NAME; + } + + /** + * Parse any properties for creating the persistence context + * + * @param element + * @param context + * @return + */ + private Map parseJPAProperties(Element element, + ParserContext context) { + Map result = new HashMap(); + 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) metadata.getEntries()) { + if (entry.getKey() instanceof ValueMetadata + && entry.getValue() instanceof ValueMetadata) { + ValueMetadata key = (ValueMetadata) entry.getKey(); + ValueMetadata value = (ValueMetadata) entry.getValue(); + + result.put(key.getStringValue(), value.getStringValue()); + } else { + _logger.error("There was a problem parsing a map of JPA properties"); + throw new UnsupportedOperationException(); + } + } + } + + return result; + } +} Added: aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/main/resources/OSGI-INF/blueprint/jpa.xml URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/main/resources/OSGI-INF/blueprint/jpa.xml?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/main/resources/OSGI-INF/blueprint/jpa.xml (added) +++ aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/main/resources/OSGI-INF/blueprint/jpa.xml Sun Feb 27 18:08:10 2011 @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file Added: aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/main/resources/org/apache/aries/jpa/blueprint/namespace/jpa.xsd URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/main/resources/org/apache/aries/jpa/blueprint/namespace/jpa.xsd?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/main/resources/org/apache/aries/jpa/blueprint/namespace/jpa.xsd (added) +++ aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/main/resources/org/apache/aries/jpa/blueprint/namespace/jpa.xsd Sun Feb 27 18:08:10 2011 @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Added: aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/test/java/org/apache/aries/jpa/blueprint/aries/test/NSHandlerTest.java URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/test/java/org/apache/aries/jpa/blueprint/aries/test/NSHandlerTest.java?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/test/java/org/apache/aries/jpa/blueprint/aries/test/NSHandlerTest.java (added) +++ aries/tags/jpa-0.1-incubating/jpa-blueprint-aries/src/test/java/org/apache/aries/jpa/blueprint/aries/test/NSHandlerTest.java Sun Feb 27 18:08:10 2011 @@ -0,0 +1,296 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.aries.jpa.blueprint.aries.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.persistence.EntityManagerFactory; +import javax.persistence.PersistenceContextType; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.aries.blueprint.ComponentDefinitionRegistry; +import org.apache.aries.blueprint.ExtendedBeanMetadata; +import org.apache.aries.blueprint.ParserContext; +import org.apache.aries.blueprint.PassThroughMetadata; +import org.apache.aries.blueprint.container.Parser; +import org.apache.aries.blueprint.reflect.BeanMetadataImpl; +import org.apache.aries.blueprint.reflect.RefMetadataImpl; +import org.apache.aries.blueprint.reflect.ReferenceMetadataImpl; +import org.apache.aries.jpa.blueprint.aries.impl.NSHandler; +import org.apache.aries.jpa.container.context.PersistenceContextProvider; +import org.apache.aries.unittest.mocks.MethodCall; +import org.apache.aries.unittest.mocks.Skeleton; +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.service.blueprint.reflect.BeanMetadata; +import org.osgi.service.blueprint.reflect.BeanProperty; +import org.osgi.service.blueprint.reflect.ComponentMetadata; +import org.osgi.service.blueprint.reflect.Metadata; +import org.osgi.service.blueprint.reflect.RefMetadata; +import org.osgi.service.blueprint.reflect.ReferenceMetadata; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class NSHandlerTest { + private Element root; + private NSHandler sut; + private PersistenceContextProvider manager; + private ParserContext parserCtx; + private Bundle clientBundle; + private List registeredComponents = new ArrayList(); + + @Before + public void setup() throws Exception { + registeredComponents.clear(); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document doc = builder.parse(getClass().getClassLoader().getResourceAsStream("jpa.xml")); + root = doc.getDocumentElement(); + + sut = new NSHandler(); + manager = Skeleton.newMock(PersistenceContextProvider.class); + sut.setManager(manager); + sut.contextAvailable(null); + + clientBundle = Skeleton.newMock(Bundle.class); + + ComponentDefinitionRegistry registry = Skeleton.newMock(new ComponentDefinitionRegistryMock(), + ComponentDefinitionRegistry.class); + + parserCtx = Skeleton.newMock(new ParserContextMock(), ParserContext.class); + Skeleton.getSkeleton(parserCtx).setReturnValue( + new MethodCall(ParserContext.class,"getComponentDefinitionRegistry"), registry); + Skeleton.getSkeleton(parserCtx).setReturnValue( + new MethodCall(ParserContext.class, "getDefaultActivation"), "eager"); + Skeleton.getSkeleton(parserCtx).setReturnValue( + new MethodCall(ParserContext.class, "getDefaultTimeout"), "5000"); + } + + private static class ParserContextMock { + public T parseElement(Class type, ComponentMetadata enclosingComponent, Element element) { + return new Parser().parseElement(type, enclosingComponent, element); + } + + public T createMetadata(Class clazz) { + if (clazz.isAssignableFrom(ReferenceMetadata.class)) + return clazz.cast(new ReferenceMetadataImpl()); + else if (clazz.isAssignableFrom(RefMetadata.class)) + return clazz.cast(new RefMetadataImpl()); + else + return clazz.cast(new BeanMetadataImpl()); + } + } + + private class ComponentDefinitionRegistryMock { + public ComponentMetadata getComponentDefinition(String id) { + PassThroughMetadata bundleMeta = Skeleton.newMock(PassThroughMetadata.class); + Skeleton.getSkeleton(bundleMeta).setReturnValue( + new MethodCall(PassThroughMetadata.class, "getObject"), clientBundle); + return bundleMeta; + } + + public void registerComponentDefinition(ComponentMetadata component) { + registeredComponents.add(component); + } + } + + @Test + public void testUnit() { + Element e = getTestElement("unit"); + BeanMetadata bean = + (BeanMetadata) sut.decorate(e, new BeanMetadataImpl(), parserCtx); + BeanProperty property = (BeanProperty) bean.getProperties().get(0); + ReferenceMetadata reference = (ReferenceMetadata) property.getValue(); + + assertEquals("emf", property.getName()); + assertEquals(EntityManagerFactory.class.getName(), reference.getInterface()); + assertEquals("(&(!(org.apache.aries.jpa.proxy.factory=*))(osgi.unit.name=myUnit))", reference.getFilter()); + + Skeleton.getSkeleton(manager).assertSkeletonNotCalled(); + + assertTrue(registeredComponents.isEmpty()); + } + + @Test + public void testUnitNoName() { + Element e = getTestElement("unitNoName"); + BeanMetadata bean = + (BeanMetadata) sut.decorate(e, new BeanMetadataImpl(), parserCtx); + BeanProperty property = (BeanProperty) bean.getProperties().get(0); + ReferenceMetadata reference = (ReferenceMetadata) property.getValue(); + + assertEquals("emf2", property.getName()); + assertEquals("(&(!(org.apache.aries.jpa.proxy.factory=*))"+NSHandler.EMPTY_UNIT_NAME_FILTER+")", + reference.getFilter()); + + assertTrue(registeredComponents.isEmpty()); + } + + @Test + public void testEmptyUnitName() { + Element e = getTestElement("emptyUnitName"); + BeanMetadata bean = + (BeanMetadata) sut.decorate(e, new BeanMetadataImpl(), parserCtx); + BeanProperty property = (BeanProperty) bean.getProperties().get(0); + ReferenceMetadata reference = (ReferenceMetadata) property.getValue(); + + assertEquals("emf3", property.getName()); + assertEquals("(&(!(org.apache.aries.jpa.proxy.factory=*))"+NSHandler.EMPTY_UNIT_NAME_FILTER+")", + reference.getFilter()); + + assertTrue(registeredComponents.isEmpty()); + } + + @Test + public void testBeanMetadataOverwrite() { + Element e = getTestElement("unit"); + BeanMetadataImpl oldBean = new BeanMetadataImpl(); + oldBean.setId("myid"); + oldBean.setProperties(Arrays.asList(Skeleton.newMock(BeanProperty.class))); + + BeanMetadata bean = (BeanMetadata) sut.decorate(e, oldBean, parserCtx); + + assertEquals("myid", bean.getId()); + assertEquals(2, bean.getProperties().size()); + + assertTrue(registeredComponents.isEmpty()); + } + + @Test + public void testDefaultContext() { + Element e = getTestElement("context"); + BeanMetadata bean = + (BeanMetadata) sut.decorate(e, new BeanMetadataImpl(), parserCtx); + BeanMetadata innerBean = (BeanMetadata) ((BeanProperty) bean.getProperties().get(0)).getValue(); + + assertEquals("createEntityManager", innerBean.getFactoryMethod()); + assertEquals("internalClose", innerBean.getDestroyMethod()); + + assertEquals(1, registeredComponents.size()); + ReferenceMetadata reference = (ReferenceMetadata) registeredComponents.get(0); + + assertEquals(EntityManagerFactory.class.getName(), reference.getInterface()); + assertEquals("(&(org.apache.aries.jpa.proxy.factory=*)(osgi.unit.name=myUnit))", reference.getFilter()); + + Map props = new HashMap(); + props.put(PersistenceContextProvider.PERSISTENCE_CONTEXT_TYPE, PersistenceContextType.TRANSACTION); + Skeleton.getSkeleton(manager).assertCalled( + new MethodCall(PersistenceContextProvider.class, "registerContext", "myUnit", clientBundle, props)); + } + + @Test + public void testContextNoPersistenceContextProvider() { + + sut.contextUnavailable(null); + Element e = getTestElement("context"); + BeanMetadata bean = + (BeanMetadata) sut.decorate(e, new BeanMetadataImpl(), parserCtx); + BeanMetadata innerBean = (BeanMetadata) ((BeanProperty) bean.getProperties().get(0)).getValue(); + + assertEquals("createEntityManager", innerBean.getFactoryMethod()); + assertEquals("internalClose", innerBean.getDestroyMethod()); + + assertEquals(1, registeredComponents.size()); + ReferenceMetadata reference = (ReferenceMetadata) registeredComponents.get(0); + + assertEquals(EntityManagerFactory.class.getName(), reference.getInterface()); + assertEquals("(&(org.apache.aries.jpa.proxy.factory=*)(osgi.unit.name=myUnit))", reference.getFilter()); + + Map props = new HashMap(); + props.put(PersistenceContextProvider.PERSISTENCE_CONTEXT_TYPE, PersistenceContextType.TRANSACTION); + Skeleton.getSkeleton(manager).assertNotCalled( + new MethodCall(PersistenceContextProvider.class, "registerContext", String.class, Bundle.class, Map.class)); + } + + @Test + public void testContextWithProps() { + Element e = getTestElement("contextWithProps"); + BeanMetadata bean = + (BeanMetadata) sut.decorate(e, new BeanMetadataImpl(), parserCtx); + BeanMetadata innerBean = (BeanMetadata) ((BeanProperty) bean.getProperties().get(0)).getValue(); + + assertEquals("createEntityManager", innerBean.getFactoryMethod()); + + assertEquals(1, registeredComponents.size()); + ReferenceMetadata reference = (ReferenceMetadata) registeredComponents.get(0); + + assertEquals(EntityManagerFactory.class.getName(), reference.getInterface()); + assertEquals("(&(org.apache.aries.jpa.proxy.factory=*)"+NSHandler.EMPTY_UNIT_NAME_FILTER+")", + reference.getFilter()); + + Map props = new HashMap(); + props.put(PersistenceContextProvider.PERSISTENCE_CONTEXT_TYPE, PersistenceContextType.EXTENDED); + props.put("one", "eins"); + props.put("two", "zwo"); + Skeleton.getSkeleton(manager).assertCalled( + new MethodCall(PersistenceContextProvider.class, "registerContext", "", clientBundle, props)); + } + + @Test + public void testNoMoreProxying() { + Element e = getTestElement("contextWithProps"); + BeanMetadata input = new BeanMetadataImpl(); + Object output = sut.decorate(e, input, parserCtx); + assertTrue(input == output); + } + + private Element getTestElement(String beanName) { + NodeList ns = root.getElementsByTagName("bean"); + + Element bean = null; + for (int i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file Added: aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/pom.xml URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/pom.xml?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/pom.xml (added) +++ aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/pom.xml Sun Feb 27 18:08:10 2011 @@ -0,0 +1,62 @@ + + + + + jpa + org.apache.aries.jpa + 0.1-incubating + + 4.0.0 + org.apache.aries.jpa.blueprint.itest.bundle + bundle + Test Bundle for Aries JPA Blueprint iTests + + + + org.apache.geronimo.specs + geronimo-jpa_2.0_spec + provided + + + + + + + org.apache.felix + maven-bundle-plugin + + + ${pom.artifactId} + + javax.persistence;version="[1.0.0,3.0.0)", + * + + + org.apache.aries.jpa.blueprint.itest*;version="${pom.version}", + + <_versionpolicy>[$(version;==;$(@)),$(version;+;$(@))) + <_removeheaders>Ignore-Package,Include-Resource,Private-Package,Bundle-DocURL + OSGI-INF/persistence/persistence.xml + + + + + + Added: aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/java/org/apache/aries/jpa/blueprint/itest/JPATestBean.java URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/java/org/apache/aries/jpa/blueprint/itest/JPATestBean.java?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/java/org/apache/aries/jpa/blueprint/itest/JPATestBean.java (added) +++ aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/java/org/apache/aries/jpa/blueprint/itest/JPATestBean.java Sun Feb 27 18:08:10 2011 @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.aries.jpa.blueprint.itest; + +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityManager; + +public class JPATestBean { + + private EntityManagerFactory persistenceUnit; + + private EntityManager persistenceContext; + + public void setPersistenceUnit(EntityManagerFactory emf) { + persistenceUnit = emf; + } + + public void setPersistenceContext(EntityManager em) { + persistenceContext = em; + } + + /** + * @return True if we sucessfully called a method on the EMF + */ + public boolean pUnitAvailable() { + persistenceUnit.isOpen(); + return true; + } + + /** + * @return True if we sucessfully called a method on the EM + */ + public boolean pContextAvailable() { + persistenceContext.isOpen(); + return true; + } + +} Added: aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/java/org/apache/aries/jpa/blueprint/itest/entities/Car.java URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/java/org/apache/aries/jpa/blueprint/itest/entities/Car.java?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/java/org/apache/aries/jpa/blueprint/itest/entities/Car.java (added) +++ aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/java/org/apache/aries/jpa/blueprint/itest/entities/Car.java Sun Feb 27 18:08:10 2011 @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.aries.jpa.blueprint.itest.entities; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Car { + @Id + private String numberPlate; + + private String colour; + + private int engineSize; + + private int numberOfSeats; + + public String getNumberPlate() { + return numberPlate; + } + + public void setNumberPlate(String numberPlate) { + this.numberPlate = numberPlate; + } + + public String getColour() { + return colour; + } + + public void setColour(String colour) { + this.colour = colour; + } + + public int getEngineSize() { + return engineSize; + } + + public void setEngineSize(int engineSize) { + this.engineSize = engineSize; + } + + public int getNumberOfSeats() { + return numberOfSeats; + } + + public void setNumberOfSeats(int numberOfSeats) { + this.numberOfSeats = numberOfSeats; + } + + +} Added: aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/resources/OSGI-INF/blueprint/injection.xml URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/resources/OSGI-INF/blueprint/injection.xml?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/resources/OSGI-INF/blueprint/injection.xml (added) +++ aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/resources/OSGI-INF/blueprint/injection.xml Sun Feb 27 18:08:10 2011 @@ -0,0 +1,32 @@ + + + + + + + + + + + + \ No newline at end of file Added: aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/resources/OSGI-INF/persistence/persistence.xml URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/resources/OSGI-INF/persistence/persistence.xml?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/resources/OSGI-INF/persistence/persistence.xml (added) +++ aries/tags/jpa-0.1-incubating/jpa-blueprint-testbundle/src/main/resources/OSGI-INF/persistence/persistence.xml Sun Feb 27 18:08:10 2011 @@ -0,0 +1,35 @@ + + + + + + Test persistence unit for the JPA Blueprint integration iTest + org.apache.aries.jpa.blueprint.itest.entities.Car + + + + Test persistence context for the JPA Integration iTest + org.apache.aries.jpa.blueprint.itest.entities.Car + + + Added: aries/tags/jpa-0.1-incubating/jpa-container-context/pom.xml URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container-context/pom.xml?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-container-context/pom.xml (added) +++ aries/tags/jpa-0.1-incubating/jpa-container-context/pom.xml Sun Feb 27 18:08:10 2011 @@ -0,0 +1,107 @@ + + + + + jpa + org.apache.aries.jpa + 0.1-incubating + + 4.0.0 + org.apache.aries.jpa.container.context + Aries JPA Container Managed Contexts + bundle + + + + org.osgi + org.osgi.core + provided + + + org.osgi + org.osgi.compendium + provided + + + org.apache.geronimo.specs + geronimo-jpa_2.0_spec + provided + + + org.apache.geronimo.specs + geronimo-jta_1.1_spec + provided + + + org.apache.aries.blueprint + org.apache.aries.blueprint + provided + + + org.apache.aries.jpa + org.apache.aries.jpa.api + provided + + + org.slf4j + slf4j-api + + + junit + junit + test + + + org.apache.aries.testsupport + org.apache.aries.testsupport.unit + test + + + org.slf4j + slf4j-simple + test + + + + + + + + org.apache.felix + maven-bundle-plugin + + + ${pom.artifactId} + + javax.persistence;version="[1.0.0,2.1.0)", + javax.persistence.criteria;version="[1.1.0,2.1.0)";resolution:=optional, + javax.persistence.metamodel;version="[1.1.0,2.1.0)";resolution:=optional, + org.apache.aries.jpa.container.context;version="[0.1.0,1.1.0)", + * + + <_versionpolicy>[$(version;==;$(@)),$(version;+;$(@))) + <_removeheaders>Ignore-Package,Include-Resource,Private-Package,Bundle-DocURL + + + + + + + Added: aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/GlobalPersistenceManager.java URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/GlobalPersistenceManager.java?rev=1075099&view=auto ============================================================================== --- aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/GlobalPersistenceManager.java (added) +++ aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/GlobalPersistenceManager.java Sun Feb 27 18:08:10 2011 @@ -0,0 +1,165 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.aries.jpa.container.context.impl; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.aries.jpa.container.context.PersistenceContextProvider; +import org.apache.aries.jpa.container.context.transaction.impl.JTAPersistenceContextRegistry; +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 PersistenceContextProvider, 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 + * 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 managers = + new HashMap(); + + /** + * This Map relates persistence context clients to persistence contexts. A bundle may be + * a client of more than one persistence context. + */ + private Map> persistenceContexts = + new HashMap>(); + + + public void setRegistry(JTAPersistenceContextRegistry registry) { + this.registry = registry; + } + + public void registerContext(String unitName, Bundle client, HashMap properties) { + if (_logger.isDebugEnabled()) { + _logger.debug("Registering bundle {} as a client of persistence unit {} with properties {}.", + new Object[] {client.getSymbolicName() + "_" + client.getVersion(), unitName, properties}); + } + + if(!!!registry.jtaIntegrationAvailable()) + _logger.warn("No JTA integration is currently available. The managed persistence context {} used by the bundle {} will operate " + + "with no transaction context and be read only until a JTA Transaction Services implementation is available in" + + "the runtime", new Object[] {unitName, client.getSymbolicName() + "_" + client.getVersion()}); + + //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()); + } + + 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(); + + //We only care about bundles stopping + if (event.getType() == BundleEvent.STOPPING) { + Set 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)) { + //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) { + _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); + bundle.getBundleContext().removeBundleListener(this); + } + } + + if (removeManager) { + manager.close(); + } else { + for (String context : contextsToBeRemoved) { + manager.unregisterContext(context, bundle); + } + } + } + } + +}