From d68dcd9ae6c6785eade5ea5002104d8185a325c3 Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Thu, 4 Apr 2013 13:54:31 -0400 Subject: [PATCH] HHH-7993 Support jar scanning in OSGi --- .../hibernate/internal/CoreMessageLogger.java | 4 + hibernate-osgi/hibernate-osgi.gradle | 2 +- .../osgi/HibernateBundleActivator.java | 7 +- .../hibernate/osgi/OsgiArchiveDescriptor.java | 106 ++++++++++++++++++ .../osgi/OsgiArchiveDescriptorFactory.java | 49 ++++++++ .../osgi/OsgiPersistenceProvider.java | 7 ++ .../java/org/hibernate/osgi/OsgiScanner.java | 38 +++++++ 7 files changed, 209 insertions(+), 4 deletions(-) create mode 100644 hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiArchiveDescriptor.java create mode 100644 hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiArchiveDescriptorFactory.java create mode 100644 hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiScanner.java diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java index 98841da660..955c5c0b04 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java @@ -1619,4 +1619,8 @@ public interface CoreMessageLogger extends BasicLogger { @LogMessage(level = INFO) @Message( value = "'javax.persistence.validation.mode' named multiple values : %s", id = 448 ) void multipleValidationModes(String modes); + + @LogMessage(level = WARN) + @Message(value = "Exception while loading a class or resource found during scanning", id = 449) + void unableToLoadScannedClassOrResource(@Cause Exception e); } diff --git a/hibernate-osgi/hibernate-osgi.gradle b/hibernate-osgi/hibernate-osgi.gradle index a9c0ce376d..af99af5fd7 100644 --- a/hibernate-osgi/hibernate-osgi.gradle +++ b/hibernate-osgi/hibernate-osgi.gradle @@ -1,7 +1,7 @@ dependencies { compile( project( ':hibernate-core' ) ) compile( project( ':hibernate-entitymanager' ) ) - compile( "org.osgi:org.osgi.core:4.2.0" ) + compile( "org.osgi:org.osgi.core:4.3.0" ) } jar { diff --git a/hibernate-osgi/src/main/java/org/hibernate/osgi/HibernateBundleActivator.java b/hibernate-osgi/src/main/java/org/hibernate/osgi/HibernateBundleActivator.java index 38c9ac000c..c1f862fb98 100644 --- a/hibernate-osgi/src/main/java/org/hibernate/osgi/HibernateBundleActivator.java +++ b/hibernate-osgi/src/main/java/org/hibernate/osgi/HibernateBundleActivator.java @@ -23,7 +23,8 @@ */ package org.hibernate.osgi; -import java.util.Properties; +import java.util.Dictionary; +import java.util.Hashtable; import javax.persistence.spi.PersistenceProvider; @@ -72,7 +73,7 @@ public class HibernateBundleActivator implements BundleActivator { osgiJtaPlatform = new OsgiJtaPlatform( context ); - Properties properties = new Properties(); + Dictionary properties = new Hashtable(); // In order to support existing persistence.xml files, register // using the legacy provider name. properties.put( "javax.persistence.provider", HibernatePersistenceProvider.class.getName() ); @@ -80,7 +81,7 @@ public class HibernateBundleActivator implements BundleActivator { new OsgiPersistenceProviderService( osgiClassLoader, osgiJtaPlatform ), properties ); context.registerService( SessionFactory.class.getName(), - new OsgiSessionFactoryService( osgiClassLoader, osgiJtaPlatform ), new Properties()); + new OsgiSessionFactoryService( osgiClassLoader, osgiJtaPlatform ), new Hashtable()); } @Override diff --git a/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiArchiveDescriptor.java b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiArchiveDescriptor.java new file mode 100644 index 0000000000..692fdf1eaa --- /dev/null +++ b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiArchiveDescriptor.java @@ -0,0 +1,106 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.hibernate.osgi; + +import java.io.InputStream; +import java.util.Collection; + +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.jpa.boot.archive.spi.ArchiveContext; +import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptor; +import org.hibernate.jpa.boot.archive.spi.ArchiveEntry; +import org.hibernate.jpa.boot.spi.InputStreamAccess; +import org.hibernate.jpa.boot.spi.NamedInputStream; +import org.jboss.logging.Logger; +import org.osgi.framework.Bundle; +import org.osgi.framework.wiring.BundleWiring; + +/** + * @author Brett Meyer + * @author Tim Ward + */ +public class OsgiArchiveDescriptor implements ArchiveDescriptor { + + private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, + OsgiArchiveDescriptor.class.getName() ); + + private BundleWiring bundleWiring; + + private Bundle persistenceBundle; + + public OsgiArchiveDescriptor(Bundle persistenceBundle) { + this.persistenceBundle = persistenceBundle; + bundleWiring = (BundleWiring) persistenceBundle.adapt( BundleWiring.class ); + } + + @Override + public void visitArchive(ArchiveContext context) { + Collection resources = bundleWiring.listResources( "/", "*", BundleWiring.LISTRESOURCES_RECURSE ); + for ( final String resource : resources ) { + try { + final InputStream inputStream = persistenceBundle.getResource( resource ).openStream(); + + // TODO: Is using resource as the names correct? + + final InputStreamAccess inputStreamAccess = new InputStreamAccess() { + @Override + public String getStreamName() { + return resource; + } + + @Override + public InputStream accessInputStream() { + return inputStream; + } + + @Override + public NamedInputStream asNamedInputStream() { + return new NamedInputStream( resource, inputStream ); + } + + }; + + final ArchiveEntry entry = new ArchiveEntry() { + @Override + public String getName() { + return resource; + } + + @Override + public String getNameWithinArchive() { + return resource; + } + + @Override + public InputStreamAccess getStreamAccess() { + return inputStreamAccess; + } + }; + + context.obtainArchiveEntryHandler( entry ).handleEntry( entry, context ); + } + catch ( Exception e ) { + LOG.unableToLoadScannedClassOrResource( e ); + } + } + } + +} diff --git a/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiArchiveDescriptorFactory.java b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiArchiveDescriptorFactory.java new file mode 100644 index 0000000000..bf10ef12bf --- /dev/null +++ b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiArchiveDescriptorFactory.java @@ -0,0 +1,49 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.hibernate.osgi; + +import java.net.URL; + +import org.hibernate.jpa.boot.archive.internal.StandardArchiveDescriptorFactory; +import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptor; +import org.osgi.framework.Bundle; + +/** + * @author Brett Meyer + * @author Tim Ward + */ +public class OsgiArchiveDescriptorFactory extends StandardArchiveDescriptorFactory { + + private Bundle persistenceBundle; + + public OsgiArchiveDescriptorFactory(Bundle persistenceBundle) { + this.persistenceBundle = persistenceBundle; + } + + @Override + public ArchiveDescriptor buildArchiveDescriptor(URL url, String entry) { + final String protocol = url.getProtocol(); + if ( "bundle".equals( protocol ) ) { + return new OsgiArchiveDescriptor( persistenceBundle ); + } + return super.buildArchiveDescriptor( url, entry ); + } +} diff --git a/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiPersistenceProvider.java b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiPersistenceProvider.java index d2e5393467..dfe4b26954 100644 --- a/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiPersistenceProvider.java +++ b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiPersistenceProvider.java @@ -32,6 +32,7 @@ import javax.persistence.spi.PersistenceUnitInfo; import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.HibernatePersistenceProvider; import org.osgi.framework.Bundle; +import org.osgi.framework.BundleReference; /** * @author Brett Meyer @@ -62,6 +63,9 @@ public class OsgiPersistenceProvider extends HibernatePersistenceProvider { properties = new HashMap(); } properties.put( AvailableSettings.JTA_PLATFORM, osgiJtaPlatform ); + // TODO: This needs tested. + properties.put( org.hibernate.ejb.AvailableSettings.SCANNER, + new OsgiScanner( requestingBundle ) ); osgiClassLoader.addBundle( requestingBundle ); @@ -74,6 +78,9 @@ public class OsgiPersistenceProvider extends HibernatePersistenceProvider { properties = new HashMap(); } properties.put( AvailableSettings.JTA_PLATFORM, osgiJtaPlatform ); + // OSGi ClassLoaders must implement BundleReference + properties.put( org.hibernate.ejb.AvailableSettings.SCANNER, + new OsgiScanner( ( (BundleReference) info.getClassLoader() ).getBundle() ) ); osgiClassLoader.addClassLoader( info.getClassLoader() ); diff --git a/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiScanner.java b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiScanner.java new file mode 100644 index 0000000000..ac753466ae --- /dev/null +++ b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiScanner.java @@ -0,0 +1,38 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.hibernate.osgi; + +import org.hibernate.jpa.boot.scan.spi.AbstractScannerImpl; +import org.osgi.framework.Bundle; + +/** + * OSGi-specific implementation of the Scanner contract. Scans the persistence + * unit Bundle for classes and resources. + * + * @author Brett Meyer + * @author Tim Ward + */ +public class OsgiScanner extends AbstractScannerImpl { + + public OsgiScanner(Bundle persistenceBundle) { + super( new OsgiArchiveDescriptorFactory( persistenceBundle ) ); + } +}