Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a SqlComponentFactory interface to let user provide a custom fa… #30

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
64 changes: 15 additions & 49 deletions src/main/java/com/simsilica/es/sql/ComponentTable.java
Expand Up @@ -34,8 +34,6 @@

package com.simsilica.es.sql;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.sql.*;
import java.util.*;

Expand All @@ -60,20 +58,18 @@ public class ComponentTable<T extends EntityComponent> {

static Logger log = LoggerFactory.getLogger(ComponentTable.class);

private boolean cached = true;
private Class<T> type;
private Constructor<T> ctor;
private FieldType[] fields;
private String tableName;
private final boolean cached = true;
private final SqlComponentFactory<T> componentFactory;
private final FieldType[] fields;
private final String tableName;
private String[] dbFieldNames;

private String insertSql;
private String updateSql;
private final String insertSql;
private final String updateSql;

protected ComponentTable( Constructor<T> ctor, Class<T> type, FieldType[] fields ) {
this.type = type;
this.ctor = ctor;
this.fields = fields;
protected ComponentTable( Class<T> type, SqlComponentFactory<T> factory ) {
this.componentFactory = factory;
this.fields = factory.getFieldTypes();
this.tableName = type.getSimpleName().toUpperCase();

List<String> names = new ArrayList<String>();
Expand All @@ -89,23 +85,7 @@ protected ComponentTable( Constructor<T> ctor, Class<T> type, FieldType[] fields

public static <T extends EntityComponent> ComponentTable<T> create( SqlSession session,
Class<T> type ) throws SQLException {
List<FieldType> types = FieldTypes.getFieldTypes(type);
FieldType[] array = new FieldType[types.size()];
array = types.toArray(array);

// Look up a no-arg constructor so that we can make sure it
// is accessible similar to fields
Constructor<T> ctor;
try {
ctor = type.getDeclaredConstructor();

// Make sure it is accessible
ctor.setAccessible(true);
} catch( NoSuchMethodException e ) {
throw new IllegalArgumentException("Type does not have a no-arg constructor:" + type, e);
}

ComponentTable<T> result = new ComponentTable<>(ctor, type, array);
ComponentTable<T> result = new ComponentTable<>(type, new DefaultComponentFactory<>(type));
result.initialize(session);

return result;
Expand Down Expand Up @@ -337,17 +317,9 @@ public T getComponent( SqlSession session, EntityId entityId ) throws SQLExcepti
ResultSet rs = st.executeQuery();
try {
if( rs.next() ) {
int index = 1;
T target = ctor.newInstance();
for( FieldType t : fields ) {
index = t.load(target, rs, index);
}

return target;
return componentFactory.createComponent(rs);
}
return null;
} catch( InvocationTargetException | InstantiationException | IllegalAccessException e ) {
throw new RuntimeException("Error in table mapping", e);
} finally {
rs.close();
}
Expand Down Expand Up @@ -558,18 +530,12 @@ public Iterator<Map.Entry<EntityId,T>> components( SqlSession session ) throws S
ResultSet rs = st.executeQuery();
try {
while( rs.next() ) {
int index = 1;
T target = ctor.newInstance();
for( FieldType t : fields ) {
index = t.load(target, rs, index);
}

Long entityId = rs.getLong(index);
T target = componentFactory.createComponent(rs);

Long entityId = rs.getLong("entityId");

results.add(new ComponentReference<T>(new EntityId(entityId), target));
results.add(new ComponentReference<T>(new EntityId(entityId), target));
}
} catch( InvocationTargetException | InstantiationException | IllegalAccessException e ) {
throw new RuntimeException("Error in table mapping", e);
} finally {
rs.close();
}
Expand Down
86 changes: 86 additions & 0 deletions src/main/java/com/simsilica/es/sql/DefaultComponentFactory.java
@@ -0,0 +1,86 @@
/*
* $Id$
*
* Copyright (c) 2011-2023 jMonkeyEngine
* 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.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* 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 OWNER 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 com.simsilica.es.sql;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
* @author Ali-RS
*/
public class DefaultComponentFactory<T> implements SqlComponentFactory<T> {

private final FieldType[] fields;
private final Constructor<T> ctor;

public DefaultComponentFactory(Class<T> type) {
List<FieldType> types = FieldTypes.getFieldTypes(type);
this.fields = types.toArray(new FieldType[types.size()]);

// Look up a no-arg constructor so that we can make sure it
// is accessible similar to fields
try {
ctor = type.getDeclaredConstructor();

// Make sure it is accessible
ctor.setAccessible(true);
} catch( NoSuchMethodException e ) {
throw new IllegalArgumentException("Type does not have a no-arg constructor:" + type, e);
}
}

@Override
public FieldType[] getFieldTypes() {
return fields;
}

@Override
public T createComponent(ResultSet rs) throws SQLException {
try {
int index = 1;
T target = ctor.newInstance();
for (FieldType t : fields) {
index = t.load(target, rs, index);
}

return target;
} catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
throw new RuntimeException("Error in table mapping", e);
}
}
}
2 changes: 2 additions & 0 deletions src/main/java/com/simsilica/es/sql/FieldType.java
Expand Up @@ -58,4 +58,6 @@ public interface FieldType {
public int store( Object object, PreparedStatement ps, int index ) throws SQLException;

public int load( Object target, ResultSet rs, int index ) throws SQLException;

public int readIntoArray( Object[] store, int storeIndex, ResultSet rs, int columnIndex ) throws SQLException;
}
50 changes: 48 additions & 2 deletions src/main/java/com/simsilica/es/sql/FieldTypes.java
Expand Up @@ -196,7 +196,19 @@ public int load( Object target, ResultSet rs, int index ) throws SQLException {
throw new RuntimeException("Error in field mapping", e);
}
}


@Override
public int readIntoArray(Object[] store, int storeIndex, ResultSet rs, int columnIndex) throws SQLException {
Number value = (Number)rs.getObject(columnIndex++);

if( value != null ) {
store[storeIndex] = new EntityId(value.longValue());
} else {
store[storeIndex] = null;
}
return columnIndex;
}

@Override
public String toString() {
if( dbFieldName != name ) {
Expand Down Expand Up @@ -282,6 +294,12 @@ public int load( Object target, ResultSet rs, int index ) throws SQLException {
}
}

@Override
public int readIntoArray(Object[] store, int storeIndex, ResultSet rs, int columnIndex) throws SQLException {
store[storeIndex] = rs.getObject(columnIndex++);
return columnIndex;
}

@Override
public String toString() {
if( dbFieldName != name ) {
Expand Down Expand Up @@ -375,6 +393,22 @@ public int load( Object target, ResultSet rs, int index ) throws SQLException {
}
}

@Override
public int readIntoArray(Object[] store, int storeIndex, ResultSet rs, int columnIndex) throws SQLException {
try {
Object subValue = field.getType().newInstance();

for( FieldType t : fields ) {
columnIndex = t.load(subValue, rs, columnIndex);
}

store[storeIndex] = subValue;
return columnIndex;
} catch(InstantiationException | IllegalAccessException e ) {
throw new RuntimeException("Error in field mapping", e);
}
}

@Override
public String toString() {
return getFieldName() + ":" + getType() + "{" + Arrays.asList(fields) + "}";
Expand Down Expand Up @@ -473,7 +507,19 @@ public int load( Object target, ResultSet rs, int index ) throws SQLException {
throw new RuntimeException("Error in field mapping", e);
}
}


@Override
public int readIntoArray(Object[] store, int storeIndex, ResultSet rs, int columnIndex) throws SQLException {
Object value = rs.getObject(columnIndex++);

if( value instanceof Number ) {
value = cast((Number)value, getType());
}

store[storeIndex] = value;
return columnIndex;
}

@Override
public String toString() {
if( dbFieldName != name ) {
Expand Down
48 changes: 48 additions & 0 deletions src/main/java/com/simsilica/es/sql/SqlComponentFactory.java
@@ -0,0 +1,48 @@
/*
* $Id$
*
* Copyright (c) 2011-2023 jMonkeyEngine
* 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.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* 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 OWNER 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 com.simsilica.es.sql;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
* @author Ali-RS
*/
public interface SqlComponentFactory<T> {

public FieldType[] getFieldTypes();

public T createComponent(ResultSet rs) throws SQLException;
}
11 changes: 11 additions & 0 deletions src/main/java/com/simsilica/es/sql/SqlComponentHandler.java
Expand Up @@ -63,6 +63,17 @@ public SqlComponentHandler( SqlEntityData parent, Class<T> type ) {
throw new RuntimeException("Error creating table for component type:" + type, e);
}
}

public SqlComponentHandler( SqlEntityData parent, Class<T> type, SqlComponentFactory<T> factory ) {
this.parent = parent;
this.type = type;
try {
this.table = new ComponentTable<>(type, factory);
table.initialize(parent.getSession());
} catch( SQLException e ) {
throw new RuntimeException("Error creating table for component type:" + type, e);
}
}

protected SqlSession getSession() throws SQLException {
return parent.getSession();
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/com/simsilica/es/sql/SqlEntityData.java
Expand Up @@ -95,6 +95,12 @@ public <T extends EntityComponent> void markPersistentType( Class<T> type ) {
}
persistentTypes.add(type);
}

public <T extends EntityComponent> void markPersistentType( Class<T> type, SqlComponentFactory<T> factory ) {
markPersistentType(type);

super.registerComponentHandler(type, new SqlComponentHandler<>(this, type, factory));
}

protected void execute( String statement ) throws SQLException {
SqlSession session = getSession();
Expand Down Expand Up @@ -129,10 +135,14 @@ protected SqlSession getSession() throws SQLException {
@Override
protected <T extends EntityComponent> ComponentHandler<T> lookupDefaultHandler( Class<T> type ) {
if( PersistentComponent.class.isAssignableFrom(type) || persistentTypes.contains(type) ) {
return new SqlComponentHandler<T>(this, type);
return new SqlComponentHandler<T>(this, type, lookupDefaultFactory(type));
}
return super.lookupDefaultHandler(type);
}

protected <T extends EntityComponent> SqlComponentFactory<T> lookupDefaultFactory( Class<T> type ) {
return new DefaultComponentFactory<>(type);
}

@Override
public void close() {
Expand Down