/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.apache.cayenne.access;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Logger;
import org.apache.cayenne.dba.DbAdapter;
import org.apache.cayenne.dba.TypesMapping;
import org.apache.cayenne.dba.derby.DerbyAdapter;
import org.apache.cayenne.dba.frontbase.FrontBaseAdapter;
import org.apache.cayenne.dba.h2.H2DBAdapter;
import org.apache.cayenne.dba.hsqldb.HSQLDBAdapter;
import org.apache.cayenne.dba.mysql.MySQLAdapter;
import org.apache.cayenne.dba.oracle.OracleAdapter;
import org.apache.cayenne.dba.postgres.PostgresAdapter;
import org.apache.cayenne.map.DataMap;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.wocompat.EOModelProcessor;
import org.openflexo.foundation.cg.CGRepository;
import org.openflexo.foundation.cg.CGSymbolicDirectory;
import org.openflexo.foundation.cg.generator.GeneratedTextResource;
import org.openflexo.foundation.cg.templates.CGTemplate;
import org.openflexo.foundation.dm.eo.DMEOAttribute;
import org.openflexo.foundation.dm.eo.DMEOEntity;
import org.openflexo.foundation.dm.eo.DMEOModel;
import org.openflexo.foundation.dm.eo.DMEOPrototype;
import org.openflexo.foundation.rm.FlexoProject;
import org.openflexo.foundation.rm.ResourceType;
import org.openflexo.foundation.rm.cg.CGRepositoryFileResource;
import org.openflexo.generator.ProjectGenerator;
import org.openflexo.generator.exception.GenerationException;
import org.openflexo.generator.utils.MetaFileGenerator;
import org.openflexo.localization.FlexoLocalization;
import org.openflexo.toolbox.FileFormat;
public class SQLGenerator extends MetaFileGenerator {
protected static final Logger logger = Logger.getLogger(SQLGenerator.class.getPackage().getName());
private DataMap _map;
private DbAdapter _dbAdapter;
private String _connectionString;
private boolean dropTable = true;
public SQLGenerator(ProjectGenerator prjgen, boolean _dropTable) {
super(prjgen, FileFormat.SQL, ResourceType.GENERATED_CODE, (_dropTable ? "re-" : "") + "createDB.sql", (_dropTable ? "re-" : "")
+ "createDB.sql");
dropTable = _dropTable;
resetGenerator();
}
private DataMap buildMergedDataMap(FlexoProject prj) throws Exception {
DataMap datamap = new DataMap();
Enumeration<DMEOModel> en = prj.getDataModel().getAllDMEOModel().elements();
while (en.hasMoreElements()) {
DMEOModel dmeomodel = en.nextElement();
DataMap dataMapToMerge = new EOModelProcessor().loadEOModel(dmeomodel.createTemporaryCopyOfMemory().getAbsolutePath());
datamap.mergeWithDataMap(dataMapToMerge);
}
return datamap;
}
private void resetGenerator() {
_connectionString = getProject().getDataModel().getGlobalDefaultConnectionString();
_dbAdapter = findDBAdapter();
}
private DbAdapter findDBAdapter() {
if (_connectionString == null) {
return null;
}
if (_connectionString.toLowerCase().indexOf("oracle") > -1) {
return new OracleAdapter();
}
if (_connectionString.toLowerCase().indexOf("frontbase") > -1) {
return new FrontBaseAdapter();
}
if (_connectionString.toLowerCase().indexOf("postgres") > -1) {
return new PostgresAdapter();
}
if (_connectionString.toLowerCase().indexOf("mysql") > -1) {
return new MySQLAdapter();
}
if (_connectionString.toLowerCase().indexOf("derby") > -1) {
return new DerbyAdapter();
}
if (_connectionString.toLowerCase().indexOf("hsql") > -1) {
return new HSQLDBAdapter();
}
if (_connectionString.toLowerCase().indexOf("h2") > -1) {
return new H2DBAdapter();
}
return null;
}
private void generateCode() throws GenerationException {
if (getProject().getDataModel().getAllDMEOModel().size() == 0) {
generatedCode = new GeneratedTextResource(getFileName(), "");
return;
}
resetGenerator();
if (_dbAdapter == null) {
throw new GenerationException("Cannot find a suitable DbAdapter for connection string : " + _connectionString);
}
try {
_map = buildMergedDataMap(projectGenerator.getProject());
} catch (Exception e) {
throw new GenerationException("An exception occurs during merge of all models", "error_during_merge_models", "see console", e);
}
try {
incorporatePrototypes();
// DbGenerator dbGenerator = new DbGenerator(_dbAdapter,_map);
MyDBGenerator dbGenerator = new MyDBGenerator(_dbAdapter, _map, Collections.EMPTY_LIST, null, new DBEntityComparator(
getProject()));
dbGenerator.setShouldDropTables(dropTable);
dbGenerator.setShouldCreateTables(true);
dbGenerator.setShouldCreateFKConstraints(true);
dbGenerator.setShouldDropPKSupport(dropTable);
dbGenerator.setShouldCreatePKSupport(true);
// Iterator<DbEntity> en = _map.getDbEntities().iterator();
// while(en.hasNext()){
// System.out.println(en.next().getName());
// }
dbGenerator.buildStatements();
StringBuilder buf = new StringBuilder();
if (_dbAdapter instanceof FrontBaseAdapter) {
buf.append("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, LOCKING PESSIMISTIC;\n\n");
}
Iterator<String> it = dbGenerator.configuredStatements().iterator();
String batchTerminator = dbGenerator.getAdapter().getBatchTerminator();
String lineEnd = batchTerminator != null ? "\n" + batchTerminator + "\n\n" : "\n\n";
while (it.hasNext()) {
buf.append(it.next()).append(lineEnd);
}
generatedCode = new GeneratedTextResource(getFileName(), buf.toString());
} catch (RuntimeException e) {
e.printStackTrace();
throw new GenerationException("sql_generation_error", null, null, e);
}
}
@Override
public String getRelativePath() {
return "";
}
@Override
public CGSymbolicDirectory getSymbolicDirectory(CGRepository repository) {
return repository.getProjectSymbolicDirectory();
}
@Override
public void generate(boolean forceRegenerate) {
try {
if (forceRegenerate || generatedCode == null) {
startGeneration();
refreshSecondaryProgressWindow(FlexoLocalization.localizedForKey("generating") + " " + getIdentifier(), false);
generateCode();
stopGeneration();
}
} catch (GenerationException e) {
setGenerationException(e);
}
}
@Override
public Vector<CGTemplate> getUsedTemplates() {
return new Vector<CGTemplate>();
}
@Override
public boolean isCodeAlreadyGenerated() {
return generatedCode != null;
}
@Override
public boolean needsGeneration() {
return !isCodeAlreadyGenerated();
}
@Override
public boolean needsRegenerationBecauseOfTemplateUpdated() {
return false;
}
@Override
public boolean needsRegenerationBecauseOfTemplateUpdated(Date diskLastGenerationDate) {
return false;
}
@Override
public Vector<CGRepositoryFileResource> refreshConcernedResources() {
// TODO Auto-generated method stub
return null;
}
@Override
public Logger getGeneratorLogger() {
return logger;
}
private void incorporatePrototypes() {
Iterator<DbEntity> entityIterator = _map.getDbEntities().iterator();
DbEntity entity = null;
DbAttribute attribute = null;
DMEOPrototype prototype = null;
DMEOAttribute dmeoattribute = null;
while (entityIterator.hasNext()) {
entity = entityIterator.next();
Iterator<DbAttribute> attributeIterator = entity.getAttributes().iterator();
while (attributeIterator.hasNext()) {
attribute = attributeIterator.next();
dmeoattribute = matchingDMEOAttribute(entity, attribute);
if (dmeoattribute != null) {
attribute.setMandatory(!dmeoattribute.getAllowsNull());
prototype = dmeoattribute.getPrototype();
if (prototype != null) {
String externalType = prototype.getExternalType();
if ("CHAR VARYING".equals(externalType)) {
externalType = "VARCHAR";
}
if ("CHARACTER".equals(externalType)) {
externalType = "CHAR";
}
if ("DOUBLE PRECISION".equals(externalType)) {
externalType = "DOUBLE";
}
if ("INT".equals(externalType)) {
externalType = "INTEGER";
}
int sqlType = TypesMapping.getSqlTypeByName(externalType);
if (attribute.getMaxLength() < 1 && prototype.getWidth() > 0) {
attribute.setMaxLength(prototype.getWidth());
}
attribute.setType(sqlType);
}
}
}
}
}
private DMEOAttribute matchingDMEOAttribute(DbEntity entity, DbAttribute attribute) {
DMEOAttribute reply = null;
DMEOEntity dmeoentity = findDMEOEntityWithName(entity.getName());
if (dmeoentity != null) {
reply = findDMEOAttributeWithName(dmeoentity, attribute.getName());
} else {
logger.warning("cannot find the matching entity for :" + entity.getName());
}
return reply;
}
private DMEOAttribute findDMEOAttributeWithName(DMEOEntity dmeoentity, String attributeName) {
Iterator<DMEOAttribute> en = dmeoentity.getAttributes().values().iterator();
DMEOAttribute candidate = null;
while (en.hasNext()) {
candidate = en.next();
if (candidate.getColumnName() != null && candidate.getColumnName().equals(attributeName)) {
return candidate;
}
}
return null;
}
private DMEOEntity findDMEOEntityWithName(String entityName) {
Enumeration<DMEOModel> en = getProject().getDataModel().getAllDMEOModel().elements();
DMEOEntity candidate = null;
DMEOModel model = null;
while (en.hasMoreElements()) {
model = en.nextElement();
Enumeration<DMEOEntity> en2 = model.getEntities().elements();
while (en2.hasMoreElements()) {
candidate = en2.nextElement();
if (candidate.getExternalName() != null && candidate.getExternalName().equals(entityName)) {
return candidate;
}
}
}
return null;
}
}