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    /**
040     * @version $Rev: 529834 $ $Date: 2007-04-18 04:32:23 +0200 (Wed, 18 Apr 2007) $
041     */
042    
043    /**
044     * Bootstrap class that is used to obtain {@link javax.persistence.EntityManagerFactory}
045     * references.
046     */
047    public class Persistence {
048    
049        protected static final Set<PersistenceProvider> providers = new HashSet<PersistenceProvider>();
050        // Changed to the hard coded PERSISTENCE_PROVIDER value to pass signature tests.
051        // public static final java.lang.String PERSISTENCE_PROVIDER = PersistenceProvider.class.getName(); 
052        public static final java.lang.String PERSISTENCE_PROVIDER = "javax.persistence.spi.PeristenceProvider";
053        static final String PERSISTENCE_PROVIDER_PROPERTY = "javax.persistence.provider";
054        static final String PERSISTENCE_PROVIDER_SERVICE = "META-INF/services/"
055            + PersistenceProvider.class.getName();
056    
057        /**
058         * Create and return an EntityManagerFactory for the named persistence unit.
059         *
060         * @param persistenceUnitName The name of the persistence unit
061         * @return The factory that creates EntityManagers configured according to the
062         *         specified persistence unit
063         */
064        public static EntityManagerFactory createEntityManagerFactory(
065                String persistenceUnitName) {
066            return createEntityManagerFactory(persistenceUnitName, Collections.EMPTY_MAP);
067                }
068    
069        /**
070         * Create and return an EntityManagerFactory for the named persistence unit using the
071         * given properties.
072         *
073         * @param persistenceUnitName The name of the persistence unit
074         * @param properties          Additional properties to use when creating the factory. The values of
075         *                            these properties override any values that may have been configured
076         *                            elsewhere.
077         * @return The factory that creates EntityManagers configured according to the
078         *         specified persistence unit.
079         */
080        public static EntityManagerFactory createEntityManagerFactory(
081                String persistenceUnitName,
082                Map properties) {
083    
084            if (properties == null) {
085                properties = Collections.EMPTY_MAP;
086            }
087    
088            // start by loading a provider explicitly specified in properties. The spec
089            // doesn't seem to forbid providers that are not deployed as a service
090            Object providerName = properties.get(PERSISTENCE_PROVIDER_PROPERTY);
091            if (providerName instanceof String) {
092                EntityManagerFactory factory = createFactory(
093                        providerName.toString(),
094                        persistenceUnitName,
095                        properties);
096                if (factory != null) {
097                    return factory;
098                }
099            }
100    
101            // load correctly deployed providers
102            ClassLoader loader = Thread.currentThread().getContextClassLoader();
103            try {
104                Enumeration<URL> providers = loader
105                    .getResources(PERSISTENCE_PROVIDER_SERVICE);
106                while (providers.hasMoreElements()) {
107    
108                    String name = getProviderName(providers.nextElement());
109    
110                    if (name != null) {
111    
112                        EntityManagerFactory factory = createFactory(
113                                name,
114                                persistenceUnitName,
115                                properties);
116    
117                        if (factory != null) {
118                            return factory;
119                        }
120                    }
121                }
122            }
123            catch (IOException e) {
124                // spec doesn't mention any exceptions thrown by this method
125            }
126    
127            return null;
128                }
129    
130        static String getProviderName(URL url) throws IOException {
131    
132            BufferedReader in = new BufferedReader(new InputStreamReader(
133                        url.openStream(),
134                        "UTF-8"));
135    
136            String providerName;
137    
138            try {
139                providerName = in.readLine();
140            }
141            finally {
142                in.close();
143            }
144    
145            if (providerName != null) {
146                providerName = providerName.trim();
147            }
148    
149            return providerName;
150        }
151    
152        static EntityManagerFactory createFactory(
153                String providerName,
154                String persistenceUnitName,
155                Map properties)
156            throws PersistenceException {
157    
158            Class providerClass;
159            try {
160                providerClass = Class.forName(providerName, true, Thread
161                        .currentThread().getContextClassLoader());
162            } 
163            catch (Exception e) {
164                throw new PersistenceException(
165                        "Invalid or inaccessible provider class: " + providerName,
166                        e);
167            }
168    
169            try {
170                PersistenceProvider provider = (PersistenceProvider) providerClass
171                    .newInstance();
172                return provider.createEntityManagerFactory(persistenceUnitName,
173                        properties);
174            }
175            catch (Exception e) {
176                throw new PersistenceException("Provider error. Provider: "
177                        + providerName, e);
178            }
179        }
180    }