blob: ecf0f8c190692fc95587b27684ec1738732f8e92 [file] [log] [blame]
/*
* 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.openjpa.jdbc.kernel;
import static org.apache.openjpa.conf.SchemaGenerationAction.CREATE;
import static org.apache.openjpa.conf.SchemaGenerationAction.DROP;
import static org.apache.openjpa.conf.SchemaGenerationAction.DROP_AND_CREATE;
import static org.apache.openjpa.conf.SchemaGenerationSource.METADATA;
import static org.apache.openjpa.conf.SchemaGenerationSource.METADATA_THEN_SCRIPT;
import static org.apache.openjpa.conf.SchemaGenerationSource.SCRIPT;
import static org.apache.openjpa.conf.SchemaGenerationSource.SCRIPT_THEN_METADATA;
import static org.apache.openjpa.jdbc.meta.MappingTool.ACTION_ADD;
import static org.apache.openjpa.jdbc.meta.MappingTool.ACTION_DROP;
import static org.apache.openjpa.jdbc.meta.MappingTool.ACTION_SCRIPT_CREATE;
import static org.apache.openjpa.jdbc.meta.MappingTool.ACTION_SCRIPT_DROP;
import static org.apache.openjpa.jdbc.meta.MappingTool.ACTION_SCRIPT_LOAD;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import org.apache.openjpa.conf.SchemaGenerationSource;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl;
import org.apache.openjpa.jdbc.meta.MappingRepository;
import org.apache.openjpa.jdbc.meta.MappingTool;
import org.apache.openjpa.kernel.AbstractBrokerFactory;
import org.apache.openjpa.kernel.Bootstrap;
import org.apache.openjpa.kernel.BrokerImpl;
import org.apache.openjpa.kernel.StoreManager;
import org.apache.openjpa.lib.conf.ConfigurationProvider;
import org.apache.openjpa.lib.conf.Configurations;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.lib.util.StringUtil;
import org.apache.openjpa.util.UserException;
/**
* BrokerFactory type for use with the JDBC runtime.
*
* @author Abe White
* @author Marc Prud'hommeaux
*/
public class JDBCBrokerFactory extends AbstractBrokerFactory {
private static final long serialVersionUID = 1L;
private static final Localizer _loc = Localizer.forPackage
(JDBCBrokerFactory.class);
private boolean _synchronizedMappings = false;
/**
* Factory method for constructing a factory from properties. Invoked from
* {@link Bootstrap#newBrokerFactory}.
*/
public static JDBCBrokerFactory newInstance(ConfigurationProvider cp) {
JDBCConfigurationImpl conf = new JDBCConfigurationImpl();
cp.setInto(conf);
return new JDBCBrokerFactory(conf);
}
/**
* Factory method for obtaining a possibly-pooled factory from properties.
* Invoked from {@link Bootstrap#getBrokerFactory}.
*/
public static JDBCBrokerFactory getInstance(ConfigurationProvider cp, ClassLoader loader) {
Map<String, Object> props = cp.getProperties();
Object key = toPoolKey(props);
JDBCBrokerFactory factory = (JDBCBrokerFactory) getPooledFactoryForKey(key);
if (factory != null)
return factory;
// The creation of all BrokerFactories should be driven through Bootstrap.
factory = (JDBCBrokerFactory) Bootstrap.newBrokerFactory(cp, loader);
pool(key, factory);
return factory;
}
/**
* Construct the factory with the given option settings; however, the
* factory construction methods are recommended.
*/
public JDBCBrokerFactory(JDBCConfiguration conf) {
super(conf);
}
@Override
public Map<String,Object> getProperties() {
// add platform property
Map<String,Object> props = super.getProperties();
String db = "Unknown";
try {
JDBCConfiguration conf = (JDBCConfiguration) getConfiguration();
db = conf.getDBDictionaryInstance().platform;
} catch (RuntimeException re) {
}
props.put("Platform", "OpenJPA JDBC Edition: " + db + " Database");
return props;
}
@Override
public void postCreationCallback() {
super.postCreationCallback();
}
@Override
protected StoreManager newStoreManager() {
return new JDBCStoreManager();
}
@Override
protected BrokerImpl newBrokerImpl(String user, String pass) {
BrokerImpl broker = super.newBrokerImpl(user, pass);
lock();
try {
// synchronize mappings; we wait until now to do this so that
// we can use the first broker user/pass for connection if no
// global login is given
if (!_synchronizedMappings) {
_synchronizedMappings = true;
synchronizeMappings(broker.getClassLoader());
}
return broker;
} finally {
unlock();
}
}
/**
* Synchronize the mappings of the classes listed in the configuration.
*/
protected boolean synchronizeMappings(ClassLoader loader,
JDBCConfiguration conf) {
mapSchemaGenerationToSynchronizeMappings(conf);
String action = conf.getSynchronizeMappings();
if (StringUtil.isEmpty(action))
return false;
MappingRepository repo = conf.getMappingRepositoryInstance();
Collection<Class<?>> classes = repo.loadPersistentTypes(false, loader);
if (classes.isEmpty())
return false;
String props = Configurations.getProperties(action);
action = Configurations.getClassName(action);
MappingTool tool = new MappingTool(conf, action, false, loader);
Configurations.configureInstance(tool, conf, props,
"SynchronizeMappings");
// initialize the schema
for (Class<?> cls : classes) {
try {
tool.run(cls);
} catch (IllegalArgumentException iae) {
throw new UserException(_loc.get("bad-synch-mappings",
action, Arrays.asList(MappingTool.ACTIONS)));
}
}
tool.record();
return true; // todo: check?
}
protected boolean synchronizeMappings(ClassLoader loader) {
return synchronizeMappings(loader, (JDBCConfiguration) getConfiguration());
}
private void mapSchemaGenerationToSynchronizeMappings(JDBCConfiguration conf) {
String actions = "";
if (conf.getDatabaseAction() != null) {
int databaseAction = conf.getDatabaseActionConstant();
if (databaseAction == CREATE) {
actions = generateSchemaCreation(conf);
} else if (databaseAction == DROP) {
actions = generateSchemaDrop(conf);
} else if (databaseAction == DROP_AND_CREATE) {
actions = generateSchemaDropCreate(conf);
}
}
String loadFile = conf.getLoadScriptSource();
if (loadFile != null) {
actions += "," + ACTION_SCRIPT_LOAD;
}
if (actions.length() > 0) {
conf.setSynchronizeMappings("buildSchema(ForeignKeys=true,SchemaAction='" + actions + "')");
}
}
private String generateSchemaCreation(JDBCConfiguration conf) {
if (conf.getCreateScriptTarget() != null) {
return MappingTool.ACTION_ADD;
} else {
int createSource = conf.getCreateSourceConstant();
if (createSource == SchemaGenerationSource.NONE && conf.getCreateScriptSource() != null) {
createSource = SCRIPT;
} else {
createSource = METADATA;
}
return mapGenerationStrategyActions(createSource, ACTION_ADD, ACTION_SCRIPT_CREATE);
}
}
private String generateSchemaDrop(JDBCConfiguration conf) {
if (conf.getDropScriptTarget() != null) {
return MappingTool.ACTION_DROP;
} else {
int dropSource = conf.getDropSourceConstant();
if (dropSource == SchemaGenerationSource.NONE && conf.getDropScriptSource() != null) {
dropSource = SCRIPT;
} else {
dropSource = METADATA;
}
return mapGenerationStrategyActions(dropSource, ACTION_DROP, ACTION_SCRIPT_DROP);
}
}
private String generateSchemaDropCreate(JDBCConfiguration conf) {
if (conf.getCreateScriptTarget() != null && conf.getDropScriptTarget() != null) {
return MappingTool.ACTION_ADD + "," + MappingTool.ACTION_DROP;
} else {
return mapGenerationStrategyActions(conf.getDropSourceConstant(), ACTION_DROP, ACTION_SCRIPT_DROP) + "," +
mapGenerationStrategyActions(conf.getCreateSourceConstant(), ACTION_ADD, ACTION_SCRIPT_CREATE);
}
}
private String mapGenerationStrategyActions(int source, String metadataAction, String scriptAction) {
String actions = "";
if (source == METADATA) {
actions += metadataAction;
} else if (source == SCRIPT) {
actions += scriptAction;
} else if (source == METADATA_THEN_SCRIPT) {
actions += metadataAction + "," + scriptAction;
} else if (source == SCRIPT_THEN_METADATA) {
actions += scriptAction + "," + metadataAction;
} else {
actions += metadataAction;
}
return actions;
}
}