001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *  http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    
020    //
021    // This source code implements specifications defined by the Java
022    // Community Process. In order to remain compliant with the specification
023    // DO NOT add / change / or delete method signatures!
024    //
025    package javax.persistence;
026    
027    import java.io.BufferedReader;
028    import java.io.IOException;
029    import java.io.InputStreamReader;
030    import java.net.URL;
031    import java.util.Collections;
032    import java.util.Enumeration;
033    import java.util.Map;
034    import java.util.HashSet;
035    import java.util.Set;
036    
037    import javax.persistence.spi.PersistenceProvider;
038    /**
039     * @version $Rev$ $Date$
040     */
041    
042    /**
043     * Bootstrap class that is used to obtain {@link javax.persistence.EntityManagerFactory}
044     * references.
045     */
046    public class Persistence {
047    
048        protected static final Set<PersistenceProvider> providers = new HashSet<PersistenceProvider>();
049        // Changed to the hard coded PERSISTENCE_PROVIDER value to pass signature tests.
050        // public static final java.lang.String PERSISTENCE_PROVIDER = PersistenceProvider.class.getName(); 
051        public static final java.lang.String PERSISTENCE_PROVIDER = "javax.persistence.spi.PeristenceProvider";
052        static final String PERSISTENCE_PROVIDER_PROPERTY = "javax.persistence.provider";
053        static final String PERSISTENCE_PROVIDER_SERVICE = "META-INF/services/"
054            + PersistenceProvider.class.getName();
055        /**
056         * Create and return an EntityManagerFactory for the named persistence unit.
057         *
058         * @param persistenceUnitName The name of the persistence unit
059         * @return The factory that creates EntityManagers configured according to the
060         *         specified persistence unit
061         */
062        public static EntityManagerFactory createEntityManagerFactory(
063                String persistenceUnitName) {
064            return createEntityManagerFactory(persistenceUnitName, Collections.EMPTY_MAP);
065                }
066    
067        /**
068         * Create and return an EntityManagerFactory for the named persistence unit using the
069         * given properties.
070         *
071         * @param persistenceUnitName The name of the persistence unit
072         * @param properties          Additional properties to use when creating the factory. The values of
073         *                            these properties override any values that may have been configured
074         *                            elsewhere.
075         * @return The factory that creates EntityManagers configured according to the
076         *         specified persistence unit.
077         */
078        public static EntityManagerFactory createEntityManagerFactory(
079                String persistenceUnitName,
080                Map properties) {
081    
082            if (properties == null) {
083                properties = Collections.EMPTY_MAP;
084            }
085    
086            // start by loading a provider explicitly specified in properties. The spec
087            // doesn't seem to forbid providers that are not deployed as a service
088            Object providerName = properties.get(PERSISTENCE_PROVIDER_PROPERTY);
089            if (providerName instanceof String) {
090                EntityManagerFactory factory = createFactory(
091                        providerName.toString(),
092                        persistenceUnitName,
093                        properties);
094                if (factory != null) {
095                    return factory;
096                }
097            }
098             
099            //If we are deployed into an OSGi environment, leverage it
100            Class providerClass = org.apache.servicemix.specs.locator.OsgiLocator.locate("javax.persistence.spi.PersistenceProvider");
101            if (providerClass != null) {
102                try {
103                    PersistenceProvider provider = (PersistenceProvider) providerClass
104                        .newInstance();
105                    return provider.createEntityManagerFactory(persistenceUnitName,
106                        properties);
107                }
108                catch (Exception e) {
109                    throw new PersistenceException("Provider error. Provider: "
110                        + providerName, e);
111                } 
112            }
113    
114            // load correctly deployed providers
115            ClassLoader loader = Thread.currentThread().getContextClassLoader();
116            try {
117                Enumeration<URL> providers = loader
118                    .getResources(PERSISTENCE_PROVIDER_SERVICE);
119                while (providers.hasMoreElements()) {
120    
121                    String name = getProviderName(providers.nextElement());
122    
123                    if (name != null) {
124    
125                        EntityManagerFactory factory = createFactory(
126                                name,
127                                persistenceUnitName,
128                                properties);
129    
130                        if (factory != null) {
131                            return factory;
132                        }
133                    }
134                }
135            }
136            catch (IOException e) {
137                // spec doesn't mention any exceptions thrown by this method
138            }
139    
140            return null;
141        }
142    
143        static String getProviderName(URL url) throws IOException {
144    
145            BufferedReader in = new BufferedReader(new InputStreamReader(
146                        url.openStream(),
147                        "UTF-8"));
148    
149            String providerName;
150    
151            try {
152                providerName = in.readLine();
153            }
154            finally {
155                in.close();
156            }
157    
158            if (providerName != null) {
159                providerName = providerName.trim();
160            }
161    
162            return providerName;
163        }
164    
165        static EntityManagerFactory createFactory(
166                String providerName,
167                String persistenceUnitName,
168                Map properties)
169            throws PersistenceException {
170    
171            Class providerClass;
172            try {
173                providerClass = Class.forName(providerName, true, Thread
174                        .currentThread().getContextClassLoader());
175            } 
176            catch (Exception e) {
177                throw new PersistenceException(
178                        "Invalid or inaccessible provider class: " + providerName,
179                        e);
180            }
181    
182            try {
183                PersistenceProvider provider = (PersistenceProvider) providerClass
184                    .newInstance();
185                return provider.createEntityManagerFactory(persistenceUnitName,
186                        properties);
187            }
188            catch (Exception e) {
189                throw new PersistenceException("Provider error. Provider: "
190                        + providerName, e);
191            }
192        }
193    }
194