I have some Android projects and most of them are connected with SQLite databases. I'm interested is it a good programming practice (or a bad habbit) to use some static class like "DatabaseHelper.class" in which I would have all static method related for database manipulation. For example
public static int getId(Context context, String name) {
dbInit(context);
Cursor result = db.rawQuery("SELECT some_id FROM table WHERE some_name = '" + name + "'", null);
result.moveToFirst();
int id = result.getInt(result.getColumnIndex("some_id"));
result.close();
return id;
}
where dbInit(context) (which is used in all my static methods for database manipluation) is
private static void dbInit(Context context) {
if (db == null) {
db = context.openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE, null);
}
}
Then when I need something I can easily call those method(s) with for example
int id = DatabaseHelper.getId(this, "Abc");
EDIT: Do I have to use dbClose on every connection or leave it open per-activity and close per-activity? So do I have change that upper code to something like this?
...
dbClose();
return id;
}
private static void dbClose() {
if (db != null) {
db.close();
}
}
I would suggest you get into the habit of getting a database connection every time you need one, and releasing it back when you are done with it. The usual name for such a facility is a "database connection pool".
This moves the connection logic out of your actual code and into the pool, and allow you to do many things later when you need them. One simple thing, could be that the pool logs how long time a connection object was used, so you can get information about the usage of the database.
Your initial pool can be very simple if you only need a single connection.
I would definitely have your database related code in a separate class, but would really recommend against using a static class or Singleton. It might look good at first because of the convenience, but unfortunately it tightly couples your classes, hides their dependencies, and also makes unit testing harder.
The drawbacks section in wikipedia gives you a small overview of why you might want to explore other techniques. You can also head over here or over there where they give concrete examples of a class that uses a database access singleton, and how using dependency injection instead can solve some of the issues I mentioned.
As a first step, I would recommend using a normal class that you instantiate in your constructor, for ex:
public class MyActivity extends Activity {
private DBAccess dbAccess;
public MyActivity() {
dbAccess = new DBAccess(this);
}
}
As a second step, you might want to investigate frameworks like RoboGuice to break the hard dependency. You code would look something like:
public class MyActivity extends Activity {
#Inject private DBAccess dbAccess;
public MyActivity() {
}
}
Let us know if you want more details!
If you're going to use a singleton the very minimum requirement is that you make it stateless/threadsafe. If you use your getId method as it stands concurrent invocations could potentially cause all manner of strange bugs...
dbInit(context);
May be called for Thread A which then stops processing before hitting the query statement. Subsequently Thread B executes getId and also calls dbInit passing in a different context all together. Thread A would then resume and attempt to execute the query on B's context.
Maybe this isn't a problem in your application but I'd recommend sticking a synchronized modifier on that getId method!
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I implemented a class Database Manager that manages operations on two database engines. The class has a private variable databaseEngine which is set before using class methods (drop database, create database, run script, compare, disconnect, etc.) and based on this variable the class recognizes how to behave.
However, and I know it's wrong, Database Manager's methods are full of switch cases like this one:
public void CreateNewDatabase(String databaseName){
switch (databaseEngine){
case "mysql":
//Executes a prepared statement for dropping mysql database (databaseName
break;
case "postgres":
//Executes a prepared statement for dropping postgres database (databaseName
break;
...
}
}
I require a good advice about this. I want to load everything from configuration and resources folders, I mean, the prepared statement for creating and dropping, etc. If a new database engine needs to be supported, it won't be a headache as It would just require to save sql sripts in a resources file and any other data in a configuration file. Please, suggest me any design pattern useful for this case.
Whenever you need to invoke different operations based on a switch statement, think about using an abstract class which defines the operation interface and implementation classes which implement the operation.
In your case databaseEngine is a String which names a database. Instead create an abstract class DatabaseEngine and define operations like createDatabase:
public abstract class DatabaseEngine {
public abstract void createDatabase(String databaseName);
public abstract void dropDatabase(String databaseName);
}
and add implementations:
public class PostgresEngine extends DatabaseEngine {
public void createDatabase(String databaseName) {
... // do it the postgres way
}
}
and then use it in your manager class
public void createNewDatabase(String databaseName) {
engine_.createDatabase(databaseName);
}
First thing: switching on strings is so old school; if at all; you would want to use a true enum for that. But of course, that isn't really the point; and switching over enums is as bad as switching over strings (regarding the thing that you have in mind) from a "OO design" point of view.
The solution by wero is definitely the "correct choice" from an OO perspective. You see, good OO design starts with SOLID; and SOLID starts with SRP.
In this case, I would point out the "there is only one reason to change" aspect of SRP. Thing is: if you push all database handling for 2, 3, n different databases into one class ... that means that you have to change that one class if any of your databases requires a change. Besides the obvious: providing "access means" to ONE database is (almost more) than enough of a "single responsibility" for a single class.
Another point of view: this is about balancing. Either you are interested in a good, well structured, "really OO type of" design ... then you have to bite the bullet and either define an interface or abstract base class; that is then implemented/extended differently for each concrete database.
Or you prefer "stuffing everything into one class" ... then just keep what you have, because it really doesn't matter if you use door handles made out of gold or steel ... for a house that was built on a bad basement anyway.
Meaning: your switch statements are just the result of a less-than-optimal design. Now decide if you want to cure the symptom or the root cause of the problem.
I implemented a class Database Manager that manages operations on two database engines.
What if you had three or four or five different databases/storages? For example, Oracle, MongoDB, Redis, etc. Would you still put implementation for all of them into Database Manager?
Database Manager's methods are full of switch cases...
As expected, because you put everything into one class.
Please, suggest me any design pattern useful for this case.
The most straitforward way to simplify your solution would be to separate MySQL and Postgree implementations from each other. You would need to use Factory and Strategy design patterns. If one sees a switch, one should consider using them, but don't be obsessed with patterns. They are NOT your goal, i.e. don't put them everywhere in your code just because you can.
So, you should start from defining your abstractions. Create an interface or an abstract class if there's a functionality common to all database subclasses.
// I'm not sure what methods you need, so I just added methods you mentioned.
public interface MyDatabase {
void drop();
void create();
void runScript();
void compare();
void disconnect();
}
Then you need to implement your databases which in fact are strategies.
public final class MySqlDatabase implements MyDatabase {
#Override
public void drop() {}
...
}
public final class PostgreDatabase implements MyDatabase {
#Override
public void drop() {}
...
}
Finally you need to create a factory. You can make it static or implement an interface if you like.
public class MyDatabaseFactory {
public MyDatabase create(String type) {
switch (type) {
case "mysql":
return new MySqlDatabase();
case "postgress":
return new PostgreDatabase();
default:
throw new IllegalArgumentException();
}
}
}
You don't necessarily have to pass a string. It can be an option/settings class, but they have a tendency to grow which may lead to bloated classes. But don't worry too much about it, it's not your biggest problem at the moment.
Last, but not least. If you don't mind, revise your naming conventions. Please, don't name your classes as managers or helpers.
You could create an abstract base class for your DatabaseEngines like this:
public abstract class DatabaseEngine {
public abstract void createDatabase(final String databaseName);
public abstract void dropDatabase(final String databaseName);
}
And then create concrete implementations for each DatabaseEngine you are supporting:
public final class MySQLEngine extends DatabaseEngine {
#Override
public void createDatabase(final String databaseName) {
}
#Override
public void dropDatabase(final String databaseName) {
}
}
Then when you want to make a call to create/drop it will look more like this:
databaseEngine.createDatabase("whatever");
This is opinion based question: but in my point of view you can use:
Factory Design pattern. This will take care of any other
database added or changed in future.
Example:
public interface IDataBaseEngine {
...
}
public class OracleDBConnection implements IDataBaseEngine {
...
}
public class MySQLDBConnection implements IDataBaseEngine {
....
}
public class DatabaseEngineFactory {
public IDataBaseEngine getDatabaseConnection() {
....
}
}
Second, create files let say xml files which will contains your SQL
and according to your DB (which can be configured) these files will
be converted to its SQL
Example:
SQL file: customer.table
<TABLE>
<SELECT>
<FROM>customer</FROM>
<WHERE>customer_id = ?</WHERE>
<ORDER_BY>customer_id<ORDER_BY>
</SELECT>
</TABLE>
Now if your configuration file says your database is oracle, then while compiling above SQL file it will create following SQL file:
SELECT * FROM customer
WHERE customer_id = ?
ORDER BY customer_id
Ok this is a bit more theoretical question.
I have PlayerRepository. This is a class that is used to make actions on my SQLite database. I've implemented there actions like select, insert, update etc.
public PlayerRepository(Context context) {
super(context, com.fixus.portals.model.Player.class);
open();
}
super in constructor is cause PlayerRepository extends Repository which is also my class. The most important part of Repository is this one
public class Repository<T> {
protected static SQLiteDatabase db = null;
protected static MainHelper helper = null;
protected Context context;
private Class<T> type;
public Repository(Context context, Class<T> classz) {
this.type = classz;
this.context = context;
if(helper == null) {
helper = new MainHelper(context.getApplicationContext());
}
}
public static void open() {
if(db == null) {
db = helper.getWritableDatabase();
}
}
}
As you can see when I create the repository I'm opening DB if it wasn't open before. To do that I need to pass the Context of the application/activity. That is not a problem.
BUT sometimes I want to use my repository out side of an activity. In some kind of tool class that need to get data. So I have two ways that I can think about
I get the data in activity and pass it to my tool class/method so I don't need to use repository in it. This is not very flexible
I need to pass context to my tool class/method. But that means that every kind of operation need to receive a context and I'm not sure this is a good way
Am I missing something ? is there any better way to handle it ?
You always need a Context to access the SQLite database so what u could do is change the constructor of that specific tool class and pass a new instance of PlayerRepository as a parameter. This prevents your tool class of needing a context itself.
Imo if u have multiple classes using the database best approach is to create a new class whose only job is doing database actions and put all the needed action inside that one.
Just create an object of this database class with the Context of the current activity the to Tools and PlayerRepository constructors. This way neither your PlayerRepository or Tools classes need Context and both can make actions on the database.
Even if you should really need Context in PlayerRepository it is always best to keep all database related functions centralized in a single class.
I understand that this is an old question but still i'll write for those like me who will pass by this in future.
In order to get rid of the context problem with repository pattern used for accessing database you can implement DI (Dependency Injection) pattern in your project. There are many reasons to do such and that question illustrates one of them.
If you implement DI you would have only one instance of database repository amongst the entire module (or app). This instance would be created in a class which has context, and injected to those classes where needed.
One of the simpliest approaches for using DI is to use Dagger 2 library. All of the related information you could find on their site.
I'm having trouble to find appropriate solution for that:
I have several databases with the same structure but with different data. And when my web app execute a query, it must separate this query for each database and execute it asynchronously and then aggregate results from all databases and return it as single result. Additionaly I want to be able to pass a list of databases where query would be executed and also I want to pass maximum expiration time for query executing. Also result must contains meta information for each databases such as excess execution time.
It would be great if it possible to use another datasource such as remote web service with specific API, rather than relational database.
I use Spring/Grail and need java solution but I will be glad to any advice.
UPD: I want to find prepared solution, maybe framework or something like that.
This is basic OO. You need to abstract what you are trying to achieve - loading data - from the mechanism you are using to achieve - a database query or a web-service call.
Such a design would usually involve an interface that defines the contract of what can be done and then multiple implementing classes that make it happen according to their implementation.
For example, you'd end up with an interface that looked something like:
public interface DataLoader
{
public Collection<Data> loadData() throws DataLoaderException;
}
You would then have implementations like JdbcDataLoader, WebServiceDataLoader, etc. In your case you would need another type of implementation that given one or more instances of DataLoader, runs each sumulatiously aggregating the results. This implementation would look something like:
public class AggregatingDataLoader implements DataLoader
{
private Collection<DataLoader> dataLoaders;
private ExecutorService executorService;
public AggregatingDataLoader(ExecutorService executorService, Collection<DataLoader> dataLoaders)
{
this.executorService = executorService;
this.dataLoaders = dataLoaders;
}
public Collection<Data> loadData() throws DataLoaderException
{
Collection<DataLoaderCallable>> dataLoaderCallables = new ArrayList<DataLoaderCallable>>();
for (DataLoader dataLoader : dataLoaders)
{
dataLoaderCallables.add(new DataLoaderCallable(dataLoader));
}
List<Future<Collection<Data>>> futures = executorService.invokeAll(dataLoaderCallables);
Collection<Data> data = new ArrayList<Data>();
for (Future<Collection<Data>> future : futures)
{
add.addAll(future.get());
}
return data;
}
private class DataLoaderCallable implements Callable<Collection<Data>>
{
private DataLoader dataLoader;
public DataLoaderCallable(DataLoader dataLoader)
{
this.dataLoader = dataLoader;
}
public Collection<Data> call()
{
return dataLoader.load();
}
}
}
You'll need to add some timeout and exception handling logic to this, but you get the gist.
The other important thing is your call code should only ever use the DataLoader interface so that you can swap different implementations in and out or use mocks during testing.
I have a backend system which we use a third-party Java API to access from our own applications. I can access the system as a normal user along with other users, but I do not have godly powers over it.
Hence to simplify testing I would like to run a real session and record the API calls, and persist them (preferably as editable code), so we can do dry test runs later with API calls just returning the corresponding response from the recording session - and this is the important part - without needing to talk to the above mentioned backend system.
So if my application contains line on the form:
Object b = callBackend(a);
I would like the framework to first capture that callBackend() returned b given the argument a, and then when I do the dry run at any later time say "hey, given a this call should return b". The values of a and b will be the same (if not, we will rerun the recording step).
I can override the class providing the API so all the method calls to capture will go through my code (i.e. byte code instrumentation to alter behavior of classes outside my control is not necessary).
What framework should I look into to do this?
EDIT: Please note that bounty hunters should provide actual code demonstrating the behavior I look for.
Actually You can build such framework or template, by using proxy pattern. Here I explain, how you can do it using dynamic proxy pattern. The idea is to,
Write a proxy manager to get recorder and replayer proxies of API on demand!
Write a wrapper class to store your collected information and also implement hashCode and equals method of that wrapper class for efficient lookup from Map like data structure.
And finally use recorder proxy to record and replayer proxy for replaying purpose.
How recorder works:
invokes the real API
collects the invocation information
persists data in expected persistence context
How replayer works:
Collect the method information (method name, parameters)
If collected information matches with previously recorded information then return the previously collected return value.
If returned value does not match, persist the collected information (As you wanted).
Now, lets look at the implementation. If your API is MyApi like bellow:
public interface MyApi {
public String getMySpouse(String myName);
public int getMyAge(String myName);
...
}
Now we will, record and replay the invocation of public String getMySpouse(String myName). To do that we can use a class to store the invocation information like bellow:
public class RecordedInformation {
private String methodName;
private Object[] args;
private Object returnValue;
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Object[] getArgs() {
return args;
}
public void setArgs(Object[] args) {
this.args = args;
}
public Object getReturnValue() {
return returnType;
}
public void setReturnValue(Object returnValue) {
this.returnValue = returnValue;
}
#Override
public int hashCode() {
return super.hashCode(); //change your implementation as you like!
}
#Override
public boolean equals(Object obj) {
return super.equals(obj); //change your implementation as you like!
}
}
Now Here comes the main part, The RecordReplyManager. This RecordReplyManager gives you proxy object of your API , depending on your need of recording or replaying.
public class RecordReplyManager implements java.lang.reflect.InvocationHandler {
private Object objOfApi;
private boolean isForRecording;
public static Object newInstance(Object obj, boolean isForRecording) {
return java.lang.reflect.Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
new RecordReplyManager(obj, isForRecording));
}
private RecordReplyManager(Object obj, boolean isForRecording) {
this.objOfApi = obj;
this.isForRecording = isForRecording;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
if (isForRecording) {
try {
System.out.println("recording...");
System.out.println("method name: " + method.getName());
System.out.print("method arguments:");
for (Object arg : args) {
System.out.print(" " + arg);
}
System.out.println();
result = method.invoke(objOfApi, args);
System.out.println("result: " + result);
RecordedInformation recordedInformation = new RecordedInformation();
recordedInformation.setMethodName(method.getName());
recordedInformation.setArgs(args);
recordedInformation.setReturnValue(result);
//persist your information
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw new RuntimeException("unexpected invocation exception: " +
e.getMessage());
} finally {
// do nothing
}
return result;
} else {
try {
System.out.println("replying...");
System.out.println("method name: " + method.getName());
System.out.print("method arguments:");
for (Object arg : args) {
System.out.print(" " + arg);
}
RecordedInformation recordedInformation = new RecordedInformation();
recordedInformation.setMethodName(method.getName());
recordedInformation.setArgs(args);
//if your invocation information (this RecordedInformation) is found in the previously collected map, then return the returnValue from that RecordedInformation.
//if corresponding RecordedInformation does not exists then invoke the real method (like in recording step) and wrap the collected information into RecordedInformation and persist it as you like!
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw new RuntimeException("unexpected invocation exception: " +
e.getMessage());
} finally {
// do nothing
}
return result;
}
}
}
If you want to record the method invocation, all you need is getting an API proxy like bellow:
MyApi realApi = new RealApi(); // using new or whatever way get your service implementation (API implementation)
MyApi myApiWithRecorder = (MyApi) RecordReplyManager.newInstance(realApi, true); // true for recording
myApiWithRecorder.getMySpouse("richard"); // to record getMySpouse
myApiWithRecorder.getMyAge("parker"); // to record getMyAge
...
And to replay all you need:
MyApi realApi = new RealApi(); // using new or whatever way get your service implementation (API implementation)
MyApi myApiWithReplayer = (MyApi) RecordReplyManager.newInstance(realApi, false); // false for replaying
myApiWithReplayer.getMySpouse("richard"); // to replay getMySpouse
myApiWithRecorder.getMyAge("parker"); // to replay getMyAge
...
And You are Done!
Edit:
The basic steps of recorder and replayers can be done in above mentioned way. Now its upto you, that how you want to use or perform those steps. You can do what ever you want and whatever you like in the recorder and replayer code blocks and just choose your implementation!
I should prefix this by saying I share some of the concerns in Yves Martin's answer: that such a system may prove frustrating to work with and ultimately less helpful than it would seem at first blush.
That said, from a technical standpoint, this is an interesting problem, and I couldn't not take a go at it. I put together a gist to log method calls in a fairly general way. The CallLoggingProxy class defined there allows usage such as the following.
Calendar original = CallLoggingProxy.create(Calendar.class, Calendar.getInstance());
original.getTimeInMillis(); // 1368311282470
CallLoggingProxy.ReplayInfo replayInfo = CallLoggingProxy.getReplayInfo(original);
// Persist the replay info to disk, serialize to a DB, whatever floats your boat.
// Come back and load it up later...
Calendar replay = CallLoggingProxy.replay(Calendar.class, replayInfo);
replay.getTimeInMillis(); // 1368311282470
You could imagine wrapping your API object with CallLoggingProxy.create prior to passing it into your testing methods, capturing the data afterwards, and persisting it using whatever your favorite serialization system happens to be. Later, when you want to run your tests, you can load the data back up, create a new instance based on the data with CallLoggingProxy.replay, and passing that into your methods instead.
The CallLoggingProxy is written using Javassist, as Java's native Proxy is limited to working against interfaces. This should cover the general use case, but there are a few limitations to keep in mind:
Classes declared final can't be proxied by this method. (Not easily fixable; this is a system limitation)
The gist assumes the same input to a method will always produce the same output. (More easily fixable; the ReplayInfo would need to keep track of sequences of calls for each input instead of single input/output pairs.)
The gist is not even remotely threadsafe (Fairly easily fixable; just requires a little thought and effort)
Obviously the gist is simply a proof of concept, so it's also not been very thoroughly tested, but I believe the general principle is sound. It's also possible there's a more fully baked framework out there to achieve this sort of goal, but if such a thing does exist, I'm not aware of it.
If you do decide to continue with the replay approach, then hopefully this will be enough to give you a possible direction to work in.
I had the same needs some months ago for non-regression testing when planning a heavy technical refactoring of a large application and... I have found nothing available as a framework.
In fact, replaying may be particularly difficult and may only work in a specific context - no (or few) application with a standard complexity can be really considered as stateless. It is a common problem when testing persistence code with a relational database. To be relevant, the complete system initial state must be restored and each replay step must impact the global state the same way. It becomes a challenge when a system state is distributed into pieces like databases, files, memory... Let's guess what happens if a timestamp taken from a system's clock is used somewhere !
So a more pratical option is to only record... and then do a clever comparison for subsequent runs.
Depending of the number of runs you plan, a human-driven session on the application may be enough, or you have to investing in an automated scenario in a robot playing with your application user interface.
First to record: you can use dynamic proxy interface or aspect programming to intercept method call and to capture state before and after invocation. It may mean: dump concerned database tables, copy some files, serialize Java objects in text format like XML.
Then compare this reference capture with a new run. This comparison should be tuned to exclude any irrelevant elements from each piece of state, like row identifiers, timestamps, file names... to only compare data where your backend's added value shines.
Finally nothing really standard, and often a few specific scripts and codes may be enough to achieve the aim: detect as much errors as possible and try to prevent non-expected side-effects.
This can be done with AOP, aspect oriented programming. It allows to intercept method calls by byte code manipulation. Do a bit of search for examples.
In one case this can do recording, in the other replaying.
Pointers: wikipedia, AspectJ, Spring AOP.
Unfortunately one moves a bit outside the java syntax, and a simple example can better be sought elsewhere. With explanation.
Maybe combined with unit tests / some mocking test framework for offline testing with recorded data.
you could look into 'Mockito'
Example:
//You can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);
//stubbing
when(mockedList.get(0)).thenReturn("first");
when(mockedList.get(1)).thenThrow(new RuntimeException());
//following prints "first"
System.out.println(mockedList.get(0));
//following throws runtime exception
System.out.println(mockedList.get(1));
//following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));
after you could replay each test more times and it will return data that you put in.
// pseudocode
class LogMethod {
List<String> parameters;
String method;
addCallTo(String method, List<String> params):
this.method = method;
parameters = params;
}
}
Have a list of LogMethods and call new LogMethod().addCallTo() before every call in your test method.
The idea of playing back the API calls sounds like a use case for the event sourcing pattern. Martin Fowler has a good article on it here. This is a nice pattern that records events as a sequence of objects which are then stored, you can then replay the sequence of events as required.
There is an implementation of this pattern using Akka called Eventsourced, which may help you build the type of system you require.
I had a similar problem some years ago. None of the above solutions would have worked for methods that are not pure functions (side effect free). The major task is in my opinion:
how to extract a snapshot of the recorded object(s) (not only restricted to objects implementing Serializable)
how to generate test code of a serialized representation in a readable way (not only restricted to beans, primitives and collections)
So I had to go my own way - with testrecorder.
For example, given:
ResultObject b = callBackend(a);
...
ResultObject callBackend(SourceObject source) {
...
}
you will only have to annotate the method like this:
#Recorded
ResultObject callBackend(SourceObject source) {
...
}
and start your application (the one that should be recorded) with the testrecorder agent. Testrecorder will manage all tasks for you, such as:
serializing arguments, results, state of this, exceptions (complete object graph!)
finding a readable representation for object construction and object matching
generating a test from the serialized data
you can extend recordings to global variables, input and output with annotations
An example for the test will look like this:
void testCallBackend() {
//arrange
SourceObject sourceObject1 = new SourceObject();
sourceObject1.setState(...); // testrecorder can use setters but is not limited to them
... // setting up backend
... // setting up globals, mocking inputs
//act
ResultObject resultObject1 = backend.callBackend(sourceObject1);
//assert
assertThat(resultObject, new GenericMatcher() {
... // property matchers
}.matching(ResultObject.class));
... // assertions on backend and sourceObject1 for potential side effects
... // assertions on outputs and globals
}
If I understood you question correctly, you should try db4o.
You will store the objects with db4o and restore later to mock and JUnit tests.
I've had someone point out that using a private method to handle query execution for all queries done by a single class increases the risk of SQL injection attacks.
An example of this method might look like this (below). I have omitted some specifics so as not to distract anyone on implementation.
If you want to talk implementation, please feel free to in the comments. The security review did not comment on the contents of the method, but mainly the fact that it should not be its own method.
Note, queryText is generated from a protected static final string containing SQL text for a prepared statement. The ?'s in the prepared statement text are set using PreparedStatement's setString (or set whatever) method. The variables that are set on the prepared statement come into the caller method as strongly typed as possible.
queryText is then passed to the private method.
private ResultSet executeQuery(PreparedStatement stmt) throws SQLException {
// Declare result set variable
try{
try{
// execute statement and store in variable
}
catch(SQLException se){
// log, close connection, do any special processing, rethrow se
}
}
finally{
// This finally block is here to ensure the connection closes if
// some special processing (not shown) in the other try generates a runtime exception
// close connection and statement properly
}
// return result set
}
The recommended alternative was to basically inline the same code in each method that does a query.
I did not post this to security.stackexchange.com because I believe it qualifies as a specific security programming problem.
I can think of no reason why duplicating this code (from a private method) into many classes would add any protection. Would it?
Thank you
Having a central (un-duplicated) place for executing queries is a good idea. Both from a code-maintainability and from a security standpoint. Why have code that could have problems multiple times? It only means that you'll have to maintain it multiple times!
What seems important to me (and which has changed by an edit of the question) is that it should be as hard as possible to execute hand-built SQL Strings with it.
You could, for example, replace any String parameters (which you had initially, but since then replace with a PreparedStatement) with a custom enum:
public enum SQLQuery {
QUERY1("SELECT foo FROM BAR", 0),
QUERY2("SELECT foo from BAR where baz = ?"; 1);
private final String sql;
private final int argumentCount;
private SQLQuery(final String sql, final int argumentCount) {
this.sql = sql;
this.argumentCount = argumentCount;
}
public String getSQL() {
return sql;
}
public int getArgumentCount() {
return argumentCount;
}
}
Then you can write your method like this:
public ResultSet executeQuery(SQLQuery query, Object... arguments) {
// implementation left as an exercise for the reader
}
This way you can be pretty sure that you (or anyone else on your team) don't accidentally passes in a self-build String into your method.
If necessary this approach could be extended to handle different parameter types but for many cases using setObject() works just fine.
For increased modularity you could extract an interface from that enum and allow multiple enums to define queries (for example if you have separate modules in your project). But this has the drawback that malicious (or clueless) developers could use dynamic non-enum implementations of SQLQuery to get their manually-built SQL strings into that method.
If the query being executed by this method has ingredients required for SQL Injection, then irrespective of private/public method, it will impact.
This private method will be invoked by some public method which takes input from either user (or) database. If that input is malicious, private method can't stop it from executing.
Don't use raw SQL strings, always better to use prepared statements.