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: package org.apache.openjpa.persistence;
020:
021: import java.lang.instrument.ClassFileTransformer;
022: import java.lang.instrument.IllegalClassFormatException;
023: import java.security.ProtectionDomain;
024: import java.util.Map;
025: import javax.persistence.EntityManager;
026: import javax.persistence.spi.ClassTransformer;
027: import javax.persistence.spi.PersistenceProvider;
028: import javax.persistence.spi.PersistenceUnitInfo;
029:
030: import org.apache.openjpa.conf.BrokerValue;
031: import org.apache.openjpa.conf.OpenJPAConfiguration;
032: import org.apache.openjpa.conf.OpenJPAConfigurationImpl;
033: import org.apache.openjpa.enhance.PCClassFileTransformer;
034: import org.apache.openjpa.kernel.Bootstrap;
035: import org.apache.openjpa.kernel.BrokerFactory;
036: import org.apache.openjpa.lib.conf.Configuration;
037: import org.apache.openjpa.lib.conf.ConfigurationProvider;
038: import org.apache.openjpa.lib.conf.Configurations;
039: import org.apache.openjpa.lib.log.Log;
040: import org.apache.openjpa.lib.util.Localizer;
041: import org.apache.openjpa.meta.MetaDataModes;
042: import org.apache.openjpa.meta.MetaDataRepository;
043: import org.apache.openjpa.util.ClassResolver;
044:
045: /**
046: * Bootstrapping class that allows the creation of a stand-alone
047: * {@link EntityManager}.
048: *
049: * @see javax.persistence.Persistence#createEntityManagerFactory(String,Map)
050: * @published
051: */
052: public class PersistenceProviderImpl implements PersistenceProvider {
053:
054: static final String CLASS_TRANSFORMER_OPTIONS = "ClassTransformerOptions";
055: private static final String EMF_POOL = "EntityManagerFactoryPool";
056:
057: private static final Localizer _loc = Localizer
058: .forPackage(PersistenceProviderImpl.class);
059:
060: /**
061: * Loads the entity manager specified by <code>name</code>, applying
062: * the properties in <code>m</code> as overrides to the properties defined
063: * in the XML configuration file for <code>name</code>. If <code>name</code>
064: * is <code>null</code>, this method loads the XML in the resource
065: * identified by <code>resource</code>, and uses the first resource found
066: * when doing this lookup, regardless of the name specified in the XML
067: * resource or the name of the jar that the resource is contained in.
068: * This does no pooling of EntityManagersFactories.
069: */
070: public OpenJPAEntityManagerFactory createEntityManagerFactory(
071: String name, String resource, Map m) {
072: PersistenceProductDerivation pd = new PersistenceProductDerivation();
073: try {
074: Object poolValue = Configurations.removeProperty(EMF_POOL,
075: m);
076: ConfigurationProvider cp = pd.load(resource, name, m);
077: if (cp == null)
078: return null;
079:
080: BrokerFactory factory = getBrokerFactory(cp, poolValue,
081: null);
082: return JPAFacadeHelper.toEntityManagerFactory(factory);
083: } catch (Exception e) {
084: throw PersistenceExceptions.toPersistenceException(e);
085: }
086: }
087:
088: private BrokerFactory getBrokerFactory(ConfigurationProvider cp,
089: Object poolValue, ClassLoader loader) {
090: // handle "true" and "false"
091: if (poolValue instanceof String
092: && ("true".equalsIgnoreCase((String) poolValue) || "false"
093: .equalsIgnoreCase((String) poolValue)))
094: poolValue = Boolean.valueOf((String) poolValue);
095:
096: if (poolValue != null && !(poolValue instanceof Boolean)) {
097: // we only support boolean settings for this option currently.
098: throw new IllegalArgumentException(poolValue.toString());
099: }
100:
101: if (poolValue == null || !((Boolean) poolValue).booleanValue())
102: return Bootstrap.newBrokerFactory(cp, loader);
103: else
104: return Bootstrap.getBrokerFactory(cp, loader);
105: }
106:
107: public OpenJPAEntityManagerFactory createEntityManagerFactory(
108: String name, Map m) {
109: return createEntityManagerFactory(name, null, m);
110: }
111:
112: public OpenJPAEntityManagerFactory createContainerEntityManagerFactory(
113: PersistenceUnitInfo pui, Map m) {
114: PersistenceProductDerivation pd = new PersistenceProductDerivation();
115: try {
116: Object poolValue = Configurations.removeProperty(EMF_POOL,
117: m);
118: ConfigurationProvider cp = pd.load(pui, m);
119: if (cp == null)
120: return null;
121:
122: // add enhancer
123: Exception transformerException = null;
124: String ctOpts = (String) Configurations.getProperty(
125: CLASS_TRANSFORMER_OPTIONS, pui.getProperties());
126: try {
127: pui.addTransformer(new ClassTransformerImpl(cp, ctOpts,
128: pui.getNewTempClassLoader(),
129: newConfigurationImpl()));
130: } catch (Exception e) {
131: // fail gracefully
132: transformerException = e;
133: }
134:
135: // if the BrokerImpl hasn't been specified, switch to the
136: // non-finalizing one, since anything claiming to be a container
137: // should be doing proper resource management.
138: if (!Configurations.containsProperty(BrokerValue.KEY, cp
139: .getProperties())) {
140: cp.addProperty("openjpa." + BrokerValue.KEY,
141: getDefaultBrokerAlias());
142: }
143:
144: BrokerFactory factory = getBrokerFactory(cp, poolValue, pui
145: .getClassLoader());
146: if (transformerException != null) {
147: Log log = factory.getConfiguration().getLog(
148: OpenJPAConfiguration.LOG_RUNTIME);
149: if (log.isTraceEnabled()) {
150: log.warn(_loc.get(
151: "transformer-registration-error-ex", pui),
152: transformerException);
153: } else {
154: log.warn(_loc.get("transformer-registration-error",
155: pui));
156: }
157: }
158: return JPAFacadeHelper.toEntityManagerFactory(factory);
159: } catch (Exception e) {
160: throw PersistenceExceptions.toPersistenceException(e);
161: }
162: }
163:
164: /*
165: * Returns a default Broker alias to be used when no openjpa.BrokerImpl
166: * is specified. This method allows PersistenceProvider subclass to
167: * override the default broker alias.
168: */
169: protected String getDefaultBrokerAlias() {
170: return BrokerValue.NON_FINALIZING_ALIAS;
171: }
172:
173: /*
174: * Return a new instance of Configuration subclass used by entity
175: * enhancement in ClassTransformerImpl. If OpenJPAConfigurationImpl
176: * instance is used, configuration options declared in configuration
177: * sub-class will not be recognized and a warning is posted in the log.
178: */
179: protected OpenJPAConfiguration newConfigurationImpl() {
180: return new OpenJPAConfigurationImpl();
181: }
182:
183: /**
184: * Java EE 5 class transformer.
185: */
186: private static class ClassTransformerImpl implements
187: ClassTransformer {
188:
189: private final ClassFileTransformer _trans;
190:
191: private ClassTransformerImpl(ConfigurationProvider cp,
192: String props, final ClassLoader tmpLoader,
193: OpenJPAConfiguration conf) {
194: cp.setInto(conf);
195: // don't allow connections
196: conf.setConnectionUserName(null);
197: conf.setConnectionPassword(null);
198: conf.setConnectionURL(null);
199: conf.setConnectionDriverName(null);
200: conf.setConnectionFactoryName(null);
201: // use the tmp loader for everything
202: conf.setClassResolver(new ClassResolver() {
203: public ClassLoader getClassLoader(Class context,
204: ClassLoader env) {
205: return tmpLoader;
206: }
207: });
208: conf.setReadOnly(Configuration.INIT_STATE_FREEZING);
209:
210: MetaDataRepository repos = conf
211: .getMetaDataRepositoryInstance();
212: repos.setResolve(MetaDataModes.MODE_MAPPING, false);
213: _trans = new PCClassFileTransformer(repos, Configurations
214: .parseProperties(props), tmpLoader);
215: }
216:
217: public byte[] transform(ClassLoader cl, String name,
218: Class<?> previousVersion, ProtectionDomain pd,
219: byte[] bytes) throws IllegalClassFormatException {
220: return _trans.transform(cl, name, previousVersion, pd,
221: bytes);
222: }
223: }
224: }
|