propagating transaction isolation fix for merovingian2

This commit is contained in:
Alex Huang 2011-07-18 16:48:49 -07:00
parent a86f49c106
commit d54f6d536a
15 changed files with 812 additions and 37 deletions

View File

@ -383,7 +383,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager {
}
}
s_logger.warn("No handling of agent control command: " + cmd.toString() + " sent from " + attache.getId());
s_logger.warn("No handling of agent control command: " + cmd + " sent from " + attache.getId());
return new AgentControlAnswer(cmd);
}
@ -601,7 +601,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager {
Status currentState = host.getStatus();
Status nextState = currentState.getNextStatus(Status.Event.Remove);
if (nextState == null) {
s_logger.debug("There is no transition from state " + currentState.toString() + " to state " + Status.Event.Remove.toString());
s_logger.debug("There is no transition from state " + currentState + " to state " + Status.Event.Remove);
return false;
}
@ -981,7 +981,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager {
long hostId = attache.getId();
s_logger.info("Host " + hostId + " is disconnecting with event " + event.toString());
s_logger.info("Host " + hostId + " is disconnecting with event " + event);
HostVO host = _hostDao.findById(hostId);
if (host == null) {
@ -993,7 +993,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager {
final Status currentState = host.getStatus();
if (currentState == Status.Down || currentState == Status.Alert || currentState == Status.Removed) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Host " + hostId + " is already " + currentState.toString());
s_logger.debug("Host " + hostId + " is already " + currentState);
}
if (currentState != Status.PrepareForMaintenance) {
removeAgent(attache, currentState);
@ -1006,21 +1006,21 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager {
return false;
}
s_logger.debug("There is no transition from state " + currentState.toString() + " and event " + event.toString());
s_logger.debug("There is no transition from state " + currentState + " and event " + event);
assert false : "How did we get here. Look at the FSM";
return false;
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("The next state is " + nextState.toString() + ", current state is " + currentState);
s_logger.debug("The next state is " + nextState + ", current state is " + currentState);
}
// Now we go and correctly diagnose what the actual situation is
if (nextState == Status.Alert && investigate) {
s_logger.info("Investigating why host " + hostId + " has disconnected with event " + event.toString());
s_logger.info("Investigating why host " + hostId + " has disconnected with event " + event);
final Status determinedState = investigate(attache);
s_logger.info("The state determined is " + (determinedState != null ? determinedState.toString() : "undeterminable"));
s_logger.info("The state determined is " + determinedState);
if (determinedState == null || determinedState == Status.Down) {
s_logger.error("Host is down: " + host.getId() + "-" + host.getName() + ". Starting HA on the VMs");
@ -1446,7 +1446,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager {
try {
Host h = _hostDao.findById(hostId);
if (h == null || h.getRemoved() != null) {
s_logger.debug("Host with id " + hostId.toString() + " doesn't exist");
s_logger.debug("Host with id " + hostId + " doesn't exist");
return null;
}
Status status = h.getStatus();
@ -1460,7 +1460,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager {
}
if (s_logger.isDebugEnabled() && answer.getDetails() != null) {
s_logger.debug("Details from executing " + cmd.getClass().toString() + ": " + answer.getDetails());
s_logger.debug("Details from executing " + cmd.getClass() + ": " + answer.getDetails());
}
return answer;
@ -1530,7 +1530,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager {
List<VMInstanceVO> vms = _haMgr.findTakenMigrationWork();
for (VMInstanceVO vm : vms) {
if (vm.getHostId() != null && vm.getHostId() == hostId) {
s_logger.info("Unable to cancel migration because the vm is being migrated: " + vm.toString());
s_logger.info("Unable to cancel migration because the vm is being migrated: " + vm);
return false;
}
}
@ -1595,8 +1595,8 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager {
}
state = host.getStatus();
if (state == Status.Disconnected || state == Status.Updating) {
s_logger.debug("Unable to put host " + hostId + " in matinenance mode because it is currently in " + state.toString());
throw new AgentUnavailableException("Agent is in " + state.toString() + " state. Please wait for it to become Alert state try again.", hostId);
s_logger.debug("Unable to put host " + hostId + " in matinenance mode because it is currently in " + state);
throw new AgentUnavailableException("Agent is in " + state + " state. Please wait for it to become Alert state try again.", hostId);
}
} while (!_hostDao.updateStatus(host, Event.MaintenanceRequested, _nodeId));
@ -1865,12 +1865,12 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager {
server = _hostDao.persist(server);
id = server.getId();
s_logger.info("New " + server.getType().toString() + " host connected w/ guid " + startup.getGuid() + " and id is " + id);
s_logger.info("New " + server.getType() + " host connected w/ guid " + startup.getGuid() + " and id is " + id);
} else {
if (!_hostDao.connect(server, _nodeId)) {
throw new CloudRuntimeException("Agent cannot connect because the current state is " + server.getStatus().toString());
throw new CloudRuntimeException("Agent cannot connect because the current state is " + server.getStatus());
}
s_logger.info("Old " + server.getType().toString() + " host reconnected w/ id =" + id);
s_logger.info("Old " + server.getType() + " host reconnected w/ id =" + id);
}
return server;
@ -2201,7 +2201,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager {
if (attache == null) {
request.logD("Processing the first command ");
if (!(cmd instanceof StartupCommand)) {
s_logger.warn("Throwing away a request because it came through as the first command on a connect: " + request.toString());
s_logger.warn("Throwing away a request because it came through as the first command on a connect: " + request);
return;
}
StartupCommand startup = (StartupCommand) cmd;
@ -2228,28 +2228,28 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager {
attache = handleConnect(link, startups);
} catch (final IllegalArgumentException e) {
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, 0, new Long(0), "Agent from " + startup.getPrivateIpAddress() + " is unable to connect due to " + e.getMessage(), "Agent from "
+ startup.getPrivateIpAddress() + " is unable to connect with " + request.toString() + " because of " + e.getMessage());
s_logger.warn("Unable to create attache for agent: " + request.toString(), e);
+ startup.getPrivateIpAddress() + " is unable to connect with " + request + " because of " + e.getMessage());
s_logger.warn("Unable to create attache for agent: " + request, e);
response = new Response(request, new StartupAnswer((StartupCommand) cmd, e.getMessage()), _nodeId, -1);
} catch (ConnectionException e) {
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, 0, new Long(0), "Agent from " + startup.getPrivateIpAddress() + " is unable to connect due to " + e.getMessage(), "Agent from "
+ startup.getPrivateIpAddress() + " is unable to connect with " + request.toString() + " because of " + e.getMessage());
s_logger.warn("Unable to create attache for agent: " + request.toString(), e);
+ startup.getPrivateIpAddress() + " is unable to connect with " + request + " because of " + e.getMessage());
s_logger.warn("Unable to create attache for agent: " + request, e);
response = new Response(request, new StartupAnswer((StartupCommand) cmd, e.getMessage()), _nodeId, -1);
} catch (final CloudRuntimeException e) {
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, 0, new Long(0), "Agent from " + startup.getPrivateIpAddress() + " is unable to connect due to " + e.getMessage(), "Agent from "
+ startup.getPrivateIpAddress() + " is unable to connect with " + request.toString() + " because of " + e.getMessage());
s_logger.warn("Unable to create attache for agent: " + request.toString(), e);
+ startup.getPrivateIpAddress() + " is unable to connect with " + request + " because of " + e.getMessage());
s_logger.warn("Unable to create attache for agent: " + request, e);
}
if (attache == null) {
if (response == null) {
s_logger.warn("Unable to create attache for agent: " + request.toString());
s_logger.warn("Unable to create attache for agent: " + request);
response = new Response(request, new StartupAnswer((StartupCommand) request.getCommand(), "Unable to register this agent"), _nodeId, -1);
}
try {
link.send(response.toBytes(), true);
} catch (final ClosedChannelException e) {
s_logger.warn("Response was not sent: " + response.toString());
s_logger.warn("Response was not sent: " + response);
}
return;
}
@ -2261,18 +2261,18 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager {
if (cmd instanceof PingRoutingCommand) {
final PingRoutingCommand ping = (PingRoutingCommand) cmd;
if (ping.getNewStates().size() > 0) {
s_logger.debug("SeqA " + hostId + "-" + request.getSequence() + ": Processing " + request.toString());
s_logger.debug("SeqA " + hostId + "-" + request.getSequence() + ": Processing " + request);
} else {
logD = false;
s_logger.debug("Ping from " + hostId);
s_logger.trace("SeqA " + hostId + "-" + request.getSequence() + ": Processing " + request.toString());
s_logger.trace("SeqA " + hostId + "-" + request.getSequence() + ": Processing " + request);
}
} else if (cmd instanceof PingCommand) {
logD = false;
s_logger.debug("Ping from " + hostId);
s_logger.trace("SeqA " + attache.getId() + "-" + request.getSequence() + ": Processing " + request.toString());
s_logger.trace("SeqA " + attache.getId() + "-" + request.getSequence() + ": Processing " + request);
} else {
s_logger.debug("SeqA " + attache.getId() + "-" + request.getSequence() + ": Processing " + request.toString());
s_logger.debug("SeqA " + attache.getId() + "-" + request.getSequence() + ": Processing " + request);
}
}
@ -2351,26 +2351,26 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager {
response = new Response(request, answers, _nodeId, attache.getId());
if (s_logger.isDebugEnabled()) {
if (logD) {
s_logger.debug("SeqA " + attache.getId() + "-" + response.getSequence() + ": Sending " + response.toString());
s_logger.debug("SeqA " + attache.getId() + "-" + response.getSequence() + ": Sending " + response);
} else {
s_logger.trace("SeqA " + attache.getId() + "-" + response.getSequence() + ": Sending " + response.toString());
s_logger.trace("SeqA " + attache.getId() + "-" + response.getSequence() + ": Sending " + response);
}
}
try {
link.send(response.toBytes());
} catch (final ClosedChannelException e) {
s_logger.warn("Unable to send response because connection is closed: " + response.toString());
s_logger.warn("Unable to send response because connection is closed: " + response);
}
}
protected void processResponse(final Link link, final Response response) {
final AgentAttache attache = (AgentAttache) link.attachment();
if (attache == null) {
s_logger.warn("Unable to process: " + response.toString());
s_logger.warn("Unable to process: " + response);
}
if (!attache.processAnswers(response.getSequence(), response)) {
s_logger.info("Host " + attache.getId() + " - Seq " + response.getSequence() + ": Response is not processed: " + response.toString());
s_logger.info("Host " + attache.getId() + " - Seq " + response.getSequence() + ": Response is not processed: " + response);
}
}

View File

@ -0,0 +1,101 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.utils.db;
import java.util.HashMap;
import com.cloud.utils.db.SearchCriteria.Op;
public class Condition<T, K> {
Where<T, K> _where;
Attribute _attr;
String _as;
SearchCriteria.Op _op;
String _paramName;
protected Condition(Where<T, K> where, Attribute attr, String as) {
assert (where != null) : "What am I going to return to the user when Where is null?";
assert (attr != null) : "What's the point of giving me a null attribute?";
_where = where;
_attr = attr;
_as = as;
}
protected NextWhere<T, K> set(Op op, String paramName) {
_op = op;
_paramName = paramName;
Where<T, K> where = _where;
_where = null;
return where;
}
public NextWhere<T, K> eq(String paramName) {
return set(Op.EQ, paramName);
}
public NextWhere<T, K> lt(String paramName) {
return set(Op.LT, paramName);
}
public NextWhere<T, K> lteq(String paramName) {
return set(Op.LTEQ, paramName);
}
public NextWhere<T, K> gt(String paramName) {
return set(Op.GT, paramName);
}
public NextWhere<T, K> isNull() {
return set(Op.NULL, null);
}
public NextWhere<T, K> isNotNull() {
return set(Op.NNULL, null);
}
public NextWhere<T, K> in(String paramName) {
_op = Op.IN;
_paramName = paramName;
return _where;
}
protected String getParamName() {
assert (_paramName instanceof String) : "Well, how can we get back a parameter name if it was not assigned one?";
return _paramName;
}
@Override
public boolean equals(Object obj) {
return _paramName.equals(obj);
}
@Override
public int hashCode() {
return _paramName.hashCode();
}
public void toSql(StringBuilder builder, HashMap<String, Object[]> values) {
if (_as != null) {
builder.append(_as);
} else {
builder.append(_attr.table);
}
builder.append(".").append(_attr.columnName);
}
}

View File

@ -0,0 +1,30 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.utils.db;
public interface FirstWhere<T, K> {
Condition<T, K> field(Object field);
Condition<T, K> field(Object field, String as);
NextWhere<T, K> text(String text, String... paramNames);
FirstWhere<T, K> op();
void done();
}

View File

@ -115,7 +115,7 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
protected final static TimeZone s_gmtTimeZone = TimeZone.getTimeZone("GMT");
protected final static Map<Class<?>, GenericDao<?, ? extends Serializable>> s_daoMaps = new ConcurrentHashMap<Class<?>, GenericDao<?, ? extends Serializable>>(71);
protected final static Map<Class<?>, GenericDaoBase<?, ? extends Serializable>> s_daoMaps = new ConcurrentHashMap<Class<?>, GenericDaoBase<?, ? extends Serializable>>(71);
protected Class<T> _entityBeanType;
protected String _table;
@ -156,9 +156,9 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
protected String _name;
public static <J> GenericDao<? extends J, ? extends Serializable> getDao(Class<J> entityType) {
public static <J> GenericDaoBase<? extends J, ? extends Serializable> getDao(Class<J> entityType) {
@SuppressWarnings("unchecked")
GenericDao<? extends J, ? extends Serializable> dao = (GenericDao<? extends J, ? extends Serializable>)s_daoMaps.get(entityType);
GenericDaoBase<? extends J, ? extends Serializable> dao = (GenericDaoBase<? extends J, ? extends Serializable>)s_daoMaps.get(entityType);
assert dao != null : "Unable to find DAO for " + entityType + ". Are you sure you waited for the DAO to be initialized before asking for it?";
return dao;
}
@ -172,6 +172,10 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
factory.setCallback(0, builder);
return builder;
}
public final Map<String, Attribute> getAllAttributes() {
return _allAttributes;
}
@SuppressWarnings("unchecked")
protected GenericDaoBase() {

View File

@ -0,0 +1,32 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.utils.db;
/**
* JoinQueryBuilder builds queries for joins between multiple tables.
*
*/
public interface JoinQueryBuilder<S, T> {
Select<S, T> selectField(Object column);
<J> On<S, J, T> innerJoin(Class<J> entityClazz);
<J> J entity(Class<J> entityClazz);
FirstWhere<S, T> where();
}

View File

@ -66,6 +66,7 @@ public class Merovingian2 extends StandardMBean implements MerovingianMBean {
Connection conn = null;
try {
conn = Transaction.getStandaloneConnectionWithException();
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
_concierge = new ConnectionConcierge("LockMaster", conn, true, true);
} catch (SQLException e) {
s_logger.error("Unable to get a new db connection", e);

View File

@ -0,0 +1,28 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.utils.db;
public interface NextWhere<T, K> extends FirstWhere<T, K> {
NextWhere<T, K> and();
NextWhere<T, K> or();
NextWhere<T, K> not();
@Override
void done();
}

View File

@ -0,0 +1,22 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.utils.db;
public interface On<S, J, T> {
}

View File

@ -0,0 +1,195 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.utils.db;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import com.cloud.utils.Pair;
public class QueryBuilder<S, T> implements MethodInterceptor, SimpleQueryBuilder<S>, SelectQueryBuilder<S, T>, JoinQueryBuilder<S, T> {
public enum Func {
NATIVE("@", 1),
MAX("MAX(@)", 1),
MIN("MIN(@)", 1),
FIRST("FIRST(@)", 1),
LAST("LAST(@)", 1),
SUM("SUM(@)", 1),
COUNT("COUNT(@)", 1),
DISTINCT("DISTINCT(@)", 1);
private String func;
private int count;
Func(String func, int params) {
this.func = func;
this.count = params;
}
@Override
public String toString() {
return func;
}
public int getCount() {
return count;
}
}
protected HashMap<Class<?>, Pair<GenericDaoBase<?,?>, Object>> _entities;
protected ArrayList<Attribute> _specifiedAttrs = new ArrayList<Attribute>();
protected T _resultSetClass;
protected ArrayList<Select<S, T>> _selects;
public QueryBuilder(Class<T> resultSetClass, Class<?>... clazzes) {
_entities = new HashMap<Class<?>, Pair<GenericDaoBase<?,?>, Object>>(clazzes.length);
for (Class<?> clazz : clazzes) {
GenericDaoBase<?,?> dao = GenericDaoBase.getDao(clazz);
Enhancer searchEnhancer = new Enhancer();
searchEnhancer.setSuperclass(clazz);
searchEnhancer.setCallback(this);
Object entity = searchEnhancer.create();
_entities.put(clazz, new Pair<GenericDaoBase<?, ?>, Object>(dao, entity));
}
}
protected void clean() {
_specifiedAttrs = null;
_entities = null;
}
/**
* Constructor for SelectQueryBuilder interface. Must specify the
* table to be performing the query on and the result class to place it in.
* @param entityClass entity class to do the query on.
* @param resultSetClass result class to put the result set in.
*/
public QueryBuilder(Class<S> entityClass, Class<T> resultSetClass) {
_entities = new HashMap<Class<?>, Pair<GenericDaoBase<?,?>, Object>>(1);
GenericDaoBase<?,?> dao = GenericDaoBase.getDao(entityClass);
Enhancer searchEnhancer = new Enhancer();
searchEnhancer.setSuperclass(entityClass);
searchEnhancer.setCallback(this);
Object entity = searchEnhancer.create();
_entities.put(entityClass, new Pair<GenericDaoBase<?, ?>, Object>(dao, entity));
}
@Override
public SimpleQueryBuilder<S> selectFields(Object... fields) {
assert _entities != null && _entities.size() == 1 : "Now you've done it....Stop casting interfaces on the QueryBuilder";
assert _specifiedAttrs.size() > 0 : "You didn't specify any attributes";
if (_selects == null) {
_selects = new ArrayList<Select<S, T>>(fields.length);
}
for (Attribute attr : _specifiedAttrs) {
_selects.add(new Select<S, T>(this, null, attr));
}
_specifiedAttrs.clear();
return this;
}
protected void set(GenericDaoBase<?, ?> dao , String name) {
Attribute attr = dao.getAllAttributes().get(name);
assert (attr != null) : "Searching for a field that's not there: " + name;
_specifiedAttrs.add(attr);
}
@Override
public Object intercept(Object entity, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Class<?> entityClass = entity.getClass().getSuperclass();
Pair<GenericDaoBase<?,?>, Object> daoInfo = _entities.get(entityClass);
assert (daoInfo != null) : "You need to specify " + entityClass + " as one of the entities in the Query";
GenericDaoBase<?,?> dao = daoInfo.first();
String name = method.getName();
if (name.startsWith("get")) {
String fieldName = Character.toLowerCase(name.charAt(3)) + name.substring(4);
set(dao, fieldName);
return null;
} else if (name.startsWith("is")) {
String fieldName = Character.toLowerCase(name.charAt(2)) + name.substring(3);
set(dao, fieldName);
return null;
} else {
assert false : "Perhaps you need to make the method start with get or is?";
}
return proxy.invokeSuper(entity, args);
}
@Override
@SuppressWarnings("unchecked")
public <E> E entity(Class<E> clazz) {
return (E)_entities.get(clazz).second();
}
@Override
@SuppressWarnings("unchecked")
public S entity() {
return (S)_entities.values().iterator().next().second();
}
@Override
public FirstWhere<S, T> where() {
return new Where<S, T>(this);
}
@Override
public SimpleQueryBuilder<S> selectAll() {
return this;
}
public List<Attribute> getSpecifiedAttributes() {
return _specifiedAttrs;
}
public Attribute getSpecifiedAttribute() {
assert _specifiedAttrs.size() == 1 : "You can only specify one attribute";
return _specifiedAttrs.get(0);
}
@Override
public Select<S, T> selectColumn(Object column) {
return null;
}
@Override
public Select<S, T> selectField(Object column) {
// TODO Auto-generated method stub
return null;
}
@Override
public <J> On<S, J, T> innerJoin(Class<J> entityClazz) {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -123,8 +123,24 @@ public class SearchCriteria<K> {
private final List<Object> _groupByValues;
private final Class<K> _resultType;
private final SelectType _selectType;
private final QueryBuilder<?, K> _builder;
protected SearchCriteria(QueryBuilder<?, K> builder) {
_builder = builder;
_attrs = null;
_conditions = null;
_additionals = null;
_counter = 0;
_joins = null;
_selects = null;
_groupBy = null;
_groupByValues = null;
_resultType = null;
_selectType = null;
}
protected SearchCriteria(GenericSearchBuilder<?, K> sb) {
this._builder = null;
this._attrs = sb._attrs;
this._conditions = sb._conditions;
this._additionals = new ArrayList<Condition>();
@ -322,4 +338,10 @@ public class SearchCriteria<K> {
}
}
}
public Pair<String, ArrayList<Object>> toSql() {
StringBuilder sql = new StringBuilder();
return new Pair<String, ArrayList<Object>>(sql.toString(), null);
}
}

View File

@ -0,0 +1,53 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.utils.db;
import java.lang.reflect.Field;
public class Select<S, T> {
QueryBuilder<S,T> _builder;
Class<T> _clazz;
Attribute _attr;
String _as;
Field _field;
protected Select(QueryBuilder<S, T> builder, Class<T> clazz, Attribute attr) {
_builder = builder;
_clazz = clazz;
_attr = attr;
}
public QueryBuilder<S, T> into(String fieldName) {
if (fieldName != null) {
try {
_field = _clazz.getDeclaredField(fieldName);
_field.setAccessible(true);
} catch (SecurityException e) {
throw new RuntimeException("Unable to find " + fieldName + " in " + _clazz.getName(), e);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Unable to find " + fieldName + " in " + _clazz.getName(), e);
}
}
return _builder;
}
public QueryBuilder<S, T> as(String as) {
_as = as;
return _builder;
}
}

View File

@ -0,0 +1,30 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.utils.db;
/**
* SelectQueryBuilder allows you to select a column into a class that
* is defined.
*/
public interface SelectQueryBuilder<T, S> {
Select<T, S> selectColumn(Object column);
T entity();
FirstWhere<T, S> where();
}

View File

@ -0,0 +1,49 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.utils.db;
/**
* SimpleQueryBuilder builds queries against a single table. The
* result is stored into the entity that represents the table.
*
*/
public interface SimpleQueryBuilder<S> {
/**
* Select all of the columns in the entity object. This is default so
* it's not necessary to make this method call at all.
*/
SimpleQueryBuilder<S> selectAll();
/**
* Select the following columns
* @param columns array of columsn to select.
*/
SimpleQueryBuilder<S> selectFields(Object... columns);
/**
* @return the entity object we're building this query for. By using this
* entity object, you can specify which column to select or form
*/
S entity();
/**
* Starts the query conditionals.
* @return
*/
FirstWhere<S, ?> where();
}

View File

@ -0,0 +1,82 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.utils.db;
import java.util.ArrayList;
import java.util.List;
/**
* Where implements any list of search conditions.
*
*/
public class Where<T, K> implements FirstWhere<T, K>, NextWhere<T, K> {
QueryBuilder<T, K> _builder;
List<Object> _conditions = new ArrayList<Object>();
protected Where(QueryBuilder<T, K> builder) {
_builder = builder;
}
@Override
public Condition<T, K> field(Object useless, String as) {
Attribute attr = _builder.getSpecifiedAttribute();
Condition<T, K> cond = new Condition<T, K>(this, attr, as);
_conditions.add(cond);
return cond;
}
@Override
public Where<T, K> and() {
_conditions.add(" (");
return this;
}
@Override
public Where<T, K> or() {
_conditions.add(" OR ");
return this;
}
@Override
public NextWhere<T, K> not() {
_conditions.add(" NOT ");
return this;
}
@Override
public NextWhere<T, K> text(String text, String... paramNames) {
assert ((paramNames.length == 0 && !text.contains("?")) || (text.matches("\\?.*{" + paramNames.length + "}")));
// TODO Auto-generated method stub
return null;
}
@Override
public Condition<T, K> field(Object useless) {
return field(useless, null);
}
@Override
public FirstWhere<T, K> op() {
_conditions.add("(");
return this;
}
@Override
public void done() {
}
}

View File

@ -0,0 +1,126 @@
package com.cloud.utils.db;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import junit.framework.TestCase;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.exception.CloudRuntimeException;
public class QueryBuilderTest extends TestCase {
@Entity
@Table(name="test")
public static class TestVO {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
long id;
@Column(name="int")
int fieldInt;
@Column(name="long")
Long fieldLong;
@Column(name="string")
String fieldString;
public String getFieldString() {
return fieldString;
}
public int getFieldInt() {
return fieldInt;
}
public long getFieldLong() {
return fieldLong;
}
public TestVO() {
}
}
public static class TestDao extends GenericDaoBase<TestVO, Long> implements GenericDao<TestVO, Long> {
protected TestDao() {
}
}
public void setup() {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = Transaction.getStandaloneConnection();
pstmt = conn.prepareStatement("CREATE TABLE `cloud`.`test` (" +
"`id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT," +
"`int` int unsigned," +
"`long` bigint unsigned," +
"`string` varchar(255)," +
"PRIMARY KEY (`id`)" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8;");
pstmt.execute();
} catch (SQLException e) {
throw new CloudRuntimeException("Problem with sql", e);
} finally {
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
}
}
}
public void teardown() {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = Transaction.getStandaloneConnection();
pstmt = conn.prepareStatement("DROP TABLE IF EXISTS `cloud`.`test`");
pstmt.execute();
} catch (SQLException e) {
throw new CloudRuntimeException("Problem with sql", e);
} finally {
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
}
}
}
public void testSimpleQueryBuilder() {
TestDao dao = ComponentLocator.inject(TestDao.class);
SimpleQueryBuilder<TestVO> qb = new QueryBuilder<TestVO, TestVO>(TestVO.class, TestVO.class);
qb.selectFields(qb.entity().getFieldLong()).where().field(qb.entity().getFieldInt()).eq("abc");
}
}