Refactored internal api
This commit is contained in:
parent
3f31bb8a3a
commit
6ccd763d1f
361 changed files with 23049 additions and 4498 deletions
|
|
@ -61,9 +61,6 @@ public class JdbcConnectionProviderJdniImpl implements JdbcConnectionProvider {
|
|||
|
||||
try {
|
||||
Context initialContext = new InitialContext();
|
||||
if ( initialContext == null ) {
|
||||
throw new SQLException("Cannot get Initial Context");
|
||||
}
|
||||
DataSource datasource = (DataSource)initialContext.lookup(dataSourceContext+name);
|
||||
if ( datasource == null ) {
|
||||
throw new SQLException("Cannot lookup datasource: "+name);
|
||||
|
|
|
|||
|
|
@ -51,10 +51,19 @@ public class JdbcVascBackend extends AbstractVascBackend {
|
|||
|
||||
private JdbcConnectionProvider jdbcConnectionProvider = null;
|
||||
private String sqlList = null;
|
||||
private String idColumn = null;
|
||||
private String sqlDelete = null;
|
||||
private String sqlUpdate = null;
|
||||
private String sqlInsert = null;
|
||||
//private String idColumn = null;
|
||||
//private String sqlDelete = null;
|
||||
//private String sqlUpdate = null;
|
||||
//private String sqlInsert = null;
|
||||
|
||||
|
||||
/**
|
||||
* @see net.forwardfire.vasc.backend.AbstractVascBackend#isReadOnly()
|
||||
*/
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JdbcConnectionProvider
|
||||
|
|
|
|||
|
|
@ -54,6 +54,14 @@ public class JdbcVascBackendXpql extends AbstractVascBackend {
|
|||
|
||||
private net.forwardfire.vasc.xpql.query.Query query = null;
|
||||
|
||||
/**
|
||||
* @see net.forwardfire.vasc.backend.AbstractVascBackend#isReadOnly()
|
||||
*/
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JdbcConnectionProvider
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -19,13 +19,13 @@
|
|||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>${persistence-api.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-annotations</artifactId>
|
||||
<version>3.4.0.GA</version>
|
||||
<version>${hibernate-annotations.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,19 @@
|
|||
<dependency>
|
||||
<groupId>org.eobjects.metamodel</groupId>
|
||||
<artifactId>MetaModel-full</artifactId>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
<version>${metamodel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>${h2.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>${postgresql.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2007-2012 forwardfire.net All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
|
||||
* the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.forwardfire.vasc.backend.metamodel;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
|
||||
/**
|
||||
* MetaModelDataContextJndiDataContext provides a data context from jndi.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 22, 2012
|
||||
*/
|
||||
public class MetaModelDataContextJndiDataContext implements MetaModelDataContextProvider {
|
||||
|
||||
private String jndiName = null;
|
||||
|
||||
public DataContext getDataContext() {
|
||||
return getDataContextJndi();
|
||||
}
|
||||
|
||||
private DataContext getDataContextJndi() {
|
||||
try {
|
||||
InitialContext context = new InitialContext();
|
||||
DataContext dataContext = (DataContext)context.lookup(jndiName);
|
||||
if (dataContext == null) {
|
||||
throw new NullPointerException("Cannot lookup dataContext: "+jndiName);
|
||||
}
|
||||
return dataContext;
|
||||
} catch (NamingException e) {
|
||||
throw new IllegalStateException("Naming error:"+e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jndiName
|
||||
*/
|
||||
public String getJndiName() {
|
||||
return jndiName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jndiName the jndiName to set
|
||||
*/
|
||||
public void setJndiName(String jndiName) {
|
||||
this.jndiName = jndiName;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2007-2012 forwardfire.net All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
|
||||
* the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.forwardfire.vasc.backend.metamodel;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.jdbc.JdbcDataContext;
|
||||
|
||||
/**
|
||||
* MetaModelDataContextJndiDataSource provides a connection from datasource for meta model data context.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 15, 2012
|
||||
*/
|
||||
public class MetaModelDataContextJndiDataSource implements MetaModelDataContextProvider {
|
||||
|
||||
private String jndiName = null;
|
||||
|
||||
public DataContext getDataContext() {
|
||||
JdbcDataContext dataContext = new JdbcDataContext(getDataSource());
|
||||
return dataContext;
|
||||
}
|
||||
|
||||
private DataSource getDataSource() {
|
||||
try {
|
||||
InitialContext context = new InitialContext();
|
||||
DataSource datasource = (DataSource)context.lookup(jndiName);
|
||||
if (datasource == null) {
|
||||
throw new NullPointerException("Cannot lookup datasource: "+jndiName);
|
||||
}
|
||||
return datasource;
|
||||
} catch (NamingException e) {
|
||||
throw new IllegalStateException("Naming error:"+e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jndiName
|
||||
*/
|
||||
public String getJndiName() {
|
||||
return jndiName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jndiName the jndiName to set
|
||||
*/
|
||||
public void setJndiName(String jndiName) {
|
||||
this.jndiName = jndiName;
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ import java.net.UnknownHostException;
|
|||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.mongodb.MongoDbDataContext;
|
||||
import org.eobjects.metamodel.mongodb.MongoDbDataContextBean;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.Mongo;
|
||||
|
|
@ -48,10 +49,15 @@ public class MetaModelDataContextMongodb implements MetaModelDataContextProvider
|
|||
private boolean readonly = false;
|
||||
|
||||
protected Mongo mongo = null;
|
||||
//protected DB db = null;
|
||||
|
||||
public DataContext getDataContext() {
|
||||
MongoDbDataContext dataContext = new MongoDbDataContext(getMongodbConnection());
|
||||
MongoDbDataContextBean dataContext = new MongoDbDataContextBean(getMongodbConnection());
|
||||
dataContext.setRegisterMBean(true);
|
||||
dataContext.start();
|
||||
//MongoDbDataContextSchemaDetector detector = new MongoDbDataContextSchemaDetector();
|
||||
//detector.setDataCheckSize(10);
|
||||
//detector.setSearchReference(true);
|
||||
//DataContext dataContext = detector.new MongoDbDataContextExtended(getMongodbConnection(),detector);
|
||||
return dataContext;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2007-2012 forwardfire.net All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
|
||||
* the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.forwardfire.vasc.backend.metamodel;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.xml.XmlDomDataContext;
|
||||
|
||||
/**
|
||||
* MetaModelDataContextXmlDom provides basic auto xml editing support.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 20, 2012
|
||||
*/
|
||||
public class MetaModelDataContextXmlDom implements MetaModelDataContextProvider {
|
||||
|
||||
private String file = null;
|
||||
private boolean autoFlattenTables = true;
|
||||
|
||||
|
||||
public DataContext getDataContext() {
|
||||
if (file==null) {
|
||||
throw new NullPointerException("Can's provided data context with null file.");
|
||||
}
|
||||
XmlDomDataContext dataContext = new XmlDomDataContext(new File(file),autoFlattenTables);
|
||||
return dataContext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the file
|
||||
*/
|
||||
public String getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param file the file to set
|
||||
*/
|
||||
public void setFile(String file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the autoFlattenTables
|
||||
*/
|
||||
public boolean isAutoFlattenTables() {
|
||||
return autoFlattenTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param autoFlattenTables the autoFlattenTables to set
|
||||
*/
|
||||
public void setAutoFlattenTables(boolean autoFlattenTables) {
|
||||
this.autoFlattenTables = autoFlattenTables;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright 2007-2012 forwardfire.net All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
|
||||
* the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.forwardfire.vasc.backend.metamodel;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.xml.XmlSaxDataContext;
|
||||
import org.eobjects.metamodel.xml.XmlSaxTableDef;
|
||||
|
||||
/**
|
||||
* MetaModelDataContextXml provides basic xml editing support.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 3, 2012
|
||||
*/
|
||||
public class MetaModelDataContextXmlSax implements MetaModelDataContextProvider {
|
||||
|
||||
private String file = null;
|
||||
private List<XmlSaxTableDef> tableSchemas = null;
|
||||
|
||||
public MetaModelDataContextXmlSax() {
|
||||
tableSchemas = new ArrayList<XmlSaxTableDef>(5);
|
||||
}
|
||||
|
||||
public DataContext getDataContext() {
|
||||
if (file==null) {
|
||||
throw new NullPointerException("Can's provided data context with null file.");
|
||||
}
|
||||
if (tableSchemas.isEmpty()) {
|
||||
throw new IllegalStateException("Can't provided data context with zero table schemas.");
|
||||
}
|
||||
XmlSaxTableDef[] args = new XmlSaxTableDef[tableSchemas.size()];
|
||||
XmlSaxDataContext dataContext = new XmlSaxDataContext(new File(file),tableSchemas.toArray(args));
|
||||
return dataContext;
|
||||
}
|
||||
|
||||
public void addTableSchema(XmlSaxTableDef tableSchema) {
|
||||
tableSchemas.add(tableSchema);
|
||||
}
|
||||
|
||||
public void removeTableSchema(XmlSaxTableDef tableSchema) {
|
||||
tableSchemas.remove(tableSchema);
|
||||
}
|
||||
|
||||
public List<XmlSaxTableDef> getTableSchemas() {
|
||||
return tableSchemas;
|
||||
}
|
||||
|
||||
public void setFile(String file) {
|
||||
this.file=file;
|
||||
}
|
||||
|
||||
public String getFile() {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
|
@ -33,14 +33,13 @@ import net.forwardfire.vasc.backend.VascBackendControllerLocal;
|
|||
import net.forwardfire.vasc.core.VascController;
|
||||
import net.forwardfire.vasc.core.VascEntry;
|
||||
import net.forwardfire.vasc.core.VascEntryControllerLocal;
|
||||
import net.forwardfire.vasc.core.VascEntryField;
|
||||
import net.forwardfire.vasc.core.VascLinkEntry;
|
||||
import net.forwardfire.vasc.core.VascLinkEntryType;
|
||||
import net.forwardfire.vasc.core.VascEntryFieldLocal;
|
||||
import net.forwardfire.vasc.core.VascEntryLinkType;
|
||||
import net.forwardfire.vasc.core.VascEntryLocal;
|
||||
|
||||
import net.forwardfire.vasc.impl.DefaultVascEntry;
|
||||
import net.forwardfire.vasc.impl.DefaultVascEntryField;
|
||||
import net.forwardfire.vasc.impl.DefaultVascFactory;
|
||||
import net.forwardfire.vasc.impl.DefaultVascLinkEntry;
|
||||
import net.forwardfire.vasc.impl.DefaultVascEntryLink;
|
||||
import net.forwardfire.vasc.impl.ui.VascSelectItemModelEntry;
|
||||
|
||||
/**
|
||||
|
|
@ -74,11 +73,11 @@ public class MetaModelSchemaAutoEntry {
|
|||
DataContext ds = getDataContextProvider().getDataContext();
|
||||
for (String table:ds.getDefaultSchema().getTableNames()) {
|
||||
if (getTableInclude()!=null && table.matches(getTableInclude())==false) {
|
||||
logger.fine("Excluding table: "+table+" from include rule.");
|
||||
logger.finer("Excluding table: "+table+" from include rule.");
|
||||
continue;
|
||||
}
|
||||
if (getTableExclude()!=null && table.matches(getTableExclude())) {
|
||||
logger.fine("Excluding table: "+table+" from exclude rule.");
|
||||
logger.finer("Excluding table: "+table+" from exclude rule.");
|
||||
continue;
|
||||
}
|
||||
createMetaEntry(ds,getEntryPrefix()+"_"+table,table);
|
||||
|
|
@ -90,7 +89,7 @@ public class MetaModelSchemaAutoEntry {
|
|||
}
|
||||
|
||||
private void createMetaEntry(DataContext ds,String id,String tableName) {
|
||||
logger.info("Creating entry id: "+id+" of table: "+tableName);
|
||||
logger.fine("Creating entry id: "+id+" of table: "+tableName);
|
||||
Table metaTable = null;
|
||||
if (tableName==null) {
|
||||
metaTable = ds.getDefaultSchema().getTable(0);
|
||||
|
|
@ -114,7 +113,7 @@ public class MetaModelSchemaAutoEntry {
|
|||
//TODO backend.setRequestReadOnly(true);
|
||||
}
|
||||
|
||||
VascEntry ve = new DefaultVascEntry();
|
||||
DefaultVascEntry ve = new DefaultVascEntry();
|
||||
ve.setId(id);
|
||||
ve.setBackendId(id+"_backend");
|
||||
ve.setPrimaryKeyFieldId(backend.getTableId());
|
||||
|
|
@ -123,10 +122,10 @@ public class MetaModelSchemaAutoEntry {
|
|||
for (Relationship rs:metaTable.getRelationships()) {
|
||||
logger.finer("Found relation FT: "+rs.getForeignTable().getName()+" PT: "+rs.getPrimaryTable().getName());
|
||||
if (tableName.equals(rs.getForeignTable().getName())==false) {
|
||||
logger.info("Creating Link entry for: "+rs.getForeignColumns()[0].getName()+" of table: "+rs.getForeignTable().getName());
|
||||
logger.finer("Creating Link entry for: "+rs.getForeignColumns()[0].getName()+" of table: "+rs.getForeignTable().getName());
|
||||
createLinkEntry(rs,ve,metaTable,id+"_"+rs.getForeignTable().getName()+"_"+rs.getForeignColumns()[0].getName()+"_link");
|
||||
} else {
|
||||
logger.info("Creating List entry for: "+rs.getPrimaryColumns()[0].getName()+" of table: "+rs.getPrimaryTable().getName());
|
||||
logger.finer("Creating List entry for: "+rs.getPrimaryColumns()[0].getName()+" of table: "+rs.getPrimaryTable().getName());
|
||||
createListEntry(rs,ve,metaTable,id+"_"+rs.getPrimaryTable().getName()+"_"+rs.getPrimaryColumns()[0].getName()+"_list");
|
||||
}
|
||||
}
|
||||
|
|
@ -134,15 +133,12 @@ public class MetaModelSchemaAutoEntry {
|
|||
try {
|
||||
((VascBackendControllerLocal)getVascController().getVascBackendController()).addVascBackend(backend);
|
||||
((VascEntryControllerLocal)getVascController().getVascEntryController()).addVascEntry(ve);
|
||||
|
||||
// mm TODO rm this fill which adds the global actions ... and show updated tree in editor
|
||||
DefaultVascFactory.fillVascControllerLocalEntries((VascEntryControllerLocal) getVascController().getVascEntryController(), getVascController());
|
||||
} catch (Exception ee) {
|
||||
ee.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void createLinkEntry(Relationship rs2,VascEntry ve,Table metaTable,String id) {
|
||||
private void createLinkEntry(Relationship rs2,VascEntryLocal ve,Table metaTable,String id) {
|
||||
MetaModelVascBackend backendLink = new MetaModelVascBackend();
|
||||
backendLink.setId(id+"_backend");
|
||||
backendLink.setDataContextProvider(getDataContextProvider());
|
||||
|
|
@ -159,7 +155,7 @@ public class MetaModelSchemaAutoEntry {
|
|||
backendLink.setTableId(cols[0].getName());
|
||||
}
|
||||
|
||||
VascEntry veLink = new DefaultVascEntry();
|
||||
DefaultVascEntry veLink = new DefaultVascEntry();
|
||||
veLink.setId(id);
|
||||
veLink.setBackendId(id+"_backend");
|
||||
veLink.setPrimaryKeyFieldId(backendLink.getTableId());
|
||||
|
|
@ -171,7 +167,7 @@ public class MetaModelSchemaAutoEntry {
|
|||
//logger.info("Creating Link entry for: "+rs.getForeignColumns()[0].getName()+" of table: "+rs.getForeignTable().getName());
|
||||
//createLinkEntry(rs,ve,rs2.getForeignTable(),id+"_"+rs.getForeignTable().getName()+"_"+rs.getForeignColumns()[0].getName()+"_link");
|
||||
} else {
|
||||
logger.info("Creating List entry for: "+rs.getPrimaryColumns()[0].getName()+" of table: "+rs.getPrimaryTable().getName());
|
||||
logger.fine("Creating List entry for: "+rs.getPrimaryColumns()[0].getName()+" of table: "+rs.getPrimaryTable().getName());
|
||||
createListEntry(rs,veLink,rs2.getForeignTable(),id+"_"+rs.getPrimaryTable().getName()+"_"+rs.getPrimaryColumns()[0].getName()+"_list");
|
||||
}
|
||||
}
|
||||
|
|
@ -180,13 +176,13 @@ public class MetaModelSchemaAutoEntry {
|
|||
((VascBackendControllerLocal)getVascController().getVascBackendController()).addVascBackend(backendLink);
|
||||
((VascEntryControllerLocal)getVascController().getVascEntryController()).addVascEntry(veLink);
|
||||
|
||||
VascLinkEntry vle = new DefaultVascLinkEntry();
|
||||
DefaultVascEntryLink vle = new DefaultVascEntryLink();
|
||||
vle.setId(id+"Link");
|
||||
vle.setVascLinkEntryType(VascLinkEntryType.DEFAULT_TYPE);
|
||||
vle.setVascLinkEntryType(VascEntryLinkType.DEFAULT_TYPE);
|
||||
vle.setVascEntryId(id);
|
||||
vle.addEntryParameterFieldId(rs2.getForeignColumns()[0].getName(), rs2.getPrimaryColumns()[0].getName());
|
||||
|
||||
ve.addVascLinkEntry(vle);
|
||||
ve.addVascEntryLink(vle);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
|
@ -209,13 +205,13 @@ public class MetaModelSchemaAutoEntry {
|
|||
} else {
|
||||
backendLink.setTableId(cols[0].getName());
|
||||
}
|
||||
VascEntry veLink = new DefaultVascEntry();
|
||||
DefaultVascEntry veLink = new DefaultVascEntry();
|
||||
veLink.setId(id);
|
||||
veLink.setBackendId(id+"_backend");
|
||||
veLink.setPrimaryKeyFieldId(backendLink.getTableId());
|
||||
createFields(veLink,cols);
|
||||
try {
|
||||
VascEntryField vef = ve.getVascEntryFieldById(rs.getForeignColumns()[0].getName());
|
||||
VascEntryFieldLocal vef = (VascEntryFieldLocal)ve.getVascEntryFieldById(rs.getForeignColumns()[0].getName());
|
||||
if (vef==null) {
|
||||
logger.warning("Could not find: "+rs.getForeignColumns()[0].getName()+" in ve: "+ve.getId());
|
||||
return;
|
||||
|
|
@ -234,9 +230,10 @@ public class MetaModelSchemaAutoEntry {
|
|||
}
|
||||
}
|
||||
|
||||
private void createFields(VascEntry ve,Column[] cols) {
|
||||
private void createFields(VascEntryLocal ve,Column[] cols) {
|
||||
for (Column c:cols) {
|
||||
VascEntryField vef = new DefaultVascEntryField(c.getName());
|
||||
DefaultVascEntryField vef = new DefaultVascEntryField();
|
||||
vef.setId(c.getName());
|
||||
vef.setVascEntryFieldType(getVascController().getVascEntryFieldTypeController().getVascEntryFieldTypeByClass(c.getType().getJavaEquivalentClass()));
|
||||
|
||||
if (vef.getId().equals(ve.getPrimaryKeyFieldId())) {
|
||||
|
|
|
|||
|
|
@ -24,29 +24,27 @@ package net.forwardfire.vasc.backend.metamodel;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.eobjects.metamodel.UpdateCallback;
|
||||
import org.eobjects.metamodel.UpdateScript;
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.UpdateableDataContext;
|
||||
import org.eobjects.metamodel.data.DataSet;
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.insert.RowInsertionBuilder;
|
||||
import org.eobjects.metamodel.query.Query;
|
||||
import org.eobjects.metamodel.query.SelectItem;
|
||||
import org.eobjects.metamodel.query.builder.SatisfiedQueryBuilder;
|
||||
import org.eobjects.metamodel.query.builder.SatisfiedWhereBuilder;
|
||||
import org.eobjects.metamodel.schema.Schema;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
import org.eobjects.metamodel.update.RowUpdationBuilder;
|
||||
|
||||
import net.forwardfire.vasc.backend.AbstractVascBackend;
|
||||
import net.forwardfire.vasc.backend.VascBackendState;
|
||||
import net.forwardfire.vasc.backend.data.MapVascEntryFieldValue;
|
||||
import net.forwardfire.vasc.backend.data.MapVascEntryRecordCreator;
|
||||
import net.forwardfire.vasc.backend.metamodel.crud.CrudDataContext;
|
||||
import net.forwardfire.vasc.backend.metamodel.crud.UpdateableRow;
|
||||
import net.forwardfire.vasc.backend.metamodel.crud.CrudDataContextImpl;
|
||||
import net.forwardfire.vasc.backend.metamodel.crud.UpdateableRowMapImpl;
|
||||
import net.forwardfire.vasc.core.VascEntry;
|
||||
import net.forwardfire.vasc.core.VascEntryField;
|
||||
import net.forwardfire.vasc.core.VascException;
|
||||
|
|
@ -61,19 +59,55 @@ import net.forwardfire.vasc.core.entry.VascEntryRecordCreator;
|
|||
*/
|
||||
public class MetaModelVascBackend extends AbstractVascBackend {
|
||||
|
||||
private Logger logger = Logger.getLogger(MetaModelVascBackend.class.getName());
|
||||
private MetaModelDataContextProvider dataContextProvider = null;
|
||||
private UpdateableDataContext dataContext = null;
|
||||
private DataContext dataContext = null;
|
||||
private CrudDataContext crudDataContext = null;
|
||||
private String table = null;
|
||||
private String tableId = null;
|
||||
|
||||
/**
|
||||
* Returns casted version of data context.
|
||||
*/
|
||||
private UpdateableDataContext getUpdateableDataContext() {
|
||||
return (UpdateableDataContext)dataContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when data context in updateable.
|
||||
*/
|
||||
private boolean isUpdateableDataContext() {
|
||||
return dataContext instanceof UpdateableDataContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see net.forwardfire.vasc.backend.AbstractVascBackend#isReadOnly()
|
||||
*/
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return isUpdateableDataContext()==false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see net.forwardfire.vasc.backend.AbstractVascBackend#startBackend()
|
||||
*/
|
||||
@Override
|
||||
public void startBackend() {
|
||||
dataContext = (UpdateableDataContext)dataContextProvider.getDataContext();
|
||||
if (table==null) {
|
||||
throw new NullPointerException("Can't start with null table.");
|
||||
}
|
||||
if (table.isEmpty()) {
|
||||
throw new NullPointerException("Can't start with empty table.");
|
||||
}
|
||||
long startTime = System.currentTimeMillis();
|
||||
dataContext = dataContextProvider.getDataContext();
|
||||
if (isUpdateableDataContext()) {
|
||||
crudDataContext = new CrudDataContextImpl(getUpdateableDataContext());
|
||||
}
|
||||
long stopTime = System.currentTimeMillis();
|
||||
logger.info(dataContext.getClass().getSimpleName()+" created for: "+table+" in: "+(stopTime-startTime)+" ms.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see net.forwardfire.vasc.backend.AbstractVascBackend#stopBackend()
|
||||
*/
|
||||
|
|
@ -163,89 +197,68 @@ public class MetaModelVascBackend extends AbstractVascBackend {
|
|||
public List<Object> execute(VascBackendState state) throws VascException {
|
||||
Schema schema = dataContext.getDefaultSchema();
|
||||
Table t = schema.getTableByName(table);
|
||||
if (t==null) {
|
||||
throw new VascException("Could not get meta table for: '"+table+"'.");
|
||||
}
|
||||
Query q = createFilterQuery(state,t,false);
|
||||
if (isPageable() && state.getPageSize()>0) {
|
||||
q.setFirstRow(state.getPageIndex());
|
||||
q.setMaxRows(state.getPageSize());
|
||||
}
|
||||
if (crudDataContext!=null) {
|
||||
DataSet ds = crudDataContext.executeQuery(q);
|
||||
List<Object> result = new ArrayList<Object>(50);
|
||||
result.addAll(ds.toRows());
|
||||
ds.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
DataSet ds = dataContext.executeQuery(q);
|
||||
List<Object> result = new ArrayList<Object>(50);
|
||||
while (ds.next()) {
|
||||
Row row = ds.getRow();
|
||||
SelectItem[] cols = row.getSelectItems();
|
||||
Map<String,Object> map = new HashMap<String,Object>(cols.length);
|
||||
List<String> keys = new ArrayList<String>(1);
|
||||
keys.add(cols[0].getColumn().getName());
|
||||
UpdateableRowMapImpl rowMM = new UpdateableRowMapImpl(dataContext.getDefaultSchema().getTableByName(table),keys);
|
||||
for (SelectItem col:cols) {
|
||||
Object value = row.getValue(col);
|
||||
map.put(col.getColumn().getName(), value);
|
||||
rowMM.setValue(col, value);
|
||||
}
|
||||
result.add(map);
|
||||
result.add(rowMM);
|
||||
}
|
||||
ds.close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void persist(Object object) throws VascException {
|
||||
final Map<String,Object> map = (Map<String,Object>)object;
|
||||
dataContext.executeUpdate(new UpdateScript() {
|
||||
public void run(UpdateCallback backendImpl) {
|
||||
RowInsertionBuilder query = backendImpl.insertInto(table);
|
||||
for (String key:map.keySet()) {
|
||||
Object value = map.get(key);
|
||||
query.value(key, value);
|
||||
}
|
||||
query.execute();
|
||||
}
|
||||
});
|
||||
|
||||
if (crudDataContext==null) {
|
||||
return;
|
||||
}
|
||||
crudDataContext.persist((UpdateableRow) object);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object merge(Object object) throws VascException {
|
||||
final Map<String,Object> map = (Map<String,Object>)object;
|
||||
dataContext.executeUpdate(new UpdateScript() {
|
||||
public void run(UpdateCallback backendImpl) {
|
||||
|
||||
RowUpdationBuilder query = null;
|
||||
if (map.get(tableId) instanceof Number) {
|
||||
query = backendImpl.update(table).where(tableId).equals((Number)map.get(tableId));
|
||||
} else {
|
||||
query = backendImpl.update(table).where(tableId).equals(map.get(tableId).toString());
|
||||
}
|
||||
for (String key:map.keySet()) {
|
||||
if (key.equals(tableId)) {
|
||||
continue; // skip id;
|
||||
}
|
||||
Object value = map.get(key);
|
||||
query.value(key, value);
|
||||
}
|
||||
query.execute();
|
||||
}
|
||||
});
|
||||
return object;
|
||||
if (crudDataContext==null) {
|
||||
return object;
|
||||
}
|
||||
return crudDataContext.merge((UpdateableRow) object);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void delete(Object object) throws VascException {
|
||||
final Map<String,Object> map = (Map<String,Object>)object;
|
||||
dataContext.executeUpdate(new UpdateScript() {
|
||||
public void run(UpdateCallback backendImpl) {
|
||||
if (map.get(tableId) instanceof Number) {
|
||||
backendImpl.deleteFrom(table).where(tableId).equals((Number)map.get(tableId)).execute();
|
||||
} else {
|
||||
backendImpl.deleteFrom(table).where(tableId).equals(map.get(tableId).toString()).execute();
|
||||
}
|
||||
}
|
||||
});
|
||||
if (crudDataContext==null) {
|
||||
return;
|
||||
}
|
||||
crudDataContext.delete((UpdateableRow) object);
|
||||
}
|
||||
|
||||
public VascEntryFieldValue provideVascEntryFieldValue(VascEntryField field) {
|
||||
return new MapVascEntryFieldValue();
|
||||
return new RowVascEntryFieldValue();
|
||||
}
|
||||
|
||||
public VascEntryRecordCreator provideVascEntryRecordCreator(VascEntry vascEntry) {
|
||||
return new MapVascEntryRecordCreator();
|
||||
return new RowVascEntryRecordCreator(crudDataContext,crudDataContext.getDefaultSchema().getTableByName(table));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,479 @@
|
|||
package net.forwardfire.vasc.backend.metamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.eobjects.metamodel.MetaModelException;
|
||||
import org.eobjects.metamodel.QueryPostprocessDataContext;
|
||||
import org.eobjects.metamodel.data.AbstractDataSet;
|
||||
import org.eobjects.metamodel.data.DataSet;
|
||||
import org.eobjects.metamodel.data.DefaultRow;
|
||||
import org.eobjects.metamodel.data.FirstRowDataSet;
|
||||
import org.eobjects.metamodel.data.MaxRowsDataSet;
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.query.FilterItem;
|
||||
import org.eobjects.metamodel.query.FromItem;
|
||||
import org.eobjects.metamodel.query.Query;
|
||||
import org.eobjects.metamodel.query.SelectItem;
|
||||
import org.eobjects.metamodel.schema.Column;
|
||||
import org.eobjects.metamodel.schema.ColumnType;
|
||||
import org.eobjects.metamodel.schema.MutableColumn;
|
||||
import org.eobjects.metamodel.schema.MutableRelationship;
|
||||
import org.eobjects.metamodel.schema.MutableSchema;
|
||||
import org.eobjects.metamodel.schema.MutableTable;
|
||||
import org.eobjects.metamodel.schema.Relationship;
|
||||
import org.eobjects.metamodel.schema.Schema;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
import org.eobjects.metamodel.schema.TableType;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBCursor;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
public class MongoDbDataContextSchemaDetector /* implements MetaModelSchemaDetector */ {
|
||||
|
||||
private int dataCheckSize = 100;
|
||||
private boolean searchReference = true;
|
||||
|
||||
public MongoDbDataContextSchemaDetector() {
|
||||
}
|
||||
|
||||
public class MongoDbDataContextExtended extends QueryPostprocessDataContext /* MongoDbDataContext */ {
|
||||
protected DB mongoDb;
|
||||
protected Schema schema;
|
||||
protected MongoDbDataContextSchemaDetector walker;
|
||||
public MongoDbDataContextExtended(DB mongoDb,MongoDbDataContextSchemaDetector walker) {
|
||||
this.mongoDb=mongoDb;
|
||||
this.walker=walker;
|
||||
}
|
||||
@Override
|
||||
protected Schema getMainSchema() throws MetaModelException {
|
||||
if (schema!=null) {
|
||||
return schema;
|
||||
}
|
||||
schema = walker.detectSchema(mongoDb, getMainSchemaName());
|
||||
return schema;
|
||||
}
|
||||
protected String getMainSchemaName() throws MetaModelException {
|
||||
return mongoDb.getName();
|
||||
}
|
||||
protected DataSet materializeMainSchemaTable(Table table, Column[] columns, int maxRows) {
|
||||
return materializeMainSchemaTableInternal(table, columns, null, maxRows, true);
|
||||
}
|
||||
|
||||
// Overidded these method because they do not use the getMainSchema() method
|
||||
public DataSet executeQuery(Query query) {
|
||||
// Check for queries containing only simple selects and where clauses,
|
||||
// or if it is a COUNT(*) query.
|
||||
|
||||
// if from clause only contains a main schema table
|
||||
List<FromItem> fromItems = query.getFromClause().getItems();
|
||||
if (fromItems.size() == 1 && fromItems.get(0).getTable() != null
|
||||
&& fromItems.get(0).getTable().getSchema() == getMainSchema()) {
|
||||
final Table table = fromItems.get(0).getTable();
|
||||
|
||||
// if GROUP BY, HAVING and ORDER BY clauses are not specified
|
||||
if (query.getGroupByClause().isEmpty() && query.getHavingClause().isEmpty()
|
||||
&& query.getOrderByClause().isEmpty()) {
|
||||
|
||||
final List<FilterItem> whereItems = query.getWhereClause().getItems();
|
||||
|
||||
// if all of the select items are "pure" column selection
|
||||
boolean allSelectItemsAreColumns = true;
|
||||
List<SelectItem> selectItems = query.getSelectClause().getItems();
|
||||
|
||||
// if it is a
|
||||
// "SELECT [columns] FROM [table] WHERE [conditions]"
|
||||
// query.
|
||||
for (SelectItem selectItem : selectItems) {
|
||||
if (selectItem.getFunction() != null || selectItem.getColumn() == null) {
|
||||
allSelectItemsAreColumns = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (allSelectItemsAreColumns) {
|
||||
//logger.debug("Query can be expressed in full MongoDB, no post processing needed.");
|
||||
|
||||
// prepare for a non-post-processed query
|
||||
Column[] columns = new Column[selectItems.size()];
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
columns[i] = selectItems.get(i).getColumn();
|
||||
}
|
||||
|
||||
DataSet dataSet = materializeMainSchemaTableInternal(table, columns, whereItems, -1, false);
|
||||
if (query.getFirstRow() != null) {
|
||||
dataSet = new FirstRowDataSet(dataSet, query.getFirstRow());
|
||||
}
|
||||
if (query.getMaxRows() != null) {
|
||||
dataSet = new MaxRowsDataSet(dataSet, query.getMaxRows());
|
||||
}
|
||||
return dataSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
//logger.debug("Query will be simplified for MongoDB and post processed.");
|
||||
return super.executeQuery(query);
|
||||
}
|
||||
private DataSet materializeMainSchemaTableInternal(Table table, Column[] columns, List<FilterItem> whereItems,
|
||||
int maxRows, boolean queryPostProcessed) {
|
||||
final DBCollection collection = mongoDb.getCollection(table.getName());
|
||||
|
||||
final DBObject query = createMongoDbQuery(table, whereItems);
|
||||
|
||||
//logger.info("Executing MongoDB 'find' query: {}", query);
|
||||
DBCursor cursor = collection.find(query);
|
||||
|
||||
if (maxRows > 0) {
|
||||
cursor = cursor.limit(maxRows);
|
||||
}
|
||||
|
||||
return new MongoDbDataSet(cursor, columns, queryPostProcessed);
|
||||
}
|
||||
final class MongoDbDataSet extends AbstractDataSet {
|
||||
|
||||
//private static final Logger logger = LoggerFactory
|
||||
// .getLogger(MongoDbDataSet.class);
|
||||
|
||||
private final DBCursor _cursor;
|
||||
private final SelectItem[] _selectItems;
|
||||
private final boolean _queryPostProcessed;
|
||||
|
||||
private boolean _closed;
|
||||
private volatile DBObject _dbObject;
|
||||
|
||||
public MongoDbDataSet(DBCursor cursor, Column[] columns,
|
||||
boolean queryPostProcessed) {
|
||||
_cursor = cursor;
|
||||
_selectItems = new SelectItem[columns.length];
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
_selectItems[i] = new SelectItem(columns[i]);
|
||||
}
|
||||
_queryPostProcessed = queryPostProcessed;
|
||||
_closed = false;
|
||||
}
|
||||
|
||||
public boolean isQueryPostProcessed() {
|
||||
return _queryPostProcessed;
|
||||
}
|
||||
|
||||
public SelectItem[] getSelectItems() {
|
||||
return _selectItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
_cursor.close();
|
||||
_closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
if (!_closed) {
|
||||
// logger.warn(
|
||||
// "finalize() invoked, but DataSet is not closed. Invoking close() on {}",
|
||||
// this);
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean next() {
|
||||
if (_cursor.hasNext()) {
|
||||
_dbObject = _cursor.next();
|
||||
return true;
|
||||
} else {
|
||||
_dbObject = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Row getRow() {
|
||||
if (_dbObject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Object[] values = new Object[_selectItems.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
String key = _selectItems[i].getColumn().getName();
|
||||
Object value = _dbObject.get(key);
|
||||
values[i] = toValue(_selectItems[i].getColumn(), value);
|
||||
}
|
||||
return new DefaultRow(_selectItems, values);
|
||||
}
|
||||
|
||||
private Object toValue(Column column, Object value) {
|
||||
if (value instanceof List) {
|
||||
return value;
|
||||
}
|
||||
if (value instanceof DBObject) {
|
||||
DBObject basicDBObject = (DBObject) value;
|
||||
return basicDBObject.toMap();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected BasicDBObject createMongoDbQuery(Table table, List<FilterItem> whereItems) {
|
||||
assert getMainSchema() == table.getSchema();
|
||||
|
||||
final BasicDBObject query = new BasicDBObject();
|
||||
if (whereItems != null && !whereItems.isEmpty()) {
|
||||
for (FilterItem item : whereItems) {
|
||||
convertToCursorObject(query, item);
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
private void convertToCursorObject(BasicDBObject query, FilterItem item) {
|
||||
if (item.isCompoundFilter()) {
|
||||
|
||||
BasicDBList orList = new BasicDBList();
|
||||
|
||||
final FilterItem[] childItems = item.getChildItems();
|
||||
for (FilterItem childItem : childItems) {
|
||||
BasicDBObject childObject = new BasicDBObject();
|
||||
convertToCursorObject(childObject, childItem);
|
||||
orList.add(childObject);
|
||||
}
|
||||
|
||||
query.put("$or", orList);
|
||||
|
||||
} else {
|
||||
|
||||
final Column column = item.getSelectItem().getColumn();
|
||||
final String columnName = column.getName();
|
||||
final Object operand = item.getOperand();
|
||||
final String operatorName = getOperatorName(item);
|
||||
|
||||
final BasicDBObject existingFilterObject = (BasicDBObject) query.get(columnName);
|
||||
if (existingFilterObject == null) {
|
||||
if (operatorName == null) {
|
||||
query.put(columnName, operand);
|
||||
} else {
|
||||
query.put(columnName, new BasicDBObject(operatorName, operand));
|
||||
}
|
||||
} else {
|
||||
if (operatorName == null) {
|
||||
throw new IllegalStateException("Cannot retrieve records for a column with two EQUALS_TO operators");
|
||||
} else {
|
||||
existingFilterObject.append(operatorName, operand);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@SuppressWarnings("deprecation")
|
||||
private String getOperatorName(FilterItem item) {
|
||||
final String operatorName;
|
||||
switch (item.getOperator()) {
|
||||
case EQUALS_TO:
|
||||
operatorName = null;
|
||||
break;
|
||||
case LESS_THAN:
|
||||
case LOWER_THAN:
|
||||
operatorName = "$lt";
|
||||
break;
|
||||
case GREATER_THAN:
|
||||
case HIGHER_THAN:
|
||||
operatorName = "$gt";
|
||||
break;
|
||||
case DIFFERENT_FROM:
|
||||
operatorName = "$ne";
|
||||
break;
|
||||
case IN:
|
||||
operatorName = "$in";
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unsupported operator type: " + item.getOperator());
|
||||
}
|
||||
return operatorName;
|
||||
}
|
||||
|
||||
protected void addTable(MutableTable table) {
|
||||
if (getMainSchema() instanceof MutableSchema) {
|
||||
MutableSchema mutableSchema = (MutableSchema) getMainSchema();
|
||||
mutableSchema.addTable(table);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Schema is not mutable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Schema detectSchema(Object nativeBackendConnection,String schemaName) {
|
||||
if ((nativeBackendConnection instanceof DB)==false) {
|
||||
throw new RuntimeException("Can only work with DB instance not with: "+nativeBackendConnection);
|
||||
}
|
||||
DB db = (DB)nativeBackendConnection;
|
||||
MutableSchema schema = new MutableSchema(schemaName);
|
||||
for (MutableTable tableDef : detectSchemaTables(db)) {
|
||||
tableDef.setSchema(schema);
|
||||
schema.addTable(tableDef);
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
protected MutableTable[] detectSchemaTables(DB db) {
|
||||
Set<String> collectionNames = db.getCollectionNames();
|
||||
Map<String,PublicTable> tables = new HashMap<String,PublicTable>(collectionNames.size());
|
||||
for (String collectionName : collectionNames) {
|
||||
PublicTable table = detectTable(db, collectionName);
|
||||
tables.put(collectionName, table);
|
||||
}
|
||||
|
||||
// Check for object id
|
||||
for (String collectionName:objectIdRef.keySet()) {
|
||||
Map<String,ObjectId> refMap = objectIdRef.get(collectionName);
|
||||
if (refMap==null) {
|
||||
continue;
|
||||
}
|
||||
for (String columnName:refMap.keySet()) {
|
||||
ObjectId objectId = refMap.get(columnName);
|
||||
|
||||
for (String colName : collectionNames) {
|
||||
Column primaryColumn = findColumnRef(db,colName,tables,objectId,columnName);
|
||||
if (primaryColumn==null) {
|
||||
continue;
|
||||
}
|
||||
PublicTable t = tables.get(collectionName);
|
||||
Column foreignColumn = t.getColumnByName(columnName);
|
||||
t.addRelationship(MutableRelationship.createRelationship(primaryColumn, foreignColumn));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MutableTable[] result = new MutableTable[collectionNames.size()];
|
||||
return new ArrayList<MutableTable>(tables.values()).toArray(result);
|
||||
}
|
||||
|
||||
Map<String,Map<String,ObjectId>> objectIdRef = new HashMap<String,Map<String,ObjectId>>(20);
|
||||
|
||||
protected Column findColumnRef(DB db, String collectionName,Map<String,PublicTable> tables,ObjectId objectId,String colName) {
|
||||
DBCollection collection = db.getCollection(collectionName);
|
||||
DBObject query = new BasicDBObject();
|
||||
query.put("_id", objectId);
|
||||
DBCursor cursor = collection.find(query).limit(dataCheckSize);
|
||||
try {
|
||||
if (cursor.hasNext()) {
|
||||
PublicTable t = tables.get(collectionName);
|
||||
return t.getColumnByName("_id");
|
||||
}
|
||||
} finally {
|
||||
if (cursor!=null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected PublicTable detectTable(DB db, String collectionName) {
|
||||
final DBCollection collection = db.getCollection(collectionName);
|
||||
final DBCursor cursor = collection.find().limit(dataCheckSize);
|
||||
final SortedMap<String, Set<Class<?>>> columnsAndTypes = new TreeMap<String, Set<Class<?>>>();
|
||||
while (cursor.hasNext()) {
|
||||
DBObject row = cursor.next();
|
||||
Set<String> keysInObject = row.keySet();
|
||||
for (String key : keysInObject) {
|
||||
Set<Class<?>> types = columnsAndTypes.get(key);
|
||||
if (types == null) {
|
||||
types = new HashSet<Class<?>>();
|
||||
columnsAndTypes.put(key, types);
|
||||
}
|
||||
Object value = row.get(key);
|
||||
if (value != null) {
|
||||
types.add(value.getClass());
|
||||
}
|
||||
if ("_id".equals(key)==false && value instanceof ObjectId) {
|
||||
Map<String,ObjectId> map = objectIdRef.get(collectionName);
|
||||
if (map==null) {
|
||||
map = new HashMap<String,ObjectId>(10);
|
||||
objectIdRef.put(collectionName,map);
|
||||
}
|
||||
map.put(key, (ObjectId)value);
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
final String[] columnNames = new String[columnsAndTypes.size()];
|
||||
final ColumnType[] columnTypes = new ColumnType[columnsAndTypes.size()];
|
||||
|
||||
int i = 0;
|
||||
for (Entry<String, Set<Class<?>>> columnAndTypes : columnsAndTypes.entrySet()) {
|
||||
final String columnName = columnAndTypes.getKey();
|
||||
final Set<Class<?>> columnTypeSet = columnAndTypes.getValue();
|
||||
final Class<?> columnType;
|
||||
if (columnTypeSet.size() == 1) {
|
||||
columnType = columnTypeSet.iterator().next();
|
||||
} else {
|
||||
columnType = Object.class;
|
||||
}
|
||||
columnNames[i] = columnName;
|
||||
if (columnType == ObjectId.class) {
|
||||
columnTypes[i] = ColumnType.ROWID;
|
||||
} else {
|
||||
columnTypes[i] = ColumnType.convertColumnType(columnType);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
PublicTable tableSchema = new PublicTable(collectionName,TableType.TABLE);
|
||||
for (int y = 0; y < columnNames.length; y++) {
|
||||
MutableColumn col = new MutableColumn(columnNames[y], columnTypes[y], tableSchema, i, true);
|
||||
tableSchema.addColumn(col);
|
||||
}
|
||||
return tableSchema; // new SimpleTableDef(collectionName, columnNames, columnTypes);
|
||||
}
|
||||
|
||||
// Override to make public
|
||||
class PublicTable extends MutableTable {
|
||||
public PublicTable(String name,TableType type) {
|
||||
super(name,type);
|
||||
}
|
||||
@Override
|
||||
public void addRelationship(Relationship relation) {
|
||||
super.addRelationship(relation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dataCheckSize
|
||||
*/
|
||||
public int getDataCheckSize() {
|
||||
return dataCheckSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dataCheckSize the dataCheckSize to set
|
||||
*/
|
||||
public void setDataCheckSize(int dataCheckSize) {
|
||||
this.dataCheckSize = dataCheckSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the searchReference
|
||||
*/
|
||||
public boolean isSearchReference() {
|
||||
return searchReference;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param searchReference the searchReference to set
|
||||
*/
|
||||
public void setSearchReference(boolean searchReference) {
|
||||
this.searchReference = searchReference;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package net.forwardfire.vasc.backend.metamodel;
|
||||
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.query.SelectItem;
|
||||
|
||||
import net.forwardfire.vasc.backend.metamodel.crud.UpdateableRow;
|
||||
import net.forwardfire.vasc.core.VascEntryField;
|
||||
import net.forwardfire.vasc.core.VascException;
|
||||
import net.forwardfire.vasc.core.entry.VascEntryFieldValue;
|
||||
|
||||
public class RowVascEntryFieldValue implements VascEntryFieldValue {
|
||||
|
||||
private static final long serialVersionUID = -806674640688182132L;
|
||||
|
||||
/**
|
||||
* @see net.forwardfire.vasc.core.entry.VascEntryFieldValue#getValue(net.forwardfire.vasc.core.VascEntryField, java.lang.Object)
|
||||
*/
|
||||
public Object getValue(VascEntryField field, Object record) throws VascException {
|
||||
if (field==null) {
|
||||
throw new NullPointerException("Can't get value of null field.");
|
||||
}
|
||||
if (field.getBackendName()==null) {
|
||||
throw new NullPointerException("Can't get value of null backendName field.");
|
||||
}
|
||||
if (record==null) {
|
||||
throw new NullPointerException("Can't get value of null object.");
|
||||
}
|
||||
if (record instanceof UpdateableRow) {
|
||||
UpdateableRow row = (UpdateableRow)record;
|
||||
return row.getValue(field.getBackendName());
|
||||
}
|
||||
Row row = (Row)record;
|
||||
Object fieldValue = row.getValue(indexOf(field.getBackendName(),row));
|
||||
return fieldValue;
|
||||
}
|
||||
|
||||
private int indexOf(String columnName,Row row) { // RM after MM Row update
|
||||
if (columnName==null) {
|
||||
return UpdateableRow.INDEX_NOT_FOUND;
|
||||
}
|
||||
int index = 0;
|
||||
for (SelectItem si:row.getSelectItems()) {
|
||||
if (si.getColumn().getName().equals(columnName)) {
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return UpdateableRow.INDEX_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see net.forwardfire.vasc.core.entry.VascEntryFieldValue#getDisplayValue(net.forwardfire.vasc.core.VascEntryField, java.lang.Object)
|
||||
*/
|
||||
public String getDisplayValue(VascEntryField field, Object record) throws VascException {
|
||||
Object fieldValue = getValue(field,record);
|
||||
if (fieldValue==null) {
|
||||
fieldValue = "";
|
||||
}
|
||||
return fieldValue.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see net.forwardfire.vasc.core.entry.VascEntryFieldValue#setValue(net.forwardfire.vasc.core.VascEntryField, java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public void setValue(VascEntryField field, Object record,Object value) throws VascException {
|
||||
if (record instanceof UpdateableRow) {
|
||||
UpdateableRow row = (UpdateableRow)record;
|
||||
row.setValue(field.getBackendName(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package net.forwardfire.vasc.backend.metamodel;
|
||||
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
|
||||
import net.forwardfire.vasc.backend.metamodel.crud.CrudDataContext;
|
||||
import net.forwardfire.vasc.backend.metamodel.crud.UpdateableRow;
|
||||
import net.forwardfire.vasc.core.VascEntry;
|
||||
import net.forwardfire.vasc.core.entry.VascEntryRecordCreator;
|
||||
|
||||
public class RowVascEntryRecordCreator implements VascEntryRecordCreator {
|
||||
|
||||
private static final long serialVersionUID = -1182678362367989090L;
|
||||
private CrudDataContext dataContext = null;
|
||||
private Table table = null;
|
||||
|
||||
public RowVascEntryRecordCreator(CrudDataContext dataContext,Table table) {
|
||||
this.dataContext=dataContext;
|
||||
this.table=table;
|
||||
}
|
||||
|
||||
public Class<?> getObjectClass() {
|
||||
return UpdateableRow.class;
|
||||
}
|
||||
|
||||
public Object newRecord(VascEntry entry) throws Exception {
|
||||
return dataContext.createRow(table);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,240 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.bundle;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import org.eobjects.metamodel.MetaModelException;
|
||||
import org.eobjects.metamodel.QueryPostprocessDataContext;
|
||||
import org.eobjects.metamodel.UpdateScript;
|
||||
import org.eobjects.metamodel.UpdateableDataContext;
|
||||
import org.eobjects.metamodel.data.AbstractDataSet;
|
||||
import org.eobjects.metamodel.data.DataSet;
|
||||
import org.eobjects.metamodel.data.DefaultRow;
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.query.FilterItem;
|
||||
import org.eobjects.metamodel.query.SelectItem;
|
||||
import org.eobjects.metamodel.schema.Column;
|
||||
import org.eobjects.metamodel.schema.MutableColumn;
|
||||
import org.eobjects.metamodel.schema.MutableSchema;
|
||||
import org.eobjects.metamodel.schema.MutableTable;
|
||||
import org.eobjects.metamodel.schema.Schema;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
import org.eobjects.metamodel.schema.TableType;
|
||||
|
||||
/**
|
||||
* ResourceBundleDataContext is updatable context for file based data source.
|
||||
* Will try to load all supported locals by jvm as tables. (except for URL)
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 26, 2012
|
||||
*/
|
||||
public class ResourceBundleDataContext extends QueryPostprocessDataContext implements UpdateableDataContext {
|
||||
|
||||
protected static final String DEFAULT_CHAR_SET = "UTF-8";
|
||||
protected ResourceBundleUpdateExecutor resourceBundleUpdateExecutor = null;
|
||||
protected ResourceBundleDataControl bundleDataControl = null;
|
||||
protected String mainSchemaName = null;
|
||||
protected Charset charSet = null;
|
||||
|
||||
private ResourceBundleDataContext(Charset charSet) {
|
||||
if (charSet==null) {
|
||||
throw new NullPointerException("Can't start with null charSet");
|
||||
}
|
||||
this.charSet = charSet;
|
||||
}
|
||||
|
||||
public ResourceBundleDataContext(String resourceBundle) {
|
||||
this(resourceBundle,Charset.forName(DEFAULT_CHAR_SET));
|
||||
}
|
||||
|
||||
public ResourceBundleDataContext(String resourceBundle,Charset charSet) {
|
||||
this(charSet);
|
||||
if (resourceBundle==null) {
|
||||
throw new NullPointerException("Can't start with null resourceBundle");
|
||||
}
|
||||
init(resourceBundle);
|
||||
}
|
||||
|
||||
public ResourceBundleDataContext(File resourceBundle) {
|
||||
this(resourceBundle,Charset.forName(DEFAULT_CHAR_SET));
|
||||
}
|
||||
|
||||
public ResourceBundleDataContext(File resourceBundle,Charset charSet) {
|
||||
this(charSet);
|
||||
if (resourceBundle==null) {
|
||||
throw new NullPointerException("Can't start with null resourceBundle");
|
||||
}
|
||||
init(resourceBundle);
|
||||
}
|
||||
|
||||
public ResourceBundleDataContext(URL resourceBundle) {
|
||||
this(resourceBundle,Charset.forName(DEFAULT_CHAR_SET));
|
||||
}
|
||||
|
||||
public ResourceBundleDataContext(URL resourceBundle,Charset charSet) {
|
||||
this(charSet);
|
||||
if (resourceBundle==null) {
|
||||
throw new NullPointerException("Can't start with null resourceBundle");
|
||||
}
|
||||
init(resourceBundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init ResourceBundleDataContext to use diffect source backends.
|
||||
*/
|
||||
protected void init(Object source) {
|
||||
if (source==null) {
|
||||
throw new NullPointerException("Can't init with null source");
|
||||
}
|
||||
if (bundleDataControl!=null) {
|
||||
throw new NullPointerException("Only one init allowed."); // can't override refreshSchema to reinit again.
|
||||
}
|
||||
|
||||
// Setup data source
|
||||
String bundleBaseName = null;
|
||||
if (source instanceof File) {
|
||||
File baseFile = (File)source;
|
||||
bundleBaseName = baseFile.getName();
|
||||
bundleDataControl = new ResourceBundleDataControl(charSet,baseFile);
|
||||
} else if (source instanceof URL) {
|
||||
URL baseUrl = (URL)source;
|
||||
bundleBaseName = baseUrl.getFile();
|
||||
bundleDataControl = new ResourceBundleDataControl(charSet,baseUrl);
|
||||
} else {
|
||||
bundleBaseName = source.toString();
|
||||
bundleDataControl = new ResourceBundleDataControl(charSet);
|
||||
}
|
||||
mainSchemaName = cleanMainSchemaName(bundleBaseName);
|
||||
|
||||
// Load all data
|
||||
//ResourceBundle.getBundle(bundleBaseName,bundleDataControl);
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
if (cl==null) { cl=getClass().getClassLoader(); }
|
||||
try {
|
||||
bundleDataControl.newBundle(bundleBaseName, Locale.getDefault(), null, cl, false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Start Query executor
|
||||
resourceBundleUpdateExecutor = new ResourceBundleUpdateExecutor(this,bundleDataControl);
|
||||
}
|
||||
|
||||
// TODO check where static verion is.
|
||||
protected String cleanMainSchemaName(String name) {
|
||||
if (name.endsWith(ResourceBundleDataControl.BUNDLE_EXTENSION)) {
|
||||
name = name.substring(0,name.indexOf(ResourceBundleDataControl.BUNDLE_EXTENSION)-1);
|
||||
}
|
||||
StringBuffer buffer = new StringBuffer(name.length());
|
||||
for (char c:name.toCharArray()) {
|
||||
if (Character.isDigit(c)) {
|
||||
buffer.append(c);
|
||||
} else if (Character.isLetter(c)) {
|
||||
buffer.append(c);
|
||||
} else {
|
||||
buffer.append('_');
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public boolean isDataContextWritable() {
|
||||
return bundleDataControl.isWritable();
|
||||
}
|
||||
|
||||
protected MutableTable createTable(Schema schema,String name) {
|
||||
MutableTable table = new MutableTable(name, TableType.TABLE, schema);
|
||||
|
||||
MutableColumn idColumn = new MutableColumn("id");
|
||||
//idColumn.setColumnNumber(0);
|
||||
idColumn.setIndexed(true);
|
||||
idColumn.setNullable(false);
|
||||
//idColumn.setPrimaryKey(true);
|
||||
|
||||
MutableColumn keyColumn = new MutableColumn("key");
|
||||
keyColumn.setColumnNumber(1);
|
||||
keyColumn.setNullable(false);
|
||||
|
||||
MutableColumn valueColumn = new MutableColumn("value");
|
||||
valueColumn.setColumnNumber(2);
|
||||
valueColumn.setNullable(false);
|
||||
|
||||
table.addColumn(idColumn);
|
||||
table.addColumn(keyColumn);
|
||||
table.addColumn(valueColumn);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
// ======== Interface
|
||||
|
||||
|
||||
@Override
|
||||
protected Number executeCountQuery(Table table, List<FilterItem> whereItems, boolean functionApproximationAllowed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Schema getMainSchema() throws MetaModelException {
|
||||
String schemaName = getDefaultSchemaName();
|
||||
MutableSchema schema = new MutableSchema(schemaName);
|
||||
for (String bundleName:bundleDataControl.getBundleNames()) {
|
||||
schema.addTable(createTable(schema,bundleName));
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
// TODO: move to SelectItem
|
||||
static public SelectItem[] convertColumns(Column[] cols) {
|
||||
SelectItem[] selectItems = new SelectItem[cols.length];
|
||||
for (int i=0;i<cols.length;i++) {
|
||||
selectItems[i] = new SelectItem(cols[i]);
|
||||
}
|
||||
return selectItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSet materializeMainSchemaTable(Table table, Column[] cols,int maxRows) {
|
||||
return materializeTable(table.getName(),convertColumns(table.getColumns()),maxRows);
|
||||
}
|
||||
|
||||
protected DataSet materializeTable(String table,final SelectItem[] selectItems,final int maxRows) {
|
||||
Properties data = bundleDataControl.getBundleData(table);
|
||||
List<Row> result = new ArrayList<Row>(200);
|
||||
for (Object keyO:data.keySet()) {
|
||||
String keyId = Integer.toString(keyO.hashCode());
|
||||
String key = (String)keyO;
|
||||
String value = data.getProperty(key);
|
||||
result.add(new DefaultRow(selectItems, new Object[] {keyId,key,value}));
|
||||
}
|
||||
final Iterator<Row> resultData = result.iterator();
|
||||
return new AbstractDataSet() {
|
||||
int resultCount = 0;
|
||||
public SelectItem[] getSelectItems() { return selectItems; }
|
||||
public Row getRow() { return resultData.next(); }
|
||||
public boolean next() {
|
||||
if (maxRows > 0 && resultCount++ > maxRows) {
|
||||
return false;
|
||||
}
|
||||
return resultData.hasNext();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void executeUpdate(UpdateScript update) {
|
||||
update.run(resourceBundleUpdateExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMainSchemaName() throws MetaModelException {
|
||||
return mainSchemaName;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.bundle;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.PropertyResourceBundle;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.ResourceBundle.Control;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* ResourceBundleControl load ResourceBundles with correct CharSet from file and class path.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Mar 26, 2012
|
||||
*/
|
||||
public class ResourceBundleDataControl extends Control {
|
||||
|
||||
/** The default extension for bundles. */
|
||||
protected static final String BUNDLE_EXTENSION = "properties";
|
||||
protected static final String BUNDLE_COMMENT = "Saved by MetaModel; ";
|
||||
|
||||
protected Logger logger = null;
|
||||
protected Charset charSet = null;
|
||||
|
||||
/** The charSet to load with **/
|
||||
protected File baseBundleFile = null;
|
||||
protected URL baseBundleUrl = null;
|
||||
|
||||
protected Map<String,Properties> bundleData = null;
|
||||
protected Map<String,File> bundleFiles = null;
|
||||
|
||||
private ResourceBundleDataControl() {
|
||||
logger = LoggerFactory.getLogger(ResourceBundleDataControl.class);
|
||||
bundleFiles = new HashMap<String,File>(10);
|
||||
bundleData = Collections.synchronizedMap(new HashMap<String,Properties>(10));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates ResourceBundleControl to read ResourceBundle with charSet.
|
||||
*/
|
||||
public ResourceBundleDataControl(Charset charSet) {
|
||||
this();
|
||||
if (charSet==null) {
|
||||
throw new NullPointerException("Can't load bundle with null Charset.");
|
||||
}
|
||||
this.charSet=charSet;
|
||||
}
|
||||
|
||||
public ResourceBundleDataControl(Charset charSet,File baseBundleFile) {
|
||||
this(charSet);
|
||||
if (baseBundleFile==null) {
|
||||
throw new NullPointerException("Can't load bundle with null baseBundleFile.");
|
||||
}
|
||||
this.baseBundleFile=baseBundleFile;
|
||||
}
|
||||
|
||||
public ResourceBundleDataControl(Charset charSet,URL baseBundleUrl) {
|
||||
this(charSet);
|
||||
if (baseBundleUrl==null) {
|
||||
throw new NullPointerException("Can't load bundle with null baseBundleUrl.");
|
||||
}
|
||||
this.baseBundleUrl=baseBundleUrl;
|
||||
}
|
||||
|
||||
public boolean isWritable() {
|
||||
return baseBundleFile!=null;
|
||||
}
|
||||
|
||||
public Set<String> getBundleNames() {
|
||||
return bundleData.keySet();
|
||||
}
|
||||
|
||||
public Properties getBundleData(String bundleName) {
|
||||
if (bundleName==null) {
|
||||
throw new NullPointerException("Can't get data for null bundleName.");
|
||||
}
|
||||
return bundleData.get(bundleName);
|
||||
}
|
||||
|
||||
public void removeBundle(String bundleName) {
|
||||
Properties data = getBundleData(bundleName);
|
||||
if (data==null) {
|
||||
throw new IllegalStateException("Can't remove bundle data of unknown bundle: "+bundleName);
|
||||
}
|
||||
bundleData.remove(bundleName);
|
||||
bundleFiles.remove(bundleName);
|
||||
}
|
||||
|
||||
public void saveBundle(String bundleName) throws IOException {
|
||||
Properties data = getBundleData(bundleName);
|
||||
if (data==null) {
|
||||
throw new IllegalStateException("Can't save bundle data of unknown bundle: "+bundleName);
|
||||
}
|
||||
File bundleFile = bundleFiles.get(bundleName);
|
||||
if (bundleFile==null) {
|
||||
throw new IllegalStateException("Could not find loaded bundle file: "+bundleName);
|
||||
}
|
||||
long startTime = System.currentTimeMillis();
|
||||
saveBundleFile(data,bundleFile);
|
||||
long stopTime = System.currentTimeMillis();
|
||||
logger.info("Saved bundle "+bundleName+" with "+data.size()+" keys in "+(stopTime-startTime)+" ms.");
|
||||
}
|
||||
|
||||
public int putBundleData(ResourceBundle bundle,String bundleName,File file) {
|
||||
Properties p = new Properties();
|
||||
for (String key:bundle.keySet()) {
|
||||
p.put(key, bundle.getString(key));
|
||||
}
|
||||
bundleData.put(bundleName, p);
|
||||
if (file!=null) {
|
||||
bundleFiles.put(bundleName, file);
|
||||
}
|
||||
return p.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the loading of the ResourceBundle
|
||||
*/
|
||||
public ResourceBundle newBundle(String baseName, Locale localeRequested, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
// On urls only load the requested one.
|
||||
if (baseBundleUrl!=null) {
|
||||
ResourceBundle bundle = loadBundleUrl(baseBundleUrl);
|
||||
putBundleData(bundle, baseBundleUrl.getFile(), null);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
if (baseName.endsWith(BUNDLE_EXTENSION)) {
|
||||
baseName = baseName.substring(0,baseName.indexOf(BUNDLE_EXTENSION)-1);
|
||||
}
|
||||
|
||||
// Try to load all bundles.
|
||||
ResourceBundle bundleLast = null;
|
||||
int totalBundleDataSize = 0;
|
||||
for (Locale locale:Locale.getAvailableLocales()) {
|
||||
String bundleName = toBundleName(baseName, locale);
|
||||
ResourceBundle bundle = null;
|
||||
File bundleFile = null;
|
||||
try {
|
||||
if (baseBundleFile==null) {
|
||||
String resourceName = toResourceName(bundleName, BUNDLE_EXTENSION);
|
||||
logger.info("Loading: "+resourceName);
|
||||
bundle = loadBundleClassPath(resourceName,loader,reload);
|
||||
} else {
|
||||
String resourceName = baseBundleFile.getParent()+File.separatorChar+bundleName+"."+BUNDLE_EXTENSION;
|
||||
logger.info("Loading: "+resourceName);
|
||||
bundleFile = new File(resourceName);
|
||||
bundle = loadBundleFile(bundleFile);
|
||||
}
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
continue; // next
|
||||
}
|
||||
if (bundle==null) {
|
||||
continue;
|
||||
}
|
||||
bundleLast = bundle;
|
||||
String tableName = toBundleName("", locale).substring(1);
|
||||
totalBundleDataSize += putBundleData(bundle,tableName,bundleFile);
|
||||
}
|
||||
|
||||
long stopTime = System.currentTimeMillis();
|
||||
logger.info("Loaded total "+bundleData.size()+" bundles with "+totalBundleDataSize+" keys in "+(stopTime-startTime)+" ms.");
|
||||
|
||||
return bundleLast; // just return last one, not requested one.
|
||||
}
|
||||
|
||||
protected ResourceBundle loadBundleClassPath(String resourceName,ClassLoader loader,boolean reload) throws IOException {
|
||||
ResourceBundle bundle = null;
|
||||
InputStream stream = null;
|
||||
if (reload) {
|
||||
URL url = loader.getResource(resourceName);
|
||||
if (url != null) {
|
||||
URLConnection connection = url.openConnection();
|
||||
if (connection != null) {
|
||||
connection.setUseCaches(false);
|
||||
stream = connection.getInputStream();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stream = loader.getResourceAsStream(resourceName);
|
||||
}
|
||||
if (stream != null) {
|
||||
bundle = loadBundleStream(stream);
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
protected ResourceBundle loadBundleUrl(URL url) throws IOException {
|
||||
ResourceBundle bundle = null;
|
||||
InputStream stream = null;
|
||||
URLConnection connection = url.openConnection();
|
||||
if (connection != null) {
|
||||
connection.setUseCaches(false);
|
||||
stream = connection.getInputStream();
|
||||
}
|
||||
if (stream != null) {
|
||||
bundle = loadBundleStream(stream);
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
protected ResourceBundle loadBundleFile(File file) throws IOException {
|
||||
ResourceBundle bundle = null;
|
||||
InputStream stream = new FileInputStream(file);
|
||||
if (stream != null) {
|
||||
bundle = loadBundleStream(stream);
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
protected ResourceBundle loadBundleStream(InputStream stream) throws IOException {
|
||||
if (stream==null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new PropertyResourceBundle(new InputStreamReader(stream, charSet));
|
||||
} finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void saveBundleFile(Properties properties,File file) throws IOException {
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
try {
|
||||
properties.store(new OutputStreamWriter(out,charSet), BUNDLE_COMMENT+new Date());
|
||||
} finally {
|
||||
if (out!=null) {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.bundle;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Properties;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import org.eobjects.metamodel.AbstractUpdateCallback;
|
||||
import org.eobjects.metamodel.MetaModelException;
|
||||
import org.eobjects.metamodel.UpdateCallback;
|
||||
import org.eobjects.metamodel.create.ColumnCreationBuilder;
|
||||
import org.eobjects.metamodel.create.TableCreationBuilder;
|
||||
import org.eobjects.metamodel.data.DataSet;
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.delete.AbstractRowDeletionBuilder;
|
||||
import org.eobjects.metamodel.delete.RowDeletionBuilder;
|
||||
import org.eobjects.metamodel.drop.AbstractTableDropBuilder;
|
||||
import org.eobjects.metamodel.drop.TableDropBuilder;
|
||||
import org.eobjects.metamodel.insert.AbstractRowInsertionBuilder;
|
||||
import org.eobjects.metamodel.insert.RowInsertionBuilder;
|
||||
import org.eobjects.metamodel.schema.Column;
|
||||
import org.eobjects.metamodel.schema.ColumnType;
|
||||
import org.eobjects.metamodel.schema.Schema;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
|
||||
/**
|
||||
* ResourceBundleUpdateExecutor handles update to ResourceBundleDataContext
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 26, 2012
|
||||
*/
|
||||
public class ResourceBundleUpdateExecutor extends AbstractUpdateCallback {
|
||||
|
||||
protected ResourceBundleDataContext resourceBundleDataContext = null;
|
||||
protected ResourceBundleDataControl resourceBundleDataControl = null;
|
||||
|
||||
public ResourceBundleUpdateExecutor(ResourceBundleDataContext resourceBundleDataContext,ResourceBundleDataControl resourceBundleDataControl) {
|
||||
super(resourceBundleDataContext);
|
||||
this.resourceBundleDataControl=resourceBundleDataControl;
|
||||
}
|
||||
|
||||
public boolean isDataContextWritable() {
|
||||
return resourceBundleDataControl.isWritable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateTableSupported() {
|
||||
return isDataContextWritable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInsertSupported() {
|
||||
return isDataContextWritable();
|
||||
}
|
||||
|
||||
public boolean isDeleteSupported() {
|
||||
return isDataContextWritable();
|
||||
}
|
||||
|
||||
public boolean isDropTableSupported() {
|
||||
return isDataContextWritable();
|
||||
}
|
||||
|
||||
public TableCreationBuilder createTable(final Schema schema, final String name) throws IllegalArgumentException, IllegalStateException {
|
||||
TableCreationBuilder result = new TableCreationBuilder() {
|
||||
public Table toTable() { return execute(); }
|
||||
public String toSql() { return "nosql"; }
|
||||
public TableCreationBuilder like(Table table) { return this; }
|
||||
public ColumnCreationBuilder withColumn(String name) {
|
||||
//return new ColumnCreationBuilderImpl(this,new MutableColumn(name));
|
||||
final TableCreationBuilder parent = this;
|
||||
return new ColumnCreationBuilder() {
|
||||
public ColumnCreationBuilder withColumn(String name) { return this; }
|
||||
public ColumnCreationBuilder ofType(ColumnType type) { return this; }
|
||||
public ColumnCreationBuilder ofSize(int size) { return this; }
|
||||
public ColumnCreationBuilder ofNativeType(String nativeType) { return this; }
|
||||
public ColumnCreationBuilder nullable(boolean nullable) { return this; }
|
||||
public ColumnCreationBuilder asPrimaryKey() { return this; }
|
||||
public ColumnCreationBuilder like(Column column) { return this; }
|
||||
public TableCreationBuilder like(Table table) { return this; }
|
||||
public String toSql() { return "nosql"; }
|
||||
public Table toTable() { return execute(); }
|
||||
public Table execute() throws MetaModelException { return parent.execute();}
|
||||
|
||||
};
|
||||
}
|
||||
public Table execute() throws MetaModelException {
|
||||
File file = new File(name);
|
||||
Properties p = new Properties();
|
||||
try {
|
||||
resourceBundleDataControl.saveBundleFile(p, file);
|
||||
ResourceBundle bundle = resourceBundleDataControl.loadBundleFile(file);
|
||||
resourceBundleDataControl.putBundleData(bundle, name, file);
|
||||
} catch (Exception e) {
|
||||
throw new MetaModelException(e);
|
||||
}
|
||||
return resourceBundleDataContext.createTable(schema, name);
|
||||
}
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
public TableDropBuilder dropTable(Table table) throws IllegalArgumentException, IllegalStateException,UnsupportedOperationException {
|
||||
TableDropBuilder result = new AbstractTableDropBuilder(table) {
|
||||
public void execute() throws MetaModelException {
|
||||
resourceBundleDataControl.removeBundle(getTable().getName());
|
||||
}
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
public RowInsertionBuilder insertInto(final Table table) throws IllegalArgumentException, IllegalStateException,UnsupportedOperationException {
|
||||
RowInsertionBuilder result = new AbstractRowInsertionBuilder<UpdateCallback>(this, table) {
|
||||
public void execute() throws MetaModelException {
|
||||
Properties data = resourceBundleDataControl.getBundleData(table.getName());
|
||||
Object[] values = getValues();
|
||||
data.put(values[1], values[2]);
|
||||
}
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
public RowDeletionBuilder deleteFrom(final Table table) throws IllegalArgumentException, IllegalStateException,UnsupportedOperationException {
|
||||
RowDeletionBuilder result = new AbstractRowDeletionBuilder(table) {
|
||||
public void execute() throws MetaModelException {
|
||||
DataSet ds = resourceBundleDataContext.materializeMainSchemaTable(getTable(),getTable().getColumns(),0);
|
||||
Properties data = resourceBundleDataControl.getBundleData(table.getName());
|
||||
while (ds.next()) {
|
||||
Row row = ds.getRow();
|
||||
if (deleteRow(row)) {
|
||||
data.remove(row.getValue(1)); // delete by key
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,294 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.crud;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.MetaModelException;
|
||||
import org.eobjects.metamodel.UpdateCallback;
|
||||
import org.eobjects.metamodel.UpdateScript;
|
||||
import org.eobjects.metamodel.UpdateableDataContext;
|
||||
import org.eobjects.metamodel.data.DataSet;
|
||||
import org.eobjects.metamodel.data.EmptyDataSet;
|
||||
import org.eobjects.metamodel.data.InMemoryDataSet;
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.delete.RowDeletionBuilder;
|
||||
import org.eobjects.metamodel.insert.RowInsertionBuilder;
|
||||
import org.eobjects.metamodel.query.FromItem;
|
||||
import org.eobjects.metamodel.query.Query;
|
||||
import org.eobjects.metamodel.query.SelectItem;
|
||||
import org.eobjects.metamodel.query.builder.SatisfiedQueryBuilder;
|
||||
import org.eobjects.metamodel.query.builder.SatisfiedWhereBuilder;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
import org.eobjects.metamodel.update.RowUpdationBuilder;
|
||||
|
||||
/**
|
||||
* AbstractCrudDataContext implements the generic abstract crud actions.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 23, 2012
|
||||
*/
|
||||
abstract public class AbstractCrudDataContext implements CrudDataContext {
|
||||
|
||||
abstract public UpdateableRow wrapOrCreateToUpdateableRow(Row row,Table table);
|
||||
|
||||
protected UpdateableDataContext abstractProviderUpdateableDataContext() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateableRow createRow(Table table) {
|
||||
return wrapOrCreateToUpdateableRow(null,table);
|
||||
}
|
||||
|
||||
public void persist(final UpdateableRow row) {
|
||||
UpdateableDataContext dataContext = abstractProviderUpdateableDataContext();
|
||||
dataContext.executeUpdate(new UpdateScript() {
|
||||
public void run(UpdateCallback backendImpl) {
|
||||
RowInsertionBuilder query = backendImpl.insertInto(row.getTable());
|
||||
for (int i=0;i<row.size();i++) {
|
||||
SelectItem si = row.getSelectItem(i);
|
||||
Object value = row.getValue(i);
|
||||
query.value(si.getColumn(), value);
|
||||
}
|
||||
query.execute();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Object merge(final UpdateableRow row) {
|
||||
for (String column:row.getPrimaryKeys()) {
|
||||
if (row.getValue(column)==null) {
|
||||
throw new IllegalStateException("Can't update row where primary key: "+column+" value is null.");
|
||||
}
|
||||
}
|
||||
UpdateableDataContext dataContext = abstractProviderUpdateableDataContext();
|
||||
dataContext.executeUpdate(new UpdateScript() {
|
||||
public void run(UpdateCallback backendImpl) {
|
||||
Object qWhere = backendImpl.update(row.getTable());
|
||||
boolean first = true;
|
||||
List<String> primaryKeyColumns = new ArrayList<String>(30);
|
||||
Collections.addAll(primaryKeyColumns, row.getPrimaryKeys());
|
||||
for (String column:primaryKeyColumns) {
|
||||
Object value = row.getValue(column);
|
||||
queryWhereBuilderUpdate(qWhere,column,value,first);
|
||||
first = false;
|
||||
}
|
||||
List<String> columns = new ArrayList<String>(30);
|
||||
Collections.addAll(columns, row.getTable().getColumnNames());
|
||||
columns.removeAll(primaryKeyColumns);
|
||||
for (String column:columns) {
|
||||
Object value = row.getValue(column);
|
||||
((RowUpdationBuilder)qWhere).value(column, value);
|
||||
}
|
||||
if (first==false) {
|
||||
((RowUpdationBuilder)qWhere).execute();
|
||||
} else {
|
||||
// loggger.warning no where clause
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Object qWhere = dataContext.query().from(row.getTable()).select(row.getTable().getColumns());
|
||||
boolean first = true;
|
||||
for (String column:row.getPrimaryKeys()) {
|
||||
Object value = row.getValue(column);
|
||||
queryWhereBuilder(qWhere,column,value,first);
|
||||
first = false;
|
||||
}
|
||||
Query mergeSelectQuery = ((SatisfiedQueryBuilder<?>)qWhere).toQuery();
|
||||
DataSet ds = dataContext.executeQuery(mergeSelectQuery);
|
||||
if (ds.next()==false) {
|
||||
ds.close();
|
||||
throw new IllegalStateException("Could not fetch row after merging.");
|
||||
}
|
||||
UpdateableRow rowResult = wrapOrCreateToUpdateableRow(ds.getRow(),row.getTable());
|
||||
ds.close();
|
||||
return rowResult;
|
||||
}
|
||||
|
||||
public void delete(final UpdateableRow row) {
|
||||
UpdateableDataContext dataContext = abstractProviderUpdateableDataContext();
|
||||
dataContext.executeUpdate(new UpdateScript() {
|
||||
public void run(UpdateCallback backendImpl) {
|
||||
Object qWhere = backendImpl.deleteFrom(row.getTable());
|
||||
boolean first = true;
|
||||
for (String column:row.getPrimaryKeys()) {
|
||||
Object value = row.getValue(column);
|
||||
queryWhereBuilderDelete(qWhere,column,value,first);
|
||||
first = false;
|
||||
}
|
||||
if (first==false) {
|
||||
((RowDeletionBuilder)qWhere).execute();
|
||||
} else {
|
||||
///logger.warning no where clause
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: redo these queryWhereBuilder methods to cleaner code
|
||||
|
||||
protected Object queryWhereBuilder(Object qWhere,String key,Object value,boolean first) {
|
||||
if (value instanceof Number) {
|
||||
if (first) {
|
||||
qWhere = ((SatisfiedQueryBuilder<?>)qWhere).where(key).equals((Number)value);
|
||||
} else {
|
||||
qWhere = ((SatisfiedWhereBuilder<?>)qWhere).and(key).equals((Number)value);
|
||||
}
|
||||
} else if (value instanceof Date) {
|
||||
if (first) {
|
||||
qWhere = ((SatisfiedQueryBuilder<?>)qWhere).where(key).equals((Date)value);
|
||||
} else {
|
||||
qWhere = ((SatisfiedWhereBuilder<?>)qWhere).and(key).equals((Date)value);
|
||||
}
|
||||
} else if (value instanceof Boolean) {
|
||||
if (first) {
|
||||
qWhere = ((SatisfiedQueryBuilder<?>)qWhere).where(key).equals((Boolean)value);
|
||||
} else {
|
||||
qWhere = ((SatisfiedWhereBuilder<?>)qWhere).and(key).equals((Boolean)value);
|
||||
}
|
||||
} else {
|
||||
if (value==null) {
|
||||
if (first) {
|
||||
qWhere = ((SatisfiedQueryBuilder<?>)qWhere).where(key).isNull();
|
||||
} else {
|
||||
qWhere = ((SatisfiedWhereBuilder<?>)qWhere).and(key).isNull();
|
||||
}
|
||||
} else {
|
||||
if (first) {
|
||||
qWhere = ((SatisfiedQueryBuilder<?>)qWhere).where(key).equals(value.toString());
|
||||
} else {
|
||||
qWhere = ((SatisfiedWhereBuilder<?>)qWhere).and(key).equals(value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return qWhere;
|
||||
}
|
||||
|
||||
protected Object queryWhereBuilderUpdate(Object qWhere,String key,Object value,boolean first) {
|
||||
if (value instanceof Number) {
|
||||
if (first) {
|
||||
qWhere = ((RowUpdationBuilder)qWhere).where(key).equals((Number)value);
|
||||
} else {
|
||||
qWhere = ((RowUpdationBuilder)qWhere).where(key).equals((Number)value);
|
||||
}
|
||||
} else if (value instanceof Date) {
|
||||
if (first) {
|
||||
qWhere = ((RowUpdationBuilder)qWhere).where(key).equals((Date)value);
|
||||
} else {
|
||||
qWhere = ((RowUpdationBuilder)qWhere).where(key).equals((Date)value);
|
||||
}
|
||||
} else if (value instanceof Boolean) {
|
||||
if (first) {
|
||||
qWhere = ((RowUpdationBuilder)qWhere).where(key).equals((Boolean)value);
|
||||
} else {
|
||||
qWhere = ((RowUpdationBuilder)qWhere).where(key).equals((Boolean)value);
|
||||
}
|
||||
} else {
|
||||
if (value==null) {
|
||||
if (first) {
|
||||
qWhere = ((RowUpdationBuilder)qWhere).where(key).isNull();
|
||||
} else {
|
||||
qWhere = ((RowUpdationBuilder)qWhere).where(key).isNull();
|
||||
}
|
||||
} else {
|
||||
if (first) {
|
||||
qWhere = ((RowUpdationBuilder)qWhere).where(key).equals(value.toString());
|
||||
} else {
|
||||
qWhere = ((RowUpdationBuilder)qWhere).where(key).equals(value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return qWhere;
|
||||
}
|
||||
|
||||
protected Object queryWhereBuilderDelete(Object qWhere,String key,Object value,boolean first) {
|
||||
if (value instanceof Number) {
|
||||
if (first) {
|
||||
qWhere = ((RowDeletionBuilder)qWhere).where(key).equals((Number)value);
|
||||
} else {
|
||||
qWhere = ((RowDeletionBuilder)qWhere).where(key).equals((Number)value);
|
||||
}
|
||||
} else if (value instanceof Date) {
|
||||
if (first) {
|
||||
qWhere = ((RowDeletionBuilder)qWhere).where(key).equals((Date)value);
|
||||
} else {
|
||||
qWhere = ((RowDeletionBuilder)qWhere).where(key).equals((Date)value);
|
||||
}
|
||||
} else if (value instanceof Boolean) {
|
||||
if (first) {
|
||||
qWhere = ((RowDeletionBuilder)qWhere).where(key).equals((Boolean)value);
|
||||
} else {
|
||||
qWhere = ((RowDeletionBuilder)qWhere).where(key).equals((Boolean)value);
|
||||
}
|
||||
} else {
|
||||
if (value==null) {
|
||||
if (first) {
|
||||
qWhere = ((RowDeletionBuilder)qWhere).where(key).isNull();
|
||||
} else {
|
||||
qWhere = ((RowDeletionBuilder)qWhere).where(key).isNull();
|
||||
}
|
||||
} else {
|
||||
if (first) {
|
||||
qWhere = ((RowDeletionBuilder)qWhere).where(key).equals(value.toString());
|
||||
} else {
|
||||
qWhere = ((RowDeletionBuilder)qWhere).where(key).equals(value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return qWhere;
|
||||
}
|
||||
|
||||
/**
|
||||
* executeQueryWrapDataSet interface so when implemented on backend then executeQueryWrapDataSet is not used.
|
||||
* There for no need to expose this primary key handler method in this abstract class.
|
||||
*/
|
||||
protected interface QueryWrapDataSetPrimaryKeyHandler {
|
||||
public List<String> getPrimaryKeysForTable(Table table);
|
||||
}
|
||||
|
||||
protected DataSet executeQueryWrapDataSet(DataContext dataContext,Query query,boolean checkPrimaryKeysAllRows,QueryWrapDataSetPrimaryKeyHandler keyHandler) throws MetaModelException {
|
||||
DataSet data = dataContext.executeQuery(query);
|
||||
if (query.getFromClause().getItems().size() > 1) {
|
||||
return data; // Only supports crud on single table data.
|
||||
}
|
||||
FromItem fromItem = query.getFromClause().getItems().get(0);
|
||||
Table table = fromItem.getTable();
|
||||
List<String> keys = keyHandler.getPrimaryKeysForTable(table);
|
||||
if (keys.isEmpty()) {
|
||||
return data;
|
||||
}
|
||||
if (query.getSelectClause().getItemCount()==1 && query.getSelectClause().getItem(0).getColumn()==null) {
|
||||
return data; // TODO: use correct api to detect selectCount query
|
||||
}
|
||||
List<Row> dataWrap = new ArrayList<Row>(2000);
|
||||
boolean keysOke = false; // NOTE: could add option checkPrimaryKeys to override if user/impl is really sure keys are there.
|
||||
boolean keysCheck = true; // always check first row
|
||||
List<String> keysCheckList = new ArrayList<String>(keys); // copy keys
|
||||
while (data.next()) {
|
||||
Row row = data.getRow();
|
||||
if (keysCheck) {
|
||||
for (SelectItem si:row.getSelectItems()) {
|
||||
keysCheckList.remove(si.getColumn().getName());
|
||||
}
|
||||
keysCheck = checkPrimaryKeysAllRows; // default is check first row only.
|
||||
keysOke = keysCheckList.isEmpty(); // Found all primary keys in result so we can wrap data.
|
||||
if (keysCheck) {
|
||||
keysCheckList.addAll(keys); // Reload keys to check all data.
|
||||
}
|
||||
}
|
||||
if (keysOke) {
|
||||
dataWrap.add(wrapOrCreateToUpdateableRow(data.getRow(),table));
|
||||
} else {
|
||||
dataWrap.add(row);
|
||||
}
|
||||
}
|
||||
data.close();
|
||||
if (dataWrap.isEmpty()) {
|
||||
return new EmptyDataSet(table.getColumns());
|
||||
}
|
||||
return new InMemoryDataSet(dataWrap);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.crud;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.data.Style;
|
||||
import org.eobjects.metamodel.query.SelectItem;
|
||||
import org.eobjects.metamodel.schema.Column;
|
||||
|
||||
/**
|
||||
* AbstractRow implements most Row features onto of itself.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 23, 2012
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
abstract public class AbstractRow implements Row,RowLocal {
|
||||
|
||||
protected Map<Integer,MetaRowData> metaData = null;
|
||||
|
||||
public AbstractRow() {
|
||||
metaData = new HashMap<Integer,MetaRowData>(30);
|
||||
}
|
||||
|
||||
public SelectItem getSelectItem(int index) {
|
||||
MetaRowData metaRow = getMetaRowData(index);
|
||||
return metaRow.selectItem;
|
||||
}
|
||||
|
||||
public void addSelectItems(Column[] columns) {
|
||||
for (Column column:columns) {
|
||||
addSelectItem(new SelectItem(column));
|
||||
}
|
||||
}
|
||||
|
||||
public void addSelectItems(SelectItem[] selectItems) {
|
||||
for (SelectItem selectItem:selectItems) {
|
||||
addSelectItem(selectItem);
|
||||
}
|
||||
}
|
||||
|
||||
public void addSelectItems(List<SelectItem> selectItems) {
|
||||
for (SelectItem selectItem:selectItems) {
|
||||
addSelectItem(selectItem);
|
||||
}
|
||||
}
|
||||
|
||||
public void addSelectItem(SelectItem selectItem) {
|
||||
MetaRowData metaRow = new MetaRowData();
|
||||
metaRow.selectItem=selectItem;
|
||||
metaData.put(metaData.size(), metaRow);
|
||||
}
|
||||
|
||||
public MetaRowData getMetaRowData(int index) {
|
||||
MetaRowData metaRow = metaData.get(index);
|
||||
return metaRow;
|
||||
}
|
||||
|
||||
public List<MetaRowData> getIndexedMetaRowDataList() {
|
||||
List<MetaRowData> result = new ArrayList<MetaRowData>(size());
|
||||
for (int i=0;i<metaData.size();i++) {
|
||||
MetaRowData metaRow = metaData.get(i);
|
||||
result.add(metaRow);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<SelectItem> getIndexedSelectItemList() {
|
||||
List<SelectItem> result = new ArrayList<SelectItem>(size());
|
||||
for (MetaRowData metaRow:getIndexedMetaRowDataList()) {
|
||||
result.add(metaRow.selectItem);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setStyle(int index,Style style) {
|
||||
MetaRowData metaRow = metaData.get(index);
|
||||
metaRow.style=style;
|
||||
}
|
||||
|
||||
class MetaRowData /* implements DataSetRowMetaData */ {
|
||||
SelectItem selectItem;
|
||||
Style style;
|
||||
// name and backendIndex,etc so DataSetApi does not need SchemaApi, when using schema aware code like an DataContext
|
||||
// the DC api does not change because it fill/config/wires the DS api with meta data from schema.
|
||||
// When using DataSet api in non-schema aware code then caller has to provided meta data for api to work.
|
||||
// ObjectConverter objectConverter
|
||||
// List<ObjectValidator>
|
||||
// etc/etc
|
||||
}
|
||||
|
||||
// ==== Start interface
|
||||
|
||||
public Object[] getValues() {
|
||||
Object[] result = new Object[size()];
|
||||
for (int i=0;i<size();i++) {
|
||||
result[i] = getValue(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Object getValue(SelectItem item) {
|
||||
return getValue(indexOf(item));
|
||||
}
|
||||
|
||||
public Object getValue(Column column) {
|
||||
return getValue(indexOf(column));
|
||||
}
|
||||
|
||||
public int indexOf(SelectItem item) {
|
||||
if (item == null) {
|
||||
return UpdateableRow.INDEX_NOT_FOUND;
|
||||
}
|
||||
int i = 0;
|
||||
for (SelectItem selectItem : getIndexedSelectItemList()) {
|
||||
if (item.equalsIgnoreAlias(selectItem)) {
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return UpdateableRow.INDEX_NOT_FOUND;
|
||||
}
|
||||
|
||||
public int indexOf(Column column) {
|
||||
if (column == null) {
|
||||
return UpdateableRow.INDEX_NOT_FOUND;
|
||||
}
|
||||
SelectItem selectItem = new SelectItem(column);
|
||||
return indexOf(selectItem);
|
||||
}
|
||||
|
||||
public SelectItem[] getSelectItems() {
|
||||
List<SelectItem> list = getIndexedSelectItemList();
|
||||
SelectItem[] result = new SelectItem[list.size()];
|
||||
return list.toArray(result);
|
||||
}
|
||||
|
||||
public Style getStyle(SelectItem item) {
|
||||
return getStyle(indexOf(item));
|
||||
}
|
||||
|
||||
public Style getStyle(Column column) {
|
||||
return getStyle(indexOf(column));
|
||||
}
|
||||
|
||||
public Style getStyle(int index) throws IndexOutOfBoundsException {
|
||||
MetaRowData metaRow = getMetaRowData(index);
|
||||
if (metaRow==null) {
|
||||
return Style.NO_STYLE;
|
||||
}
|
||||
if (metaRow.style==null) {
|
||||
return Style.NO_STYLE;
|
||||
}
|
||||
return metaRow.style;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return metaData.size();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.crud;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.data.Style;
|
||||
import org.eobjects.metamodel.query.SelectItem;
|
||||
import org.eobjects.metamodel.schema.Column;
|
||||
|
||||
/**
|
||||
* AbstractUpdateableRow implements some setters of UpdateableRow interface.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 23, 2012
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
abstract public class AbstractUpdateableRow extends AbstractRow implements UpdateableRow {
|
||||
|
||||
// TODO: rm / move getValue and indexOf to AbstractRow after UpdateableRow interface change
|
||||
public Object getValue(String columnName) {
|
||||
return getValue(indexOf(columnName));
|
||||
}
|
||||
public int indexOf(String columnName) {
|
||||
if (columnName==null) {
|
||||
return UpdateableRow.INDEX_NOT_FOUND;
|
||||
}
|
||||
int index = 0;
|
||||
for (SelectItem si:getIndexedSelectItemList()) {
|
||||
if (si.getColumn().getName().equals(columnName)) {
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return UpdateableRow.INDEX_NOT_FOUND;
|
||||
}
|
||||
|
||||
public void setValue(Row row) {
|
||||
for (SelectItem selectItem:row.getSelectItems()) {
|
||||
Object value = row.getValue(selectItem);
|
||||
setValue(indexOf(selectItem),value);
|
||||
}
|
||||
}
|
||||
|
||||
public void setValue(String columnName,Object object) {
|
||||
setValue(indexOf(columnName), object);
|
||||
}
|
||||
|
||||
public void setValue(SelectItem selectItem,Object object) {
|
||||
setValue(indexOf(selectItem),object);
|
||||
}
|
||||
|
||||
public void setValue(Column column,Object object) {
|
||||
setValue(indexOf(column),object);
|
||||
}
|
||||
|
||||
public String[] getPrimaryKeys() {
|
||||
List<String> primaryKeys = getPrimaryKeysList();
|
||||
return primaryKeys.toArray(new String[primaryKeys.size()]);
|
||||
}
|
||||
|
||||
public Row getSubSelectionFromImpl(AbstractUpdateableRow rowImpl,SelectItem[] selectItems) {
|
||||
for (SelectItem selectItem:selectItems) {
|
||||
int index = rowImpl.indexOf(selectItem);
|
||||
Object value = null;
|
||||
Style style = null;
|
||||
|
||||
if (selectItem.getSubQuerySelectItem() != null) {
|
||||
value = getValue(selectItem.getSubQuerySelectItem());
|
||||
style = getStyle(selectItem.getSubQuerySelectItem());
|
||||
}
|
||||
if (value == null) {
|
||||
value = getValue(selectItem);
|
||||
style = getStyle(selectItem);
|
||||
}
|
||||
rowImpl.setValue(index, value);
|
||||
rowImpl.setStyle(index, style);
|
||||
}
|
||||
return rowImpl;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.crud;
|
||||
|
||||
import org.eobjects.metamodel.UpdateableDataContext;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
|
||||
/**
|
||||
* CrudDataContext provides Create/Update/Delete operations on row level of table.
|
||||
*
|
||||
* note: UpdateableDataContext can implement UpdateableRowDataContext interface to provide native support for UpdateableRow in DataSet.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 23, 2012
|
||||
*/
|
||||
public interface CrudDataContext extends UpdateableDataContext {
|
||||
|
||||
/**
|
||||
* Creates empty row to fill and persist.
|
||||
*/
|
||||
public UpdateableRow createRow(Table table);
|
||||
|
||||
/**
|
||||
* Inserts row into table.
|
||||
*/
|
||||
public void persist(UpdateableRow row);
|
||||
|
||||
/**
|
||||
* Merges row with table.
|
||||
*/
|
||||
public Object merge(UpdateableRow row);
|
||||
|
||||
/**
|
||||
* Deletes row from table.
|
||||
*/
|
||||
public void delete(UpdateableRow row);
|
||||
}
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.crud;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.MetaModelException;
|
||||
import org.eobjects.metamodel.UpdateScript;
|
||||
import org.eobjects.metamodel.UpdateableDataContext;
|
||||
import org.eobjects.metamodel.data.DataSet;
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.query.Query;
|
||||
import org.eobjects.metamodel.query.builder.InitFromBuilder;
|
||||
import org.eobjects.metamodel.query.builder.InitFromBuilderImpl;
|
||||
import org.eobjects.metamodel.schema.Column;
|
||||
import org.eobjects.metamodel.schema.ColumnType;
|
||||
import org.eobjects.metamodel.schema.Schema;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
|
||||
/**
|
||||
* CrudDataContextImpl is implementation of CrudDataContext interface which provides crud operations on UpdateableDataContext
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 23, 2012
|
||||
*/
|
||||
public class CrudDataContextImpl extends AbstractCrudDataContext implements AbstractCrudDataContext.QueryWrapDataSetPrimaryKeyHandler {
|
||||
|
||||
protected UpdateableDataContext dataContextDelegate = null;
|
||||
protected Map<String,List<String>> tableKeys = null;
|
||||
private boolean checkPrimaryKeysAllRows = false;
|
||||
|
||||
public CrudDataContextImpl(UpdateableDataContext dataContext) {
|
||||
dataContextDelegate = dataContext;
|
||||
tableKeys = new HashMap<String,List<String>>(100);
|
||||
}
|
||||
|
||||
public void overridePrimaryKeysForTable(String table,List<String> keys) {
|
||||
tableKeys.put(table, keys);
|
||||
}
|
||||
|
||||
public List<String> getPrimaryKeysForTable(Table table) {
|
||||
List<String> keys = tableKeys.get(table.getName());
|
||||
if (keys!=null) {
|
||||
return keys;
|
||||
}
|
||||
keys = new ArrayList<String>(5);
|
||||
for (Column k:table.getPrimaryKeys()) {
|
||||
keys.add(k.getName()); // strange getPrimaryKeys is mostly empty, check SimpleTableDef.toTable or MutableColumn.setType to fix
|
||||
}
|
||||
// start test hack code
|
||||
if (keys.isEmpty()) {
|
||||
for (Column k:table.getColumnsOfType(ColumnType.ROWID)) { // mmm still empty
|
||||
keys.add(k.getName());
|
||||
}
|
||||
if (keys.isEmpty()) {
|
||||
for (Column k:table.getColumns()) {
|
||||
String colName = k.getName();
|
||||
if (colName.equals("_id")) {
|
||||
keys.add(colName);
|
||||
} else if (colName.equalsIgnoreCase("id")) { // TODO: rm this quick hard code ID search
|
||||
keys.add(colName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// stop test hack code
|
||||
if (keys.isEmpty()) {
|
||||
throw new IllegalStateException("Can't work with table: "+table+" without primary key.");
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the actual automatic Row to UpdateableRow wrapping.
|
||||
*/
|
||||
@Override
|
||||
public UpdateableRow wrapOrCreateToUpdateableRow(Row row,Table table) {
|
||||
UpdateableRowMapImpl result = new UpdateableRowMapImpl(table,getPrimaryKeysForTable(table));
|
||||
if (row==null) {
|
||||
result.addSelectItems(table.getColumns()); // create new when row is null
|
||||
} else {
|
||||
result.addSelectItems(row.getSelectItems());
|
||||
result.setValue(row); // copy all values to impl
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if backend dataContextDelegate has native support for UpdateableRowDataContext.
|
||||
* If not then automatic wrap full DataSet data to UpdateableRow
|
||||
*/
|
||||
public DataSet executeQuery(Query query) throws MetaModelException {
|
||||
if (dataContextDelegate instanceof UpdateableRowDataContext) {
|
||||
return ((UpdateableRowDataContext) dataContextDelegate).crudExecuteQuery(this,query);
|
||||
} else {
|
||||
return executeQueryWrapDataSet(dataContextDelegate,query,isCheckPrimaryKeysAllRows(),this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if backend dataContextDelegate has native support for UpdateableRowDataContext.
|
||||
* If so then use api to start query builder with this datacontext.
|
||||
* Else use default InitFromBuilderImpl query builder.
|
||||
*/
|
||||
public InitFromBuilder query() {
|
||||
if (dataContextDelegate instanceof UpdateableRowDataContext) {
|
||||
return ((UpdateableRowDataContext) dataContextDelegate).crudCreateQuery(this);
|
||||
} else {
|
||||
return new InitFromBuilderImpl(this);
|
||||
}
|
||||
}
|
||||
|
||||
// === Bean properties
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the checkPrimaryKeysAllRows
|
||||
*/
|
||||
public boolean isCheckPrimaryKeysAllRows() {
|
||||
return checkPrimaryKeysAllRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param checkPrimaryKeysAllRows the checkPrimaryKeysAllRows to set
|
||||
*/
|
||||
public void setCheckPrimaryKeysAllRows(boolean checkPrimaryKeysAllRows) {
|
||||
this.checkPrimaryKeysAllRows = checkPrimaryKeysAllRows;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// === Start wrapper to dataContextDelegate
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eobjects.metamodel.UpdateableDataContext#executeUpdate(org.eobjects.metamodel.UpdateScript)
|
||||
*/
|
||||
public void executeUpdate(UpdateScript arg0) {
|
||||
dataContextDelegate.executeUpdate(arg0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eobjects.metamodel.DataContext#getColumnByQualifiedLabel(java.lang.String)
|
||||
*/
|
||||
public Column getColumnByQualifiedLabel(String arg0) {
|
||||
return dataContextDelegate.getColumnByQualifiedLabel(arg0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eobjects.metamodel.DataContext#getDefaultSchema()
|
||||
*/
|
||||
public Schema getDefaultSchema() throws MetaModelException {
|
||||
return dataContextDelegate.getDefaultSchema();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eobjects.metamodel.DataContext#getSchemaByName(java.lang.String)
|
||||
*/
|
||||
public Schema getSchemaByName(String arg0) throws MetaModelException {
|
||||
return dataContextDelegate.getSchemaByName(arg0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eobjects.metamodel.DataContext#getSchemaNames()
|
||||
*/
|
||||
public String[] getSchemaNames() throws MetaModelException {
|
||||
return dataContextDelegate.getSchemaNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eobjects.metamodel.DataContext#getSchemas()
|
||||
*/
|
||||
public Schema[] getSchemas() throws MetaModelException {
|
||||
return dataContextDelegate.getSchemas();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eobjects.metamodel.DataContext#getTableByQualifiedLabel(java.lang.String)
|
||||
*/
|
||||
public Table getTableByQualifiedLabel(String arg0) {
|
||||
return dataContextDelegate.getTableByQualifiedLabel(arg0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eobjects.metamodel.DataContext#refreshSchemas()
|
||||
*/
|
||||
public DataContext refreshSchemas() {
|
||||
return dataContextDelegate.refreshSchemas();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.crud;
|
||||
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.data.Style;
|
||||
|
||||
/**
|
||||
* RowLocal is the set version of Row interface.
|
||||
*
|
||||
* Currently only needed setStyle to make duplicate code in Row.getSubSelection(SelectItem[] selectItems) abstract so impl can do one liner.
|
||||
* other option is move all get/setStyle to one RowStyle interface as that data is almost always locally implemented.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 23, 2012
|
||||
*/
|
||||
public interface RowLocal extends Row {
|
||||
|
||||
public void setStyle(int index,Style style);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.crud;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.query.SelectItem;
|
||||
import org.eobjects.metamodel.schema.Column;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
|
||||
/**
|
||||
* UpdateableRow is the setValue(...) version of Row interface.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 23, 2012
|
||||
*/
|
||||
public interface UpdateableRow extends Row {
|
||||
|
||||
// TODO: move these 3 to Row interface
|
||||
public SelectItem getSelectItem(int index);
|
||||
public Object getValue(String columnName);
|
||||
public static final int INDEX_NOT_FOUND = -1;
|
||||
|
||||
/**
|
||||
* Returns the table
|
||||
*/
|
||||
public Table getTable();
|
||||
|
||||
/**
|
||||
* Returns primary keys of table.
|
||||
*/
|
||||
public List<String> getPrimaryKeysList();
|
||||
|
||||
/**
|
||||
* Returns primary keys of table.
|
||||
*/
|
||||
public String[] getPrimaryKeys();
|
||||
|
||||
/**
|
||||
* Sets the value by the column name.
|
||||
*
|
||||
* @param columnName
|
||||
* @param object
|
||||
*/
|
||||
public void setValue(String columnName,Object object);
|
||||
|
||||
/**
|
||||
* Sets the value of the provided SelectItem.
|
||||
*
|
||||
* @param item
|
||||
* @return the value that corresponds to the provided SelectItem. Can be
|
||||
* null if either the value <i>is</i> null or if no value exists
|
||||
* that matches the SelectItem.
|
||||
*/
|
||||
public void setValue(SelectItem item,Object object);
|
||||
|
||||
/**
|
||||
* Shorthand method for setting the value of a SelectItem based on the
|
||||
* provided column. Invoking this method is equivalent to invoking
|
||||
* setValue(new SelectItem(column)).
|
||||
*
|
||||
* @param column
|
||||
* @return the value of the specified column
|
||||
*/
|
||||
public void setValue(Column column,Object object);
|
||||
|
||||
/**
|
||||
* Sets the value of the row at a given index
|
||||
*
|
||||
* @param index
|
||||
* @return the value at the specified index
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the provided index is out of range
|
||||
*/
|
||||
public void setValue(int index,Object object) throws IndexOutOfBoundsException;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.crud;
|
||||
|
||||
import org.eobjects.metamodel.data.DataSet;
|
||||
import org.eobjects.metamodel.query.Query;
|
||||
import org.eobjects.metamodel.query.builder.InitFromBuilder;
|
||||
|
||||
/**
|
||||
* UpdateableRowDataContext to let DataContexts integrate CrudDataContext without wrapping data.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 24, 2012
|
||||
*/
|
||||
public interface UpdateableRowDataContext {
|
||||
|
||||
/**
|
||||
* Gets called by executeQuery from crud to this impl which knows how to return UpdateableRow DataSet.
|
||||
*/
|
||||
public DataSet crudExecuteQuery(CrudDataContext crudDataContext,Query query);
|
||||
|
||||
/**
|
||||
* Start the query builder with correct data context for execute call back.
|
||||
*/
|
||||
public InitFromBuilder crudCreateQuery(CrudDataContext crudDataContext);
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.crud;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.query.SelectItem;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
|
||||
/**
|
||||
* UpdateableRowMapImpl is basic implementation of UpdateableRow interface.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 23, 2012
|
||||
*/
|
||||
public class UpdateableRowMapImpl extends AbstractUpdateableRow {
|
||||
|
||||
private static final long serialVersionUID = 7660759661023194759L;
|
||||
private Map<Integer,Object> dataMap = null;
|
||||
private Table table = null;
|
||||
private List<String> primaryKeys = null;
|
||||
|
||||
public UpdateableRowMapImpl(Table table,List<String> primaryKeys) {
|
||||
this(table,primaryKeys,null);
|
||||
}
|
||||
|
||||
public UpdateableRowMapImpl(Table table,List<String> primaryKeys,SelectItem[] selectItems) {
|
||||
if (table==null) { throw new NullPointerException("Can't work with null table."); }
|
||||
if (primaryKeys==null) { throw new NullPointerException("Can't work with null primaryKeys."); }
|
||||
this.dataMap = new HashMap<Integer,Object>(30);
|
||||
this.table=table;
|
||||
this.primaryKeys = primaryKeys;
|
||||
if (selectItems!=null) {
|
||||
addSelectItems(selectItems);
|
||||
}
|
||||
}
|
||||
|
||||
// interface
|
||||
|
||||
public Table getTable() {
|
||||
return table;
|
||||
}
|
||||
|
||||
public List<String> getPrimaryKeysList() {
|
||||
return primaryKeys;
|
||||
}
|
||||
|
||||
public void setValue(int index, Object value) throws IndexOutOfBoundsException {
|
||||
dataMap.put(index, value);
|
||||
}
|
||||
|
||||
public Object getValue(int index) throws IndexOutOfBoundsException {
|
||||
return dataMap.get(index);
|
||||
}
|
||||
|
||||
public Row getSubSelection(SelectItem[] selectItems) {
|
||||
return getSubSelectionFromImpl(new UpdateableRowMapImpl(table,primaryKeys,selectItems),selectItems);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.jndi;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
|
||||
/**
|
||||
* DataContextProvider will create of fetch an DataContext for use.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 22, 2012
|
||||
*/
|
||||
public interface DataContextProvider {
|
||||
|
||||
public DataContext getDataContext();
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.jndi;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.spi.ObjectFactory;
|
||||
|
||||
import net.forwardfire.vasc.backend.metamodel.jndi.loader.JndiCsvDataContextLoader;
|
||||
import net.forwardfire.vasc.backend.metamodel.jndi.loader.JndiDataContextLoader;
|
||||
import net.forwardfire.vasc.backend.metamodel.jndi.loader.JndiDataContextLoaderConfig;
|
||||
import net.forwardfire.vasc.backend.metamodel.jndi.loader.JndiJdbcDataContextLoader;
|
||||
import net.forwardfire.vasc.backend.metamodel.jndi.loader.JndiMongodbDataContextLoader;
|
||||
import net.forwardfire.vasc.backend.metamodel.jndi.loader.JndiXmlDomDataContextLoader;
|
||||
import net.forwardfire.vasc.backend.metamodel.jndi.loader.JndiXmlSaxDataContextLoader;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.UpdateableDataContext;
|
||||
|
||||
/**
|
||||
* JndiDataContextObjectFactory provides data contexts on application scope level for
|
||||
* all (EE) servers which provides java naming support.
|
||||
*
|
||||
* Tomcat context.xml config example;
|
||||
* <pre>
|
||||
* <Resource name="metamodel/databaseExampleDC" auth="Container" type="org.eobjects.metamodel.DataContext"
|
||||
* factory="net.forwardfire.vasc.backend.metamodel.jndi.JndiDataContextObjectFactory"
|
||||
* backendType="jdbcJndi" backendUrl="java:jdbc/databaseExampleDS"
|
||||
* />
|
||||
* </pre>
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 22, 2012
|
||||
*/
|
||||
public class JndiDataContextObjectFactory implements ObjectFactory {
|
||||
|
||||
protected DataContext dataContext = null;
|
||||
public enum BackendType {
|
||||
jdbcJndi,jdbc,mongodb,mongodbJndi,csvFile,csvUrl,xmlDomFile,xmlDomUrl,xmlSaxFile,xmlSaxUrl,providerClass
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.naming.spi.ObjectFactory#getObjectInstance(java.lang.Object, javax.naming.Name, javax.naming.Context, java.util.Hashtable)
|
||||
*/
|
||||
synchronized public Object getObjectInstance(Object obj, Name namePath, Context nameCtx,Hashtable<?, ?> env) throws Exception {
|
||||
|
||||
// Create only once.
|
||||
if (dataContext!=null) {
|
||||
return dataContext;
|
||||
}
|
||||
|
||||
// Create objectName to print with errors
|
||||
StringBuffer buf = new StringBuffer(40);
|
||||
for (int i=0;i<namePath.size();i++) {
|
||||
buf.append(namePath.get(i));
|
||||
}
|
||||
String objectName = buf.toString(); // note: print only last part of full name path
|
||||
|
||||
// Wrap to loader and config bean
|
||||
JndiDataContextLoaderConfig config = new JndiDataContextLoaderConfig(obj,namePath,nameCtx,env,objectName);
|
||||
BackendType type = BackendType.valueOf(config.getBackendType());
|
||||
JndiDataContextLoader loader = null;
|
||||
|
||||
// Config loader
|
||||
switch (type) {
|
||||
default: throw new IllegalStateException("Can't handle unimplemented backendType: "+config.getBackendType());
|
||||
case jdbcJndi: loader = new JndiJdbcDataContextLoader(); break;
|
||||
case jdbc: loader = new JndiJdbcDataContextLoader(false); break;
|
||||
case mongodb: loader = new JndiMongodbDataContextLoader(); break;
|
||||
case mongodbJndi: loader = new JndiMongodbDataContextLoader(true); break;
|
||||
case csvFile: loader = new JndiCsvDataContextLoader(); break;
|
||||
case csvUrl: loader = new JndiCsvDataContextLoader(true); break;
|
||||
case xmlDomFile: loader = new JndiXmlDomDataContextLoader(); break;
|
||||
case xmlDomUrl: loader = new JndiXmlDomDataContextLoader(true); break;
|
||||
case xmlSaxFile: loader = new JndiXmlSaxDataContextLoader(); break;
|
||||
case xmlSaxUrl: loader = new JndiXmlSaxDataContextLoader(true); break;
|
||||
case providerClass:
|
||||
dataContext = createDataContextProvider(objectName,config.getBackendClass()).getDataContext();
|
||||
break;
|
||||
}
|
||||
|
||||
// Load data context except when using the providerClass type.
|
||||
if (loader!=null) {
|
||||
dataContext = loader.loadDataContext(config);
|
||||
}
|
||||
|
||||
// Make data context read only is requested by config of factory.
|
||||
if ("true".equalsIgnoreCase(config.getBackendReadOnly()) && dataContext instanceof UpdateableDataContext) {
|
||||
dataContext = new JndiReadOnlyDataContext(dataContext);
|
||||
}
|
||||
|
||||
// We are done lets return
|
||||
return dataContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load DataContextProvider from class path to provide data context.
|
||||
*/
|
||||
protected DataContextProvider createDataContextProvider(String objectName,String className) {
|
||||
if (className==null) {
|
||||
throw new IllegalArgumentException("Can't work with null backendClass attribute for: "+objectName);
|
||||
}
|
||||
if (className.isEmpty()) {
|
||||
throw new IllegalArgumentException("Can't work with empty backendClass attribute for: "+objectName);
|
||||
}
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
if (cl==null) {
|
||||
cl = getClass().getClassLoader();
|
||||
}
|
||||
try {
|
||||
Class<?> providerClass = cl.loadClass(className);
|
||||
DataContextProvider dataContextProvider = (DataContextProvider)providerClass.newInstance();
|
||||
return dataContextProvider;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Could not create provider of: "+className,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.jndi;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
|
||||
/**
|
||||
* JndiDataContextProvider retreives a DataContext from the jndi tree by the jndiName.
|
||||
*
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 22, 2012
|
||||
*/
|
||||
public class JndiDataContextProvider implements DataContextProvider {
|
||||
|
||||
private String jndiName = null;
|
||||
|
||||
/**
|
||||
* Returns an DataContext object from the jndi tree.
|
||||
*/
|
||||
public DataContext getDataContext() {
|
||||
try {
|
||||
InitialContext context = new InitialContext();
|
||||
DataContext dataContext = (DataContext)context.lookup(jndiName);
|
||||
return dataContext;
|
||||
} catch (NamingException e) {
|
||||
throw new IllegalStateException("Jndi naming error on: "+jndiName,e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jndiName
|
||||
*/
|
||||
public String getJndiName() {
|
||||
return jndiName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jndiName the jndiName to set
|
||||
*/
|
||||
public void setJndiName(String jndiName) {
|
||||
this.jndiName = jndiName;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.jndi;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.MetaModelException;
|
||||
import org.eobjects.metamodel.data.DataSet;
|
||||
import org.eobjects.metamodel.query.Query;
|
||||
import org.eobjects.metamodel.query.builder.InitFromBuilder;
|
||||
import org.eobjects.metamodel.schema.Column;
|
||||
import org.eobjects.metamodel.schema.Schema;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
|
||||
/**
|
||||
* JndiReadOnlyDataContext makes DataContext read only by removing the UpdateableDataContext interface.
|
||||
*
|
||||
* @author Willem Cazanders
|
||||
* @version 1.0 May 22, 2012
|
||||
*/
|
||||
public class JndiReadOnlyDataContext /* extends DataContextProxy */ implements DataContext {
|
||||
private DataContext proxyDataContext = null;
|
||||
public JndiReadOnlyDataContext(DataContext proxyDataContext) {
|
||||
this.proxyDataContext=proxyDataContext;
|
||||
}
|
||||
public DataSet executeQuery(Query arg0) throws MetaModelException {
|
||||
return proxyDataContext.executeQuery(arg0);
|
||||
}
|
||||
public Column getColumnByQualifiedLabel(String arg0) {
|
||||
return proxyDataContext.getColumnByQualifiedLabel(arg0);
|
||||
}
|
||||
public Schema getDefaultSchema() throws MetaModelException {
|
||||
return proxyDataContext.getDefaultSchema();
|
||||
}
|
||||
public Schema getSchemaByName(String arg0) throws MetaModelException {
|
||||
return proxyDataContext.getSchemaByName(arg0);
|
||||
}
|
||||
public String[] getSchemaNames() throws MetaModelException {
|
||||
return proxyDataContext.getSchemaNames();
|
||||
}
|
||||
public Schema[] getSchemas() throws MetaModelException {
|
||||
return proxyDataContext.getSchemas();
|
||||
}
|
||||
public Table getTableByQualifiedLabel(String arg0) {
|
||||
return proxyDataContext.getTableByQualifiedLabel(arg0);
|
||||
}
|
||||
public InitFromBuilder query() {
|
||||
return proxyDataContext.query();
|
||||
}
|
||||
public DataContext refreshSchemas() {
|
||||
return proxyDataContext.refreshSchemas();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.jndi.loader;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.csv.CsvConfiguration;
|
||||
import org.eobjects.metamodel.csv.CsvDataContext;
|
||||
|
||||
/**
|
||||
* JndiCsvDataContextLoader Loads and confis csv DataContext from jndi loader config.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 22, 2012
|
||||
*/
|
||||
public class JndiCsvDataContextLoader implements JndiDataContextLoader {
|
||||
|
||||
private boolean useUrlSource = false;
|
||||
|
||||
public JndiCsvDataContextLoader() {
|
||||
}
|
||||
public JndiCsvDataContextLoader(boolean useUrlSource) {
|
||||
setUseUrlSource(useUrlSource);
|
||||
}
|
||||
|
||||
public DataContext loadDataContext(JndiDataContextLoaderConfig config) {
|
||||
if (useUrlSource) {
|
||||
return new CsvDataContext(config.checkBackendUrl(),createCsvConfig(config.getBackendParameters()));
|
||||
} else {
|
||||
return new CsvDataContext(config.checkFile(),createCsvConfig(config.getBackendParameters()));
|
||||
}
|
||||
}
|
||||
|
||||
protected CsvConfiguration createCsvConfig(Map<String,String> param) {
|
||||
int columnNameLineNumber = 0;
|
||||
String encoding = "UTF-8";
|
||||
char separatorChar = CsvConfiguration.DEFAULT_SEPARATOR_CHAR;
|
||||
char quoteChar = CsvConfiguration.DEFAULT_QUOTE_CHAR;
|
||||
char escapeChar = CsvConfiguration.DEFAULT_ESCAPE_CHAR;
|
||||
boolean failOnInconsistentRowLength = false;
|
||||
if (param.containsKey("fileEnconding")) {
|
||||
encoding = param.get("fileEnconding");
|
||||
}
|
||||
if (param.containsKey("separatorChar")) {
|
||||
separatorChar = param.get("separatorChar").charAt(0);
|
||||
}
|
||||
if (param.containsKey("quoteChar")) {
|
||||
quoteChar = param.get("quoteChar").charAt(0);
|
||||
}
|
||||
if (param.containsKey("escapeChar")) {
|
||||
escapeChar = param.get("escapeChar").charAt(0);
|
||||
}
|
||||
if (param.containsKey("failOnInconsistentRowLength")) {
|
||||
failOnInconsistentRowLength = true;
|
||||
}
|
||||
return new CsvConfiguration(columnNameLineNumber,encoding,separatorChar,quoteChar,escapeChar,failOnInconsistentRowLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the useUrlSource
|
||||
*/
|
||||
public boolean isUseUrlSource() {
|
||||
return useUrlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param useUrlSource the useUrlSource to set
|
||||
*/
|
||||
public void setUseUrlSource(boolean useUrlSource) {
|
||||
this.useUrlSource = useUrlSource;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.jndi.loader;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
|
||||
/**
|
||||
* JndiDataContextLoader loads and config the DataContext(DC) from the loader config.
|
||||
* This makes the jndi factory class independent from all MetaModel DC classes.
|
||||
* So we can have one factory for all DC without needing all DC libs in classpath when
|
||||
* most are not needed if using only one or two different DC's.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 22, 2012
|
||||
*/
|
||||
public interface JndiDataContextLoader {
|
||||
|
||||
public DataContext loadDataContext(JndiDataContextLoaderConfig config);
|
||||
}
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.jndi.loader;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.RefAddr;
|
||||
import javax.naming.Reference;
|
||||
|
||||
/**
|
||||
* JndiDataContextLoaderConfig hold generic parameters to config the loader and DataContext.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 22, 2012
|
||||
*/
|
||||
public class JndiDataContextLoaderConfig {
|
||||
|
||||
public final static String BACKEND_TYPE = "backendType";
|
||||
public final static String BACKEND_FILE = "backendFile";
|
||||
public final static String BACKEND_URL = "backendUrl";
|
||||
public final static String BACKEND_HOST = "backendHost";
|
||||
public final static String BACKEND_PORT = "backendPort";
|
||||
public final static String BACKEND_DB = "backendDatabase";
|
||||
public final static String BACKEND_USER = "backendUsername";
|
||||
public final static String BACKEND_PASS = "backendPassword";
|
||||
public final static String BACKEND_CLASS= "backendClass";
|
||||
public final static String BACKEND_READ_ONLY = "backendReadOnly";
|
||||
|
||||
private Object jndiObject = null;
|
||||
private Name jndiNamePath = null;
|
||||
private Context jndiContext = null;
|
||||
private Hashtable<?, ?> jndiEnv = null;
|
||||
private String jndiObjectName = null;
|
||||
private String backendType = null;
|
||||
private String backendFile = null;
|
||||
private String backendUrl = null;
|
||||
private String backendHost = null;
|
||||
private String backendPort = null;
|
||||
private String backendDatabase = null;
|
||||
private String backendUsername = null;
|
||||
private String backendPassword = null;
|
||||
private String backendClass = null;
|
||||
private String backendReadOnly = null;
|
||||
private Map<String,String> backendParameters = null;
|
||||
|
||||
public JndiDataContextLoaderConfig(Object jndiObject,Name jndiNamePath,Context jndiContext,Hashtable<?, ?> jndiEnv,String jndiObjectName) {
|
||||
this.jndiObject=jndiObject;
|
||||
this.jndiNamePath=jndiNamePath;
|
||||
this.jndiContext=jndiContext;
|
||||
this.jndiEnv=jndiEnv;
|
||||
this.jndiObjectName=jndiObjectName;
|
||||
|
||||
initBackendParameters();
|
||||
initBeanParameters();
|
||||
}
|
||||
|
||||
protected void initBackendParameters() {
|
||||
// Copy config parameters of this factory instance to map
|
||||
backendParameters = new HashMap<String,String>(30);
|
||||
Reference ref = (Reference) getJndiObject();
|
||||
Enumeration<?> addrs = ref.getAll();
|
||||
while (addrs.hasMoreElements()) {
|
||||
RefAddr addr = (RefAddr) addrs.nextElement();
|
||||
String name = addr.getType();
|
||||
String value = (String) addr.getContent();
|
||||
backendParameters.put(name,value);
|
||||
}
|
||||
}
|
||||
|
||||
protected void initBeanParameters() {
|
||||
// Check out most generic parameters
|
||||
backendType = backendParameters.get(BACKEND_TYPE);
|
||||
backendFile = backendParameters.get(BACKEND_FILE);
|
||||
backendUrl = backendParameters.get(BACKEND_URL);
|
||||
backendHost = backendParameters.get(BACKEND_HOST);
|
||||
backendPort = backendParameters.get(BACKEND_PORT);
|
||||
backendDatabase = backendParameters.get(BACKEND_DB);
|
||||
backendUsername = backendParameters.get(BACKEND_USER);
|
||||
backendPassword = backendParameters.get(BACKEND_PASS);
|
||||
backendClass = backendParameters.get(BACKEND_CLASS);
|
||||
backendReadOnly = backendParameters.get(BACKEND_READ_ONLY);
|
||||
if (backendHost==null) {
|
||||
backendHost = "localhost";
|
||||
}
|
||||
if (backendHost.isEmpty()) {
|
||||
throw new IllegalArgumentException("Can't work with empty "+BACKEND_HOST+" attribute.");
|
||||
}
|
||||
}
|
||||
|
||||
public URL checkBackendUrl() {
|
||||
if (backendUrl==null) {
|
||||
throw new IllegalArgumentException("Can't work with null "+BACKEND_URL+" attribute for: "+jndiObjectName);
|
||||
}
|
||||
if (backendUrl.isEmpty()) {
|
||||
throw new IllegalArgumentException("Can't work with empty "+BACKEND_URL+" attribute for: "+jndiObjectName);
|
||||
}
|
||||
try {
|
||||
return new URL(backendUrl);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new IllegalArgumentException("Could not convert "+backendUrl+" to url.",e);
|
||||
}
|
||||
}
|
||||
|
||||
public File checkFile() {
|
||||
if (backendFile==null) {
|
||||
throw new IllegalArgumentException("Can't work with null "+BACKEND_FILE+" attribute for: "+jndiObjectName);
|
||||
}
|
||||
if (backendFile.isEmpty()) {
|
||||
throw new IllegalArgumentException("Can't work with empty "+BACKEND_FILE+" attribute for: "+jndiObjectName);
|
||||
}
|
||||
File file = new File(backendFile);
|
||||
if (file.exists()==false) {
|
||||
throw new IllegalStateException("File not found: "+file.getName()+" for: "+jndiObjectName);
|
||||
}
|
||||
if (file.canRead()==false) {
|
||||
throw new IllegalStateException("Can't read file: "+file+" for: "+jndiObjectName);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jndiObject
|
||||
*/
|
||||
public Object getJndiObject() {
|
||||
return jndiObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jndiNamePath
|
||||
*/
|
||||
public Name getJndiNamePath() {
|
||||
return jndiNamePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jndiContext
|
||||
*/
|
||||
public Context getJndiContext() {
|
||||
return jndiContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jndiEnv
|
||||
*/
|
||||
public Hashtable<?, ?> getJndiEnv() {
|
||||
return jndiEnv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jndiObjectName
|
||||
*/
|
||||
public String getJndiObjectName() {
|
||||
return jndiObjectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the backendType
|
||||
*/
|
||||
public String getBackendType() {
|
||||
return backendType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the backendFile
|
||||
*/
|
||||
public String getBackendFile() {
|
||||
return backendFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the backendUrl
|
||||
*/
|
||||
public String getBackendUrl() {
|
||||
return backendUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the backendHost
|
||||
*/
|
||||
public String getBackendHost() {
|
||||
return backendHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the backendPort
|
||||
*/
|
||||
public String getBackendPort() {
|
||||
return backendPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the backendDatabase
|
||||
*/
|
||||
public String getBackendDatabase() {
|
||||
return backendDatabase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the backendUsername
|
||||
*/
|
||||
public String getBackendUsername() {
|
||||
return backendUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the backendPassword
|
||||
*/
|
||||
public String getBackendPassword() {
|
||||
return backendPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the backendClass
|
||||
*/
|
||||
public String getBackendClass() {
|
||||
return backendClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the backendReadOnly
|
||||
*/
|
||||
public String getBackendReadOnly() {
|
||||
return backendReadOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the backendParameters
|
||||
*/
|
||||
public Map<String, String> getBackendParameters() {
|
||||
return backendParameters;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.jndi.loader;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.jdbc.JdbcDataContext;
|
||||
|
||||
/**
|
||||
* JndiCsvDataContextLoader Loads and config jdbc DataContext from jndi loader config.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 22, 2012
|
||||
*/
|
||||
public class JndiJdbcDataContextLoader implements JndiDataContextLoader {
|
||||
|
||||
private boolean useDataSource = true;
|
||||
|
||||
public JndiJdbcDataContextLoader() {
|
||||
}
|
||||
public JndiJdbcDataContextLoader(boolean useDataSource) {
|
||||
setUseDataSource(useDataSource);
|
||||
}
|
||||
|
||||
public DataContext loadDataContext(JndiDataContextLoaderConfig config) {
|
||||
if (useDataSource) {
|
||||
if (config.getBackendUrl()==null) {
|
||||
throw new IllegalArgumentException("Can't work with null "+JndiDataContextLoaderConfig.BACKEND_URL+" attribute for: "+config.getJndiObjectName());
|
||||
}
|
||||
if (config.getBackendUrl().isEmpty()) {
|
||||
throw new IllegalArgumentException("Can't work with empty "+JndiDataContextLoaderConfig.BACKEND_URL+" attribute for: "+config.getJndiObjectName());
|
||||
}
|
||||
|
||||
return new JdbcDataContext(getDataSource(config.getJndiObjectName(),config.getBackendUrl()));
|
||||
} else {
|
||||
config.checkBackendUrl();
|
||||
return new JdbcDataContext(getConnection(
|
||||
config.getJndiObjectName(),
|
||||
config.getBackendClass(),
|
||||
config.getBackendUrl(),
|
||||
config.getBackendUsername(),
|
||||
config.getBackendPassword()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
protected Connection getConnection(String objectName,String driverClass,String url,String user,String pass) {
|
||||
try {
|
||||
if (driverClass!=null && driverClass.isEmpty()==false) {
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
if (cl==null) {
|
||||
cl = this.getClass().getClassLoader();
|
||||
}
|
||||
cl.loadClass(driverClass);
|
||||
}
|
||||
Connection connection = DriverManager.getConnection(url,user,pass);
|
||||
return connection;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not get jdbc connection to: "+url+" for: "+objectName,e);
|
||||
}
|
||||
}
|
||||
|
||||
protected DataSource getDataSource(String objectName,String jndiName) {
|
||||
try {
|
||||
InitialContext context = new InitialContext();
|
||||
DataSource datasource = (DataSource)context.lookup(jndiName);
|
||||
return datasource;
|
||||
} catch (NamingException e) {
|
||||
throw new IllegalStateException("Jndi naming error on: "+jndiName+" for: "+objectName,e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the useDataSource
|
||||
*/
|
||||
public boolean isUseDataSource() {
|
||||
return useDataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param useDataSource the useDataSource to set
|
||||
*/
|
||||
public void setUseDataSource(boolean useDataSource) {
|
||||
this.useDataSource = useDataSource;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.jndi.loader;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.mongodb.MongoDbDataContext;
|
||||
import org.eobjects.metamodel.mongodb.MongoDbDataContextBean;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoOptions;
|
||||
import com.mongodb.ServerAddress;
|
||||
|
||||
/**
|
||||
* JndiCsvDataContextLoader Loads and config mongodb DataContext from jndi loader config.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 22, 2012
|
||||
*/
|
||||
public class JndiMongodbDataContextLoader implements JndiDataContextLoader {
|
||||
|
||||
private boolean useJndiResource = false;
|
||||
|
||||
public JndiMongodbDataContextLoader() {
|
||||
}
|
||||
public JndiMongodbDataContextLoader(boolean useJndiResource) {
|
||||
setUseJndiResource(useJndiResource);
|
||||
}
|
||||
|
||||
public DataContext loadDataContext(JndiDataContextLoaderConfig config) {
|
||||
MongoDbDataContextBean result = null;
|
||||
if (useJndiResource) {
|
||||
config.checkBackendUrl();
|
||||
result = new MongoDbDataContextBean(getMongodbJdni(config.getJndiObjectName(),config.getBackendUrl()));
|
||||
} else {
|
||||
int mongoPort = 27017;
|
||||
if (config.getBackendPort()!=null && config.getBackendPort().isEmpty()==false) {
|
||||
mongoPort = new Integer(config.getBackendPort());
|
||||
}
|
||||
result = new MongoDbDataContextBean(getMongodbConnection(
|
||||
config.getJndiObjectName(),
|
||||
config.getBackendHost(),
|
||||
mongoPort,
|
||||
config.getBackendDatabase(),
|
||||
config.getBackendUsername(),
|
||||
config.getBackendPassword()
|
||||
));
|
||||
}
|
||||
result.setRegisterMBean(true); // TODO: make flag
|
||||
result.start();
|
||||
return result;
|
||||
}
|
||||
|
||||
protected DB getMongodbJdni(String objectName,String jndiName) {
|
||||
try {
|
||||
InitialContext context = new InitialContext();
|
||||
DB db = (DB)context.lookup(jndiName);
|
||||
return db;
|
||||
} catch (NamingException e) {
|
||||
throw new IllegalStateException("Jndi naming error on: "+jndiName+" for: "+objectName,e);
|
||||
}
|
||||
}
|
||||
|
||||
protected DB getMongodbConnection(String objectName,String hostname,int port,String database,String username,String password) {
|
||||
if (database==null) {
|
||||
throw new IllegalArgumentException("Can't work with null "+JndiDataContextLoaderConfig.BACKEND_DB+" attribute for: "+objectName);
|
||||
}
|
||||
if (database.isEmpty()) {
|
||||
throw new IllegalArgumentException("Can't work with empty "+JndiDataContextLoaderConfig.BACKEND_DB+" attribute for: "+objectName);
|
||||
}
|
||||
ServerAddress server;
|
||||
try {
|
||||
server = new ServerAddress(hostname,port);
|
||||
} catch (UnknownHostException e) {
|
||||
throw new IllegalStateException("Could not create hostname from: "+hostname+" for: "+objectName,e);
|
||||
}
|
||||
MongoOptions options = new MongoOptions();
|
||||
Mongo mongo = new Mongo(server,options);
|
||||
DB db = mongo.getDB(database);
|
||||
if (username!=null && password!=null) {
|
||||
boolean auth = db.authenticate(username, password.toCharArray());
|
||||
if (auth==false) {
|
||||
throw new IllegalStateException("Could not auth to db: "+database+" with username: "+username+" for: "+objectName);
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the useJndiResource
|
||||
*/
|
||||
public boolean isUseJndiResource() {
|
||||
return useJndiResource;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param useJndiResource the useJndiResource to set
|
||||
*/
|
||||
public void setUseJndiResource(boolean useJndiResource) {
|
||||
this.useJndiResource = useJndiResource;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.jndi.loader;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.xml.XmlDomDataContext;
|
||||
|
||||
/**
|
||||
* JndiCsvDataContextLoader Loads and config xml dom DataContext from jndi loader config.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 22, 2012
|
||||
*/
|
||||
public class JndiXmlDomDataContextLoader implements JndiDataContextLoader {
|
||||
|
||||
private boolean useUrlSource = false;
|
||||
|
||||
public JndiXmlDomDataContextLoader() {
|
||||
}
|
||||
public JndiXmlDomDataContextLoader(boolean useUrlSource) {
|
||||
setUseUrlSource(useUrlSource);
|
||||
}
|
||||
|
||||
public DataContext loadDataContext(JndiDataContextLoaderConfig config) {
|
||||
boolean autoFlattenTables = true;
|
||||
if ("false".equalsIgnoreCase(config.getBackendParameters().get("autoFlattenTables"))) {
|
||||
autoFlattenTables = false;
|
||||
}
|
||||
if (useUrlSource) {
|
||||
return new XmlDomDataContext(config.checkBackendUrl(),autoFlattenTables);
|
||||
} else {
|
||||
return new XmlDomDataContext(config.checkFile(),autoFlattenTables);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the useUrlSource
|
||||
*/
|
||||
public boolean isUseUrlSource() {
|
||||
return useUrlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param useUrlSource the useUrlSource to set
|
||||
*/
|
||||
public void setUseUrlSource(boolean useUrlSource) {
|
||||
this.useUrlSource = useUrlSource;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.jndi.loader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.util.Ref;
|
||||
import org.eobjects.metamodel.xml.XmlSaxDataContext;
|
||||
import org.eobjects.metamodel.xml.XmlSaxTableDef;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
/**
|
||||
* JndiXmlSaxDataContextLoader Loads and config xml sax DataContext from jndi loader config.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 May 22, 2012
|
||||
*/
|
||||
public class JndiXmlSaxDataContextLoader implements JndiDataContextLoader {
|
||||
|
||||
private boolean useUrlSource = false;
|
||||
|
||||
public JndiXmlSaxDataContextLoader() {
|
||||
}
|
||||
public JndiXmlSaxDataContextLoader(boolean useUrlSource) {
|
||||
setUseUrlSource(useUrlSource);
|
||||
}
|
||||
|
||||
public DataContext loadDataContext(JndiDataContextLoaderConfig config) {
|
||||
List<XmlSaxTableDef> tableSchemas = createXmlSaxConfig(config.getJndiObjectName(),config.getBackendParameters());
|
||||
XmlSaxTableDef[] args = new XmlSaxTableDef[tableSchemas.size()];
|
||||
if (useUrlSource) {
|
||||
final URL url = config.checkBackendUrl();
|
||||
return new XmlSaxDataContext(new Ref<InputSource>() { // TODO: missing constructor in XmlSaxDataContext
|
||||
public InputSource get() {
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = url.openStream();
|
||||
return new InputSource(in);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Could not read url; "+url,e);
|
||||
} finally {
|
||||
if (in!=null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},tableSchemas.toArray(args));
|
||||
} else {
|
||||
return new XmlSaxDataContext(config.checkFile(),tableSchemas.toArray(args)); // copy List to array
|
||||
}
|
||||
}
|
||||
|
||||
protected List<XmlSaxTableDef> createXmlSaxConfig(String objectName,Map<String,String> param) {
|
||||
String rowXPath = param.get("rowXPath");
|
||||
String dataXPaths = param.get("dataXPaths");
|
||||
if (rowXPath==null) {
|
||||
throw new IllegalArgumentException("Can't work with null rowXPath attribute for: "+objectName);
|
||||
}
|
||||
if (rowXPath.isEmpty()) {
|
||||
throw new IllegalArgumentException("Can't work with empty rowXPath attribute for: "+objectName);
|
||||
}
|
||||
if (dataXPaths==null) {
|
||||
throw new IllegalArgumentException("Can't work with null dataXPaths attribute for: "+objectName);
|
||||
}
|
||||
if (dataXPaths.isEmpty()) {
|
||||
throw new IllegalArgumentException("Can't work with empty dataXPaths attribute for: "+objectName);
|
||||
}
|
||||
String[] args = dataXPaths.split(",");
|
||||
|
||||
List<XmlSaxTableDef> tableSchemas = new ArrayList<XmlSaxTableDef>(5);
|
||||
XmlSaxTableDef tableSchema = new XmlSaxTableDef(rowXPath,args);
|
||||
tableSchemas.add(tableSchema);
|
||||
return tableSchemas;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the useUrlSource
|
||||
*/
|
||||
public boolean isUseUrlSource() {
|
||||
return useUrlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param useUrlSource the useUrlSource to set
|
||||
*/
|
||||
public void setUseUrlSource(boolean useUrlSource) {
|
||||
this.useUrlSource = useUrlSource;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.x4o;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.forwardfire.vasc.backend.metamodel.MetaModelDataContextXmlSax;
|
||||
|
||||
import org.eobjects.metamodel.xml.XmlSaxTableDef;
|
||||
import org.x4o.xml.element.AbstractElement;
|
||||
import org.x4o.xml.element.Element;
|
||||
import org.x4o.xml.element.ElementException;
|
||||
|
||||
public class XmlSaxSchemaElement extends AbstractElement {
|
||||
|
||||
/**
|
||||
* @see org.x4o.xml.element.AbstractElement#doElementRun()
|
||||
*/
|
||||
@Override
|
||||
public void doElementRun() throws ElementException {
|
||||
if (getElementClass().getTag().endsWith("Column")) {
|
||||
return; // save one object to code.
|
||||
}
|
||||
if (getParent()==null) {
|
||||
throw new ElementException("Parent element is null.");
|
||||
}
|
||||
if (getParent().getElementObject()==null) {
|
||||
throw new ElementException("Parent object is null.");
|
||||
}
|
||||
if ((getParent().getElementObject() instanceof MetaModelDataContextXmlSax)==false) {
|
||||
throw new ElementException("Parent object is not MetaModelDataContextXmlSax class.");
|
||||
}
|
||||
String rowXPath = getAttributes().get("rowXPath");
|
||||
if (rowXPath==null) {
|
||||
throw new ElementException("Attribute rowXPath is null.");
|
||||
}
|
||||
if (rowXPath.isEmpty()) {
|
||||
throw new ElementException("Attribute rowXPath is empty.");
|
||||
}
|
||||
List<String> columns = new ArrayList<String>(15);
|
||||
for (Element e:getChilderen()) {
|
||||
String col = e.getAttributes().get("dataXPath");
|
||||
if (col==null) {
|
||||
throw new ElementException("Attribute dataXPath is null.");
|
||||
}
|
||||
if (col.isEmpty()) {
|
||||
throw new ElementException("Attribute dataXPath is empty.");
|
||||
}
|
||||
columns.add(col);
|
||||
}
|
||||
MetaModelDataContextXmlSax saxDataContext = (MetaModelDataContextXmlSax)getParent().getElementObject();
|
||||
String[] args = new String[columns.size()];
|
||||
XmlSaxTableDef tableSchema = new XmlSaxTableDef(rowXPath,columns.toArray(args));
|
||||
saxDataContext.addTableSchema(tableSchema);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<eld:root xmlns:eld="http://eld.x4o.org/eld/eld-lang.eld">
|
||||
|
||||
<eld:elementClass tag="metaModelBackend" objectClassName="net.forwardfire.vasc.backend.metamodel.MetaModelVascBackend"/>
|
||||
<eld:elementClass tag="mongodbDataContext" objectClassName="net.forwardfire.vasc.backend.metamodel.MetaModelDataContextMongodb"/>
|
||||
<eld:elementClass tag="jdbcDataContext" objectClassName="net.forwardfire.vasc.backend.metamodel.MetaModelDataContextJdbc"/>
|
||||
<eld:elementClass tag="csvDataContext" objectClassName="net.forwardfire.vasc.backend.metamodel.MetaModelDataContextCsv"/>
|
||||
<eld:elementClass tag="schemaAutoEntry" objectClassName="net.forwardfire.vasc.backend.metamodel.MetaModelSchemaAutoEntry">
|
||||
<eld:elementClass tag="metaModelBackend" objectClassName="net.forwardfire.vasc.backend.metamodel.MetaModelVascBackend"/>
|
||||
<eld:elementClass tag="mongodbDataContext" objectClassName="net.forwardfire.vasc.backend.metamodel.MetaModelDataContextMongodb"/>
|
||||
<eld:elementClass tag="jdbcDataContext" objectClassName="net.forwardfire.vasc.backend.metamodel.MetaModelDataContextJdbc"/>
|
||||
<eld:elementClass tag="jndiDataSourceDataContext" objectClassName="net.forwardfire.vasc.backend.metamodel.MetaModelDataContextJndiDataSource"/>
|
||||
<eld:elementClass tag="csvDataContext" objectClassName="net.forwardfire.vasc.backend.metamodel.MetaModelDataContextCsv"/>
|
||||
|
||||
<eld:elementClass tag="xmlSaxDataContext" objectClassName="net.forwardfire.vasc.backend.metamodel.MetaModelDataContextXmlSax"/>
|
||||
<eld:elementClass tag="xmlSaxSchema" elementClassName="net.forwardfire.vasc.backend.metamodel.x4o.XmlSaxSchemaElement"/>
|
||||
<eld:elementClass tag="xmlSaxSchemaColumn" elementClassName="net.forwardfire.vasc.backend.metamodel.x4o.XmlSaxSchemaElement"/>
|
||||
|
||||
<eld:elementClass tag="xmlDomDataContext" objectClassName="net.forwardfire.vasc.backend.metamodel.MetaModelDataContextXmlDom"/>
|
||||
|
||||
<eld:elementClass tag="jndiDataContext" objectClassName="net.forwardfire.vasc.backend.metamodel.MetaModelDataContextJndiDataContext"/>
|
||||
|
||||
<eld:elementClass tag="schemaAutoEntry" objectClassName="net.forwardfire.vasc.backend.metamodel.MetaModelSchemaAutoEntry">
|
||||
<eld:elementConfigurator bean.class="net.forwardfire.vasc.backend.metamodel.x4o.SchemaAutoEntryElementConfigurator" configAction="true"/>
|
||||
</eld:elementClass>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Statement;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.eobjects.metamodel.data.DataSet;
|
||||
import org.eobjects.metamodel.jdbc.JdbcDataContext;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
|
||||
|
||||
public class BravoTest extends TestCase {
|
||||
|
||||
private Connection conn;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
Class.forName("org.postgresql.Driver");
|
||||
conn = DriverManager.getConnection("jdbc:postgresql://localhost/openbravo","postgres","postgresql");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
conn.close();
|
||||
}
|
||||
|
||||
public void testDataTypeBoolean() throws Exception {
|
||||
|
||||
/*
|
||||
Statement s = conn.createStatement();
|
||||
s.executeUpdate("DROP TABLE test_type_bool IF EXISTS;");
|
||||
s.executeUpdate("CREATE TABLE test_type_bool (id IDENTITY not null primary key,name varchar not null,active boolean not null);");
|
||||
s.executeUpdate("INSERT INTO test_type_bool VALUES(1,\'name\',true);");
|
||||
|
||||
// Test working data first
|
||||
JdbcDataContext dc = new JdbcDataContext(conn);
|
||||
Table table = dc.getDefaultSchema().getTableByName("TEST_TYPE_BOOL");
|
||||
assertNotNull(table);
|
||||
DataSet ds = dc.query().from(table).select(table.getColumns()).execute();
|
||||
assertTrue(ds.next());
|
||||
ds = dc.query().from(table).selectCount().execute();
|
||||
assertTrue(ds.next());
|
||||
|
||||
// Now let it fail
|
||||
s.executeUpdate("DROP TABLE test_type_bool IF EXISTS;");
|
||||
s.executeUpdate("CREATE TABLE test_type_bool (id IDENTITY not null primary key,name varchar not null,active boolean not null);");
|
||||
s.executeUpdate("INSERT INTO test_type_bool VALUES(1,\'\',true);");
|
||||
|
||||
// Make sure it works from jdbc driver
|
||||
Boolean active = null;
|
||||
s.execute("SELECT * FROM TEST_TYPE_BOOL");
|
||||
ResultSet rs = s.getResultSet();
|
||||
while (rs.next()) {
|
||||
active = rs.getBoolean(3); // this should be same method as exception
|
||||
}
|
||||
assertTrue(active);
|
||||
*/
|
||||
// Fails on execute.
|
||||
long startTime = System.currentTimeMillis();
|
||||
JdbcDataContext dc = new JdbcDataContext(conn);
|
||||
long stopTime = System.currentTimeMillis();
|
||||
System.out.println("DC init took: "+(stopTime-startTime)+" ms. for total tables: "+dc.getDefaultSchema().getTableCount());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Statement;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.eobjects.metamodel.data.DataSet;
|
||||
import org.eobjects.metamodel.jdbc.JdbcDataContext;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
|
||||
|
||||
public class H2Test extends TestCase {
|
||||
|
||||
private Connection conn;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
Class.forName("org.h2.Driver");
|
||||
conn = DriverManager.getConnection("jdbc:h2:mem:");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
conn.close();
|
||||
}
|
||||
|
||||
public void testDataTypeBoolean() throws Exception {
|
||||
|
||||
// This works see diff is empty value in column before boolean column ...
|
||||
Statement s = conn.createStatement();
|
||||
s.executeUpdate("DROP TABLE test_type_bool IF EXISTS;");
|
||||
s.executeUpdate("CREATE TABLE test_type_bool (id IDENTITY not null primary key,name varchar not null,active boolean not null);");
|
||||
s.executeUpdate("INSERT INTO test_type_bool VALUES(1,\'name\',true);");
|
||||
|
||||
// Test working data first
|
||||
JdbcDataContext dc = new JdbcDataContext(conn);
|
||||
Table table = dc.getDefaultSchema().getTableByName("TEST_TYPE_BOOL");
|
||||
assertNotNull(table);
|
||||
DataSet ds = dc.query().from(table).select(table.getColumns()).execute();
|
||||
assertTrue(ds.next());
|
||||
ds = dc.query().from(table).selectCount().execute();
|
||||
assertTrue(ds.next());
|
||||
|
||||
// Now let it fail
|
||||
s.executeUpdate("DROP TABLE test_type_bool IF EXISTS;");
|
||||
s.executeUpdate("CREATE TABLE test_type_bool (id IDENTITY not null primary key,name varchar not null,active boolean not null);");
|
||||
s.executeUpdate("INSERT INTO test_type_bool VALUES(1,\'\',true);");
|
||||
|
||||
// Make sure it works from jdbc driver
|
||||
Boolean active = null;
|
||||
s.execute("SELECT * FROM TEST_TYPE_BOOL");
|
||||
ResultSet rs = s.getResultSet();
|
||||
while (rs.next()) {
|
||||
active = rs.getBoolean(3); // this should be same method as exception
|
||||
}
|
||||
assertTrue(active);
|
||||
|
||||
// Fails on execute.
|
||||
dc = new JdbcDataContext(conn);
|
||||
table = dc.getDefaultSchema().getTableByName("TEST_TYPE_BOOL");
|
||||
assertNotNull(table);
|
||||
ds = dc.query().from(table).select(table.getColumns()).execute();
|
||||
assertTrue(ds.next());
|
||||
ds = dc.query().from(table).selectCount().execute();
|
||||
assertTrue(ds.next());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
|
||||
import java.io.File;
|
||||
|
||||
import org.eobjects.metamodel.UpdateCallback;
|
||||
import org.eobjects.metamodel.UpdateScript;
|
||||
import org.eobjects.metamodel.csv.CsvDataContext;
|
||||
import org.eobjects.metamodel.data.DataSet;
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.schema.Schema;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
import org.eobjects.metamodel.util.MutableRef;
|
||||
|
||||
public class SwingLoadTest {
|
||||
private Table table = null;
|
||||
public static void main(String[] argu) {
|
||||
try {SwingLoadTest test = new SwingLoadTest();test.run(argu);} catch (Exception e) {e.printStackTrace();}
|
||||
}
|
||||
public void run(String[] argu) throws Exception {
|
||||
File tmpFile = File.createTempFile("test-class-loading", "csv");
|
||||
tmpFile.deleteOnExit();
|
||||
CsvDataContext dataContext = new CsvDataContext(tmpFile);
|
||||
final Schema schema = dataContext.getDefaultSchema();
|
||||
dataContext.executeUpdate(new UpdateScript() {
|
||||
public void run(UpdateCallback cb) {
|
||||
MutableRef<Table> tableRef = new MutableRef<Table>();
|
||||
table = cb.createTable(schema, "table").withColumn("column").execute();
|
||||
tableRef.set(table);
|
||||
cb.insertInto(table).value(0,"data").execute();
|
||||
}
|
||||
});
|
||||
DataSet ds = dataContext.query().from(table).select(table.getColumns()).execute();
|
||||
while (ds.next()) {
|
||||
Row row = ds.getRow();
|
||||
System.out.println("Row value contains "+row.getValue(0));
|
||||
}
|
||||
ds.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.bundle;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.UpdateableDataContext;
|
||||
import org.eobjects.metamodel.csv.CsvDataContext;
|
||||
import org.eobjects.metamodel.data.DataSet;
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class ResouceBundleTest extends TestCase {
|
||||
|
||||
public void testBundle() {
|
||||
final String tableName = "mm-bundle-test"; // Setup some small test data in tmp
|
||||
File testFile = new File(System.getProperty("java.io.tmpdir")+File.separatorChar+tableName+".properties");
|
||||
final boolean createTable = testFile.exists()==false;
|
||||
DataContext dataContext = new ResourceBundleDataContext(testFile);
|
||||
assertTrue(dataContext instanceof UpdateableDataContext);
|
||||
|
||||
for (String t:dataContext.getDefaultSchema().getTableNames()) {
|
||||
System.out.println("table: '"+t+"'");
|
||||
}
|
||||
|
||||
Table table = dataContext.getDefaultSchema().getTableByName("en");
|
||||
assertNotNull(table);
|
||||
|
||||
DataSet ds = dataContext.query().from(table).select(table.getColumns()).execute();
|
||||
while (ds.next()) {
|
||||
Row row = ds.getRow();
|
||||
System.out.println("row: "+row.getValue(0)+" "+row.getValue(1)+" "+row.getValue(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
package net.forwardfire.vasc.backend.metamodel.crud;
|
||||
|
||||
import java.io.File;
|
||||
import org.eobjects.metamodel.DataContext;
|
||||
import org.eobjects.metamodel.UpdateCallback;
|
||||
import org.eobjects.metamodel.UpdateScript;
|
||||
import org.eobjects.metamodel.UpdateableDataContext;
|
||||
import org.eobjects.metamodel.csv.CsvDataContext;
|
||||
import org.eobjects.metamodel.data.DataSet;
|
||||
import org.eobjects.metamodel.data.Row;
|
||||
import org.eobjects.metamodel.schema.Schema;
|
||||
import org.eobjects.metamodel.schema.Table;
|
||||
import org.eobjects.metamodel.util.MutableRef;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class CrudContextTest extends TestCase {
|
||||
|
||||
public void testCrud() {
|
||||
final String tableName = "test-crud"; // Setup some small test data in tmp
|
||||
File testFile = new File(System.getProperty("java.io.tmpdir")+File.separatorChar+tableName+".csv");
|
||||
final boolean createTable = testFile.exists()==false;
|
||||
CsvDataContext dataContext = new CsvDataContext(testFile);
|
||||
assertTrue(dataContext instanceof UpdateableDataContext);
|
||||
final Schema schema = dataContext.getDefaultSchema();
|
||||
final MutableRef<Table> tableRef = new MutableRef<Table>();
|
||||
dataContext.executeUpdate(new UpdateScript() {
|
||||
public void run(UpdateCallback cb) {
|
||||
Table table = null;
|
||||
int idx = 0;
|
||||
if (createTable) {
|
||||
table = cb.createTable(schema, tableName).withColumn("id").withColumn("name").withColumn("active").execute();
|
||||
tableRef.set(table);
|
||||
} else {
|
||||
table = cb.getDataContext().getDefaultSchema().getTableByName(tableName);
|
||||
idx = generateNextId(cb.getDataContext(),table);
|
||||
}
|
||||
cb.insertInto(table).value(0,idx+1).value(1, "foo").value(2, true).execute();
|
||||
cb.insertInto(table).value(0,idx+2).value(1, "foo").value(2, false).execute();
|
||||
cb.insertInto(table).value(0,idx+3).value(1, "bar").value(2, false).execute();
|
||||
cb.insertInto(table).value(0,idx+4).value(1, "bar").value(2, true).execute();
|
||||
cb.insertInto(table).value(0,idx+5).value(1, "object").value(2, true).execute();
|
||||
}
|
||||
});
|
||||
|
||||
// Wrap to CrudDataContext and get table to test with.
|
||||
CrudDataContext crudDataContext = new CrudDataContextImpl((UpdateableDataContext)dataContext);
|
||||
Table table = crudDataContext.getDefaultSchema().getTableByName(tableName);
|
||||
assertNotNull(table);
|
||||
|
||||
// Fetch and update data
|
||||
DataSet ds = crudDataContext.query().from(table).select(table.getColumns()).execute();
|
||||
while (ds.next()) {
|
||||
Row row = ds.getRow();
|
||||
if (row instanceof UpdateableRow) {
|
||||
UpdateableRow rowCrud = (UpdateableRow)row;
|
||||
if (rowCrud.getValue("name")!=null && rowCrud.getValue("name").toString().startsWith("test")==false) {
|
||||
rowCrud.setValue("active", false);
|
||||
crudDataContext.merge(rowCrud);
|
||||
}
|
||||
}
|
||||
}
|
||||
ds.close();
|
||||
|
||||
// Lets add an record.
|
||||
UpdateableRow newRow = crudDataContext.createRow(table);
|
||||
newRow.setValue("id", generateNextId(crudDataContext,table)); // Leave key out on jdbc/mongo backends for sequence/auto id.
|
||||
newRow.setValue("name", "test date "+System.currentTimeMillis());
|
||||
newRow.setValue("active", true);
|
||||
crudDataContext.persist(newRow);
|
||||
|
||||
// Delete some data.
|
||||
DataSet dsDel = crudDataContext.query().from(table).select(table.getColumns()).where("name").equals("foo").or("name").equals("bar").execute();
|
||||
while (dsDel.next()) {
|
||||
crudDataContext.delete((UpdateableRow)dsDel.getRow());
|
||||
}
|
||||
dsDel.close();
|
||||
//testFile.deleteOnExit();
|
||||
}
|
||||
|
||||
private int generateNextId(DataContext dataContext,Table table) {
|
||||
//DataSet dsMax = dataContext.query().from(table).select(FunctionType.MAX, table.getColumn(0)).execute();
|
||||
//assertTrue(dsMax.next());
|
||||
//Row rowMax = dsMax.getRow();
|
||||
//int recordId = new Integer(rowMax.getValue(0).toString()); // MAX stops on first row ?
|
||||
//dsMax.close();
|
||||
int recordId = 0;
|
||||
DataSet ds = dataContext.query().from(table).select(table.getColumns()).execute();
|
||||
while (ds.next()) {
|
||||
Row row = ds.getRow();
|
||||
int id = new Integer(row.getValue(0).toString());
|
||||
if (id > recordId) {
|
||||
recordId = id;
|
||||
}
|
||||
}
|
||||
return recordId + 1; // Fetch new ID because CSV has no auto ID
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
<version>2.7.2</version>
|
||||
<version>${mongo-java-driver.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
Loading…
Add table
Add a link
Reference in a new issue