diff --git a/api/src/com/cloud/agent/api/to/NetworkTO.java b/api/src/com/cloud/agent/api/to/NetworkTO.java index ed446da126e..363946a3d5a 100644 --- a/api/src/com/cloud/agent/api/to/NetworkTO.java +++ b/api/src/com/cloud/agent/api/to/NetworkTO.java @@ -18,6 +18,7 @@ package com.cloud.agent.api.to; import java.net.URI; +import java.util.List; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.TrafficType; @@ -38,10 +39,11 @@ public class NetworkTO { protected URI broadcastUri; protected URI isolationUri; protected boolean isSecurityGroupEnabled; - + protected String[] tags; + public NetworkTO() { } - + public String getUuid() { return uuid; } @@ -85,11 +87,19 @@ public class NetworkTO { public void setType(TrafficType type) { this.type = type; } - + + public void setTags(List tags) { + this.tags = tags.toArray(new String[tags.size()]); + } + + public String[] getTags() { + return tags; + } + public void setSecurityGroupEnabled(boolean enabled) { this.isSecurityGroupEnabled = enabled; } - + /** * This constructor is usually for hosts where the other information are not important. * @@ -100,7 +110,7 @@ public class NetworkTO { public NetworkTO(String ip, String netmask, String mac) { this(ip, netmask, mac, null, null, null); } - + /** * This is the full constructor and should be used for VM's network as it contains * the full information about what is needed. @@ -145,27 +155,27 @@ public class NetworkTO { public String getDns2() { return dns2; } - + public TrafficType getType() { return type; } - + public URI getBroadcastUri() { return broadcastUri; } - + public void setBroadcastUri(URI broadcastUri) { this.broadcastUri = broadcastUri; } - + public URI getIsolationUri() { return isolationUri; } - + public void setIsolationuri(URI isolationUri) { this.isolationUri = isolationUri; } - + public boolean isSecurityGroupEnabled() { return this.isSecurityGroupEnabled; } diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index b531fd254ad..ad6532cb19b 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -37,14 +37,14 @@ import com.cloud.utils.fsm.StateMachine; * owned by an account. */ public interface Network extends ControlledEntity { - + public enum GuestIpType { Virtual, Direct, } - + public static class Service { - + public static final Service Vpn = new Service("Vpn", Capability.SupportedVpnTypes); public static final Service Dhcp = new Service("Dhcp"); public static final Service Dns = new Service("Dns"); @@ -52,7 +52,7 @@ public interface Network extends ControlledEntity { public static final Service Firewall = new Service("Firewall", Capability.PortForwarding, Capability.StaticNat, Capability.SupportedProtocols, Capability.MultipleIps, Capability.SupportedSourceNatTypes, Capability.TrafficStatistics); public static final Service Lb = new Service("Lb", Capability.SupportedLBAlgorithms, Capability.SupportedProtocols, Capability.TrafficStatistics, Capability.LoadBalancingSupportedIps); public static final Service UserData = new Service("UserData"); - + private String name; private Capability[] caps; @@ -60,15 +60,15 @@ public interface Network extends ControlledEntity { this.name = name; this.caps = caps; } - + public String getName() { return name; } - + public Capability[] getCapabilities() { return caps; } - + public boolean containsCapability(Capability cap) { boolean success = false; if (caps != null) { @@ -80,13 +80,13 @@ public interface Network extends ControlledEntity { } } } - + return success; } } - + public static class Provider { - + public static final Provider VirtualRouter = new Provider("VirtualRouter"); public static final Provider DhcpServer = new Provider("DhcpServer"); public static final Provider JuniperSRX = new Provider("JuniperSRX"); @@ -94,20 +94,20 @@ public interface Network extends ControlledEntity { public static final Provider ExternalDhcpServer = new Provider("ExternalDhcpServer"); public static final Provider ExternalGateWay = new Provider("ExternalGateWay"); public static final Provider None = new Provider("None"); - + private String name; - + public Provider(String name) { this.name = name; } - + public String getName() { return name; } } - + public static class Capability { - + public static final Capability PortForwarding = new Capability("PortForwarding"); public static final Capability StaticNat = new Capability("StaticNat"); public static final Capability SupportedProtocols = new Capability("SupportedProtocols"); @@ -117,25 +117,25 @@ public interface Network extends ControlledEntity { public static final Capability SupportedVpnTypes = new Capability("SupportedVpnTypes"); public static final Capability TrafficStatistics = new Capability("TrafficStatistics"); public static final Capability LoadBalancingSupportedIps = new Capability("LoadBalancingSupportedIps"); - + private String name; - + public Capability(String name) { this.name = name; } - + public String getName() { return name; } } - + enum Event { ImplementNetwork, DestroyNetwork, OperationSucceeded, OperationFailed; } - + enum State implements FiniteState { Allocated("Indicates the network configuration is in allocated but not setup"), Setup("Indicates the network configuration is setup"), @@ -143,7 +143,7 @@ public interface Network extends ControlledEntity { Implemented("Indicates the network configuration is in use"), Shutdown("Indicates the network configuration is being destroyed"), Destroy("Indicates that the network is destroyed"); - + @Override public StateMachine getStateMachine() { @@ -164,18 +164,18 @@ public interface Network extends ControlledEntity { public Set getPossibleEvents() { return s_fsm.getPossibleEvents(this); } - + String _description; - + @Override public String getDescription() { return _description; } - + private State(String description) { _description = description; } - + private static StateMachine s_fsm = new StateMachine(); static { s_fsm.addTransition(State.Allocated, Event.ImplementNetwork, State.Implementing); @@ -186,12 +186,12 @@ public interface Network extends ControlledEntity { s_fsm.addTransition(State.Shutdown, Event.OperationFailed, State.Implemented); } } - + /** * @return id of the network profile. Null means the network profile is not from the database. */ long getId(); - + String getName(); Mode getMode(); @@ -205,27 +205,29 @@ public interface Network extends ControlledEntity { String getCidr(); long getDataCenterId(); - + long getNetworkOfferingId(); - + State getState(); - + long getRelated(); - + URI getBroadcastUri(); - + GuestIpType getGuestType(); - + String getDisplayText(); - + boolean getIsShared(); - + String getReservationId(); - + boolean isDefault(); - + String getNetworkDomain(); boolean isSecurityGroupEnabled(); + List getTags(); + } diff --git a/api/src/com/cloud/network/NetworkProfile.java b/api/src/com/cloud/network/NetworkProfile.java index cd1fd08cc17..64da475b91d 100644 --- a/api/src/com/cloud/network/NetworkProfile.java +++ b/api/src/com/cloud/network/NetworkProfile.java @@ -19,13 +19,14 @@ package com.cloud.network; import java.net.URI; +import java.util.List; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.Mode; import com.cloud.network.Networks.TrafficType; -public class NetworkProfile implements Network{ +public class NetworkProfile implements Network { private long id; private long dataCenterId; private long ownerId; @@ -49,6 +50,7 @@ public class NetworkProfile implements Network{ private boolean isDefault; private String networkDomain; private boolean isSecurityGroupEnabled; + private List tags; public NetworkProfile(Network network) { this.id = network.getId(); @@ -74,6 +76,11 @@ public class NetworkProfile implements Network{ this.isSecurityGroupEnabled = network.isSecurityGroupEnabled(); } + @Override + public List getTags() { + return tags; + } + public String getDns1() { return dns1; } @@ -89,7 +96,7 @@ public class NetworkProfile implements Network{ public void setDns2(String dns2) { this.dns2 = dns2; } - + public void setBroadcastUri(URI broadcastUri) { this.broadcastUri = broadcastUri; } @@ -103,22 +110,22 @@ public class NetworkProfile implements Network{ public long getId() { return id; } - + @Override public long getDataCenterId() { return dataCenterId; } - + @Override public long getAccountId() { return ownerId; } - + @Override public State getState() { return state; } - + @Override public String getName() { return name; @@ -153,37 +160,37 @@ public class NetworkProfile implements Network{ public long getNetworkOfferingId() { return networkOfferingId; } - + @Override public long getRelated() { return related; } - + @Override public GuestIpType getGuestType() { return guestIpType; } - + @Override public String getDisplayText() { return displayText; } - + @Override public boolean getIsShared() { return isShared; } - + @Override public String getReservationId() { return reservationId; } - + @Override public boolean isDefault() { return isDefault; } - + @Override public String getNetworkDomain() { return networkDomain; @@ -193,7 +200,7 @@ public class NetworkProfile implements Network{ public long getDomainId() { return domainId; } - + @Override public boolean isSecurityGroupEnabled() { return isSecurityGroupEnabled; diff --git a/api/src/com/cloud/vm/NicProfile.java b/api/src/com/cloud/vm/NicProfile.java index 0d49870a94c..7105fa6226b 100644 --- a/api/src/com/cloud/vm/NicProfile.java +++ b/api/src/com/cloud/vm/NicProfile.java @@ -22,6 +22,7 @@ package com.cloud.vm; import java.net.URI; +import java.util.List; import com.cloud.network.Network; import com.cloud.network.Networks.AddressFormat; @@ -53,11 +54,16 @@ public class NicProfile { String dns2; Integer networkRate; boolean isSecurityGroupEnabled; + List tags; public String getDns1() { return dns1; } + public List getTags() { + return tags; + } + public String getDns2() { return dns2; } @@ -226,6 +232,7 @@ public class NicProfile { this.netmask = nic.getNetmask(); this.isSecurityGroupEnabled = network.isSecurityGroupEnabled(); this.vmId = nic.getInstanceId(); + this.tags = network.getTags(); if (networkRate != null) { this.networkRate = networkRate; diff --git a/core/src/com/cloud/agent/transport/Request.java b/core/src/com/cloud/agent/transport/Request.java index a1669ff55d5..79028e9e477 100755 --- a/core/src/com/cloud/agent/transport/Request.java +++ b/core/src/com/cloud/agent/transport/Request.java @@ -23,8 +23,10 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import org.apache.log4j.Level; import org.apache.log4j.Logger; +import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; import com.cloud.agent.api.SecStorageFirewallCfgCommand.PortConfig; import com.cloud.exception.UnsupportedVersionException; @@ -64,6 +66,7 @@ public class Request { protected static final Gson s_gson = GsonHelper.getGson(); protected static final Gson s_gogger = GsonHelper.getGsonLogger(); + protected static final Logger s_gsonLogger = GsonHelper.getLogger(); public enum Version { v1, // using gson to marshall @@ -278,47 +281,69 @@ public class Request { public void logD(String msg, boolean logContent) { if (s_logger.isDebugEnabled()) { - s_logger.debug(log(msg, logContent)); + String log = log(msg, logContent, Level.DEBUG); + if (log != null) { + s_logger.debug(log); + } } } public void logT(String msg, boolean logD) { if (s_logger.isTraceEnabled()) { - s_logger.trace(log(msg, true)); + String log = log(msg, true, Level.TRACE); + if (log != null) { + s_logger.trace(log); + } } else if (logD && s_logger.isDebugEnabled()) { - s_logger.debug(log(msg, false)); + String log = log(msg, false, Level.DEBUG); + if (log != null) { + s_logger.debug(log); + } } } - protected String log(String msg, boolean logContent) { + protected String log(String msg, boolean logContent, Level level) { + StringBuilder content = new StringBuilder(); + if (logContent) { + if (_cmds == null) { + _cmds = s_gson.fromJson(_content, this instanceof Response ? Answer[].class : Command[].class); + } + try { + s_gogger.toJson(_cmds, content); + } catch (Throwable e) { + StringBuilder buff = new StringBuilder(); + for (Command cmd : _cmds) { + buff.append(cmd.getClass().getSimpleName()).append("/"); + } + s_logger.error("Gson serialization error " + buff.toString(), e); + assert false : "More gson errors on " + buff.toString(); + return ""; + } + if (content.length() <= 4) { + return null; + } + } else { + if (_cmds == null) { + _cmds = s_gson.fromJson(_content, this instanceof Response ? Answer[].class : Command[].class); + } + content.append("{ "); + for (Command cmd : _cmds) { + content.append(cmd.getClass().getSimpleName()).append(", "); + } + content.replace(content.length() - 2, content.length(), " }"); + + } + StringBuilder buf = new StringBuilder("Seq "); + buf.append(_agentId).append("-").append(_seq).append(": "); buf.append(msg); - buf.append("{ ").append(getType()); + buf.append(" { ").append(getType()); buf.append(", MgmtId: ").append(_mgmtId).append(", via: ").append(_via); - if (logContent) { - buf.append(", Ver: ").append(_ver.toString()); - buf.append(", Flags: ").append(Integer.toBinaryString(getFlags())).append(", "); - if (_cmds != null) { - try { - s_gogger.toJson(_cmds, buf); - } catch (Throwable e) { - StringBuilder buff = new StringBuilder(); - for (Command cmd : _cmds) { - buff.append(cmd.getClass().getName()).append("/"); - } - s_logger.error("Gson serialization error " + buff.toString(), e); - assert false : "More gson errors on " + buff.toString(); - return ""; - } - } else if (_content != null) { - buf.append(_content.subSequence(0, 32)); - } else { - buf.append("I've got nada here!"); - assert false : "How can both commands and content be null? What are we sending here?"; - } - } + buf.append(", Ver: ").append(_ver.toString()); + buf.append(", Flags: ").append(Integer.toBinaryString(getFlags())).append(", "); + buf.append(content); buf.append(" }"); return buf.toString(); } diff --git a/core/src/com/cloud/serializer/GsonHelper.java b/core/src/com/cloud/serializer/GsonHelper.java index 93a7ddf9cd7..e5143496127 100644 --- a/core/src/com/cloud/serializer/GsonHelper.java +++ b/core/src/com/cloud/serializer/GsonHelper.java @@ -75,4 +75,8 @@ public class GsonHelper { public final static Gson getGsonLogger() { return s_gogger; } + + public final static Logger getLogger() { + return s_logger; + } } diff --git a/core/test/com/cloud/agent/transport/RequestTest.java b/core/test/com/cloud/agent/transport/RequestTest.java index 7f55f62bab7..150a29f67d7 100644 --- a/core/test/com/cloud/agent/transport/RequestTest.java +++ b/core/test/com/cloud/agent/transport/RequestTest.java @@ -54,7 +54,7 @@ public class RequestTest extends TestCase { Level level = logger.getLevel(); logger.setLevel(Level.DEBUG); - String log = sreq.log("Debug", true); + String log = sreq.log("Debug", true, Level.DEBUG); assert (log.contains(UpdateHostPasswordCommand.class.getSimpleName())); assert (log.contains(SecStorageFirewallCfgCommand.class.getSimpleName())); assert (!log.contains(GetHostStatsCommand.class.getSimpleName())); @@ -62,7 +62,7 @@ public class RequestTest extends TestCase { assert (!log.contains("password")); logger.setLevel(Level.TRACE); - log = sreq.log("Trace", true); + log = sreq.log("Trace", true, Level.TRACE); assert (log.contains(UpdateHostPasswordCommand.class.getSimpleName())); assert (log.contains(SecStorageFirewallCfgCommand.class.getSimpleName())); assert (log.contains(GetHostStatsCommand.class.getSimpleName())); @@ -70,7 +70,7 @@ public class RequestTest extends TestCase { assert (!log.contains("password")); logger.setLevel(Level.INFO); - sreq.log("Info", true); + sreq.log("Info", true, Level.INFO); assert (log.contains(UpdateHostPasswordCommand.class.getSimpleName())); assert (log.contains(SecStorageFirewallCfgCommand.class.getSimpleName())); assert (!log.contains(GetHostStatsCommand.class.getSimpleName())); @@ -127,6 +127,28 @@ public class RequestTest extends TestCase { } + public void testLogging() { + GetHostStatsCommand cmd3 = new GetHostStatsCommand("hostguid", "hostname", 101); + Request sreq = new Request(2, 3, new Command[] { cmd3 }, true, true); + sreq.setSequence(1); + Logger logger = Logger.getLogger(GsonHelper.class); + Level level = logger.getLevel(); + + logger.setLevel(Level.DEBUG); + String log = sreq.log("Debug", true, Level.DEBUG); + assert (log == null); + + log = sreq.log("Debug", false, Level.DEBUG); + assert (log != null); + + logger.setLevel(Level.TRACE); + log = sreq.log("Trace", true, Level.TRACE); + assert (log.contains(GetHostStatsCommand.class.getSimpleName())); + s_logger.debug(log); + + logger.setLevel(level); + } + protected void compareRequest(Request req1, Request req2) { assert req1.getSequence() == req2.getSequence(); assert req1.getAgentId() == req2.getAgentId(); diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java index 2ab545115eb..197739abb18 100644 --- a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java @@ -33,7 +33,7 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis protected HypervisorGuruBase() { super(); } - + protected NicTO toNicTO(NicProfile profile) { NicTO to = new NicTO(); to.setDeviceId(profile.getDeviceId()); @@ -50,39 +50,41 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis to.setIsolationuri(profile.getIsolationUri()); to.setNetworkRateMbps(profile.getNetworkRate()); to.setSecurityGroupEnabled(profile.isSecurityGroupEnabled()); + to.setTags(profile.getTags()); return to; } - - + + protected VirtualMachineTO toVirtualMachineTO(VirtualMachineProfile vmProfile) { - + ServiceOffering offering = vmProfile.getServiceOffering(); VirtualMachine vm = vmProfile.getVirtualMachine(); - + VirtualMachineTO to = new VirtualMachineTO(vm.getId(), vm.getInstanceName(), vm.getType(), offering.getCpu(), offering.getSpeed(), - offering.getRamSize() * 1024l * 1024l, offering.getRamSize() * 1024l * 1024l, null, null, vm.isHaEnabled(), vm.limitCpuUse(), vm.getVncPassword()); + offering.getRamSize() * 1024l * 1024l, offering.getRamSize() * 1024l * 1024l, null, null, vm.isHaEnabled(), vm.limitCpuUse(), vm.getVncPassword()); to.setBootArgs(vmProfile.getBootArgs()); - + List nicProfiles = vmProfile.getNics(); NicTO[] nics = new NicTO[nicProfiles.size()]; int i = 0; for (NicProfile nicProfile : nicProfiles) { nics[i++] = toNicTO(nicProfile); } - + to.setNics(nics); to.setDisks(vmProfile.getDisks().toArray(new VolumeTO[vmProfile.getDisks().size()])); - + if(vmProfile.getTemplate().getBits() == 32) { to.setArch("i686"); } else { to.setArch("x86_64"); } - + return to; } - + + @Override public long getCommandHostDelegation(long hostId, Command cmd) { - return hostId; + return hostId; } } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 56b50d44580..3e7be21359b 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -234,7 +234,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag @DB public PublicIp fetchNewPublicIp(long dcId, Long podId, Long vlanDbId, Account owner, VlanType vlanUse, Long networkId, boolean sourceNat, boolean assign) - throws InsufficientAddressCapacityException { + throws InsufficientAddressCapacityException { Transaction txn = Transaction.currentTxn(); txn.start(); SearchCriteria sc = null; @@ -570,7 +570,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag boolean isSourceNat = false; txn.start(); - + NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); if (!offering.isSharedSourceNatService()) { // First IP address should be source nat when it's being associated with Guest Virtual network @@ -828,7 +828,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag @Override public List setupNetwork(Account owner, NetworkOfferingVO offering, DeploymentPlan plan, String name, String displayText, boolean isShared, boolean isDefault) - throws ConcurrentOperationException { + throws ConcurrentOperationException { return setupNetwork(owner, offering, null, plan, name, displayText, isShared, isDefault, false, null); } @@ -1098,7 +1098,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag @Override @DB public Pair implementNetwork(long networkId, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, - InsufficientCapacityException { + InsufficientCapacityException { Transaction.currentTxn(); Pair implemented = new Pair(null, null); @@ -1193,7 +1193,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag @Override public void prepare(VirtualMachineProfile vmProfile, DeployDestination dest, ReservationContext context) throws InsufficientCapacityException, - ConcurrentOperationException, ResourceUnavailableException { + ConcurrentOperationException, ResourceUnavailableException { List nics = _nicDao.listByVmId(vmProfile.getId()); // we have to implement default nics first - to ensure that default network elements start up first in multiple nics @@ -1667,7 +1667,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag if (!NetUtils.verifyDomainName(networkDomain)) { throw new InvalidParameterValueException( "Invalid network domain. Total length shouldn't exceed 190 chars. Each domain label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', " - + "and the hyphen ('-'); can't start or end with \"-\""); + + "and the hyphen ('-'); can't start or end with \"-\""); } } @@ -2500,7 +2500,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag @Override @DB public boolean associateIpAddressListToAccount(long userId, long accountId, long zoneId, Long vlanId, Network network) throws InsufficientCapacityException, ConcurrentOperationException, - ResourceUnavailableException { + ResourceUnavailableException { Account owner = _accountMgr.getActiveAccount(accountId); boolean createNetwork = false; diff --git a/server/src/com/cloud/network/NetworkVO.java b/server/src/com/cloud/network/NetworkVO.java index 8d8954eb4c1..ab760faacfe 100644 --- a/server/src/com/cloud/network/NetworkVO.java +++ b/server/src/com/cloud/network/NetworkVO.java @@ -18,7 +18,9 @@ package com.cloud.network; import java.net.URI; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; @@ -32,6 +34,7 @@ import javax.persistence.Transient; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.Mode; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.dao.NetworkDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.GenericDao; import com.cloud.utils.net.NetUtils; @@ -47,99 +50,102 @@ public class NetworkVO implements Network { @TableGenerator(name="networks_sq", table="sequence", pkColumnName="name", valueColumnName="value", pkColumnValue="networks_seq", allocationSize=1) @Column(name="id") long id; - + @Column(name="mode") @Enumerated(value=EnumType.STRING) Mode mode; - + @Column(name="broadcast_domain_type") @Enumerated(value=EnumType.STRING) BroadcastDomainType broadcastDomainType; - + @Column(name="traffic_type") @Enumerated(value=EnumType.STRING) TrafficType trafficType; - + @Column(name="guest_type") GuestIpType guestType; - + @Column(name="name") String name; - + @Column(name="display_text") String displayText;; - + @Column(name="broadcast_uri") URI broadcastUri; - + @Column(name="gateway") String gateway; - + @Column(name="cidr") String cidr; - + @Column(name="network_offering_id") long networkOfferingId; - + @Column(name="data_center_id") long dataCenterId; - + @Column(name="related") long related; - + @Column(name="guru_name") String guruName; - + @Column(name="state") @Enumerated(value=EnumType.STRING) State state; - + @Column(name="dns1") String dns1; - + @Column(name="domain_id") long domainId; - + @Column(name="account_id") long accountId; - + @Column(name="set_fields") long setFields; - + @TableGenerator(name="mac_address_seq", table="op_networks", pkColumnName="id", valueColumnName="mac_address_seq", allocationSize=1) @Transient long macAddress = 1; - + @Column(name="guru_data") String guruData; - + @Column(name="dns2") String dns2; - + @Column(name="shared") boolean isShared; - + @Column(name="network_domain") String networkDomain; - + @Column(name=GenericDao.REMOVED_COLUMN) Date removed; - + @Column(name=GenericDao.CREATED_COLUMN) Date created; - + @Column(name="reservation_id") String reservationId; - + @Column(name="is_default") boolean isDefault; - + @Column(name="is_security_group_enabled") boolean securityGroupEnabled; - + + @Transient + List tags; + public NetworkVO() { } - + /** * Constructor to be used for the adapters because it only initializes what's needed. * @param trafficType @@ -163,7 +169,7 @@ public class NetworkVO implements Network { this.id = -1; this.guestType = guestType; } - + public NetworkVO(long id, Network that, long offeringId, long dataCenterId, String guruName, long domainId, long accountId, long related, String name, String displayText, Boolean isShared, boolean isDefault, boolean isSecurityGroupEnabled) { this(id, that.getTrafficType(), that.getGuestType(), that.getMode(), that.getBroadcastDomainType(), offeringId, dataCenterId, domainId, accountId, related, name, displayText, isShared, isDefault); this.gateway = that.getGateway(); @@ -204,25 +210,25 @@ public class NetworkVO implements Network { this.isShared = isShared; this.isDefault = isDefault; } - + @Override public String getReservationId() { return reservationId; } - + public void setReservationId(String reservationId) { this.reservationId = reservationId; } - + @Override public State getState() { return state; } - + public void setState(State state) { this.state = state; } - + @Override public long getRelated() { return related; @@ -232,7 +238,23 @@ public class NetworkVO implements Network { public long getId() { return id; } - + + @Override + public List getTags() { + return tags != null ? tags : new ArrayList(); + } + + public void addTag(String tag) { + if (tags == null) { + tags = new ArrayList(); + } + tags.add(tag); + } + + public void setTags(List tags) { + this.tags = tags; + } + @Override public GuestIpType getGuestType() { return guestType; @@ -242,17 +264,17 @@ public class NetworkVO implements Network { public Mode getMode() { return mode; } - + @Override public long getAccountId() { return accountId; } - + @Override public long getDomainId() { return domainId; } - + @Override public long getNetworkOfferingId() { return networkOfferingId; @@ -266,19 +288,19 @@ public class NetworkVO implements Network { public BroadcastDomainType getBroadcastDomainType() { return broadcastDomainType; } - + public String getGuruData() { return guruData; } - + public void setGuruData(String guruData) { this.guruData = guruData; } - + public String getGuruName() { return guruName; } - + public void setGuruName(String guruName) { this.guruName = guruName; } @@ -286,12 +308,12 @@ public class NetworkVO implements Network { public void setBroadcastDomainType(BroadcastDomainType broadcastDomainType) { this.broadcastDomainType = broadcastDomainType; } - + @Override public String getNetworkDomain() { return networkDomain; } - + public void setNetworkDomain(String networkDomain) { this.networkDomain = networkDomain; } @@ -322,7 +344,7 @@ public class NetworkVO implements Network { public void setCidr(String cidr) { this.cidr = cidr; } - + @Override public URI getBroadcastUri() { return broadcastUri; @@ -331,33 +353,33 @@ public class NetworkVO implements Network { public void setBroadcastUri(URI broadcastUri) { this.broadcastUri = broadcastUri; } - + @Override public int hashCode() { return NumbersUtil.hash(id); } - + @Override public long getDataCenterId() { return dataCenterId; } - + public String getDns1() { return dns1; } - + public void setDns1(String dns) { this.dns1 = dns; } - + public String getDns2() { return dns2; } - + public void setDns2(String dns) { this.dns2 = dns; } - + @Override public String getName() { return name; @@ -366,7 +388,7 @@ public class NetworkVO implements Network { public void setName(String name) { this.name = name; } - + @Override public String getDisplayText() { return displayText; @@ -375,22 +397,22 @@ public class NetworkVO implements Network { public void setDisplayText(String displayText) { this.displayText = displayText; } - + @Override public boolean getIsShared() { return isShared; } - + @Override public boolean isDefault() { return isDefault; } - + @Override public boolean isSecurityGroupEnabled() { return securityGroupEnabled; } - + public void setSecurityGroupEnabled(boolean enabled) { this.securityGroupEnabled = enabled; } @@ -424,26 +446,28 @@ public class NetworkVO implements Network { if (this.trafficType != that.trafficType) { return false; } - + if ((this.cidr == null && that.cidr != null) || (this.cidr != null && that.cidr == null)) { return false; } - + if (this.cidr == null && that.cidr == null) { return true; } - + return NetUtils.isNetworkAWithinNetworkB(this.cidr, that.cidr); } - - public boolean isImplemented() { - return broadcastUri != null && cidr != null && gateway != null && mode != null && broadcastDomainType != null; - } - + @Override public String toString() { StringBuilder buf = new StringBuilder("Ntwk["); buf.append(id).append("|").append(trafficType.toString()).append("|").append(networkOfferingId).append("]"); return buf.toString(); } + + private static NetworkDao _networkDao = null; + static void init(NetworkDao networkDao) { + _networkDao = networkDao; + } + } diff --git a/server/src/com/cloud/network/dao/NetworkDaoImpl.java b/server/src/com/cloud/network/dao/NetworkDaoImpl.java index f868acf0355..35e20814756 100644 --- a/server/src/com/cloud/network/dao/NetworkDaoImpl.java +++ b/server/src/com/cloud/network/dao/NetworkDaoImpl.java @@ -51,17 +51,19 @@ public class NetworkDaoImpl extends GenericDaoBase implements N final SearchBuilder AccountNetworkSearch; final SearchBuilder ZoneBroadcastUriSearch; final SearchBuilder ZoneSecurityGroupSearch; - + NetworkAccountDaoImpl _accountsDao = ComponentLocator.inject(NetworkAccountDaoImpl.class); NetworkDomainDaoImpl _domainsDao = ComponentLocator.inject(NetworkDomainDaoImpl.class); NetworkOpDaoImpl _opDao = ComponentLocator.inject(NetworkOpDaoImpl.class); + NetworkTagDaoImpl _tagDao = ComponentLocator.inject(NetworkTagDaoImpl.class); + final TableGenerator _tgMacAddress; Random _rand = new Random(System.currentTimeMillis()); long _prefix = 0x2; - + protected NetworkDaoImpl() { super(); - + AllFieldsSearch = createSearchBuilder(); AllFieldsSearch.and("trafficType", AllFieldsSearch.entity().getTrafficType(), Op.EQ); AllFieldsSearch.and("cidr", AllFieldsSearch.entity().getCidr(), Op.EQ); @@ -73,7 +75,7 @@ public class NetworkDaoImpl extends GenericDaoBase implements N AllFieldsSearch.and("related", AllFieldsSearch.entity().getRelated(), Op.EQ); AllFieldsSearch.and("isShared", AllFieldsSearch.entity().getIsShared(), Op.EQ); AllFieldsSearch.done(); - + AccountSearch = createSearchBuilder(); AccountSearch.and("offering", AccountSearch.entity().getNetworkOfferingId(), Op.EQ); SearchBuilder join = _accountsDao.createSearchBuilder(); @@ -82,7 +84,7 @@ public class NetworkDaoImpl extends GenericDaoBase implements N AccountSearch.and("datacenter", AccountSearch.entity().getDataCenterId(), Op.EQ); AccountSearch.and("cidr", AccountSearch.entity().getCidr(), Op.EQ); AccountSearch.done(); - + RelatedConfigSearch = createSearchBuilder(); RelatedConfigSearch.and("offering", RelatedConfigSearch.entity().getNetworkOfferingId(), Op.EQ); RelatedConfigSearch.and("datacenter", RelatedConfigSearch.entity().getDataCenterId(), Op.EQ); @@ -90,29 +92,29 @@ public class NetworkDaoImpl extends GenericDaoBase implements N join2.and("account", join2.entity().getAccountId(), Op.EQ); RelatedConfigSearch.join("account", join2, join2.entity().getNetworkId(), RelatedConfigSearch.entity().getId(), JoinType.INNER); RelatedConfigSearch.done(); - + AccountNetworkSearch = createSearchBuilder(); AccountNetworkSearch.and("networkId", AccountNetworkSearch.entity().getId(), Op.EQ); SearchBuilder mapJoin = _accountsDao.createSearchBuilder(); mapJoin.and("accountId", mapJoin.entity().getAccountId(), Op.EQ); AccountNetworkSearch.join("networkSearch", mapJoin, AccountNetworkSearch.entity().getId(), mapJoin.entity().getNetworkId(), JoinBuilder.JoinType.INNER); AccountNetworkSearch.done(); - - + + ZoneBroadcastUriSearch = createSearchBuilder(); ZoneBroadcastUriSearch.and("dataCenterId", ZoneBroadcastUriSearch.entity().getDataCenterId(), Op.EQ); ZoneBroadcastUriSearch.and("broadcastUri", ZoneBroadcastUriSearch.entity().getBroadcastUri(), Op.EQ); ZoneBroadcastUriSearch.done(); - + ZoneSecurityGroupSearch = createSearchBuilder(); ZoneSecurityGroupSearch.and("dataCenterId", ZoneSecurityGroupSearch.entity().getDataCenterId(), Op.EQ); ZoneSecurityGroupSearch.and("securityGroup", ZoneSecurityGroupSearch.entity().isSecurityGroupEnabled(), Op.EQ); ZoneSecurityGroupSearch.done(); - + _tgMacAddress = _tgs.get("macAddress"); - + } - + @Override public List listBy(long accountId, long dataCenterId, GuestIpType type) { SearchCriteria sc = AllFieldsSearch.create(); @@ -123,37 +125,42 @@ public class NetworkDaoImpl extends GenericDaoBase implements N } return listBy(sc, null); } - + public List findBy(TrafficType trafficType, Mode mode, BroadcastDomainType broadcastType, long networkOfferingId, long dataCenterId) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("trafficType", trafficType); sc.setParameters("broadcastType", broadcastType); sc.setParameters("offering", networkOfferingId); sc.setParameters("datacenter", dataCenterId); - + return search(sc, null); } - + @Override public List listBy(long accountId) { SearchCriteria sc = AccountSearch.create(); sc.setParameters("account", accountId); sc.setJoinParameters("accounts", "account", accountId); - + return listBy(sc); } - - + + // @Override + // public void loadTags(NetworkVO network) { + // network.setTags(_tagDao.getTags(network.getId())); + // } + + @Override public List listBy(long accountId, long offeringId, long dataCenterId) { SearchCriteria sc = AccountSearch.create(); sc.setParameters("offering", offeringId); sc.setJoinParameters("accounts", "account", accountId); sc.setParameters("datacenter", dataCenterId); - + return listBy(sc); } - + @Override public List listBy(long accountId, long offeringId, long dataCenterId, String cidr) { SearchCriteria sc = AccountSearch.create(); @@ -161,37 +168,41 @@ public class NetworkDaoImpl extends GenericDaoBase implements N sc.setJoinParameters("accounts", "account", accountId); sc.setParameters("datacenter", dataCenterId); sc.setParameters("cidr", cidr); - + return listBy(sc); } - + @Override @DB - public NetworkVO persist(NetworkVO config, boolean gc) { + public NetworkVO persist(NetworkVO network, boolean gc) { Transaction txn = Transaction.currentTxn(); txn.start(); - config = super.persist(config); - addAccountToNetworkConfiguration(config.getId(), config.getAccountId(), true); - NetworkOpVO op = new NetworkOpVO(config.getId(), gc); + NetworkVO newNetwork = super.persist(network); + addAccountToNetwork(network.getId(), network.getAccountId(), true); + NetworkOpVO op = new NetworkOpVO(network.getId(), gc); _opDao.persist(op); + for (String tag : network.getTags()) { + _tagDao.persist(new NetworkTagVO(network.getId(), tag)); + } txn.commit(); - return config; + newNetwork.setTags(network.getTags()); + return newNetwork; } - + @Override - public void addAccountToNetwork(long configurationId, long accountId) { - addAccountToNetworkConfiguration(configurationId, accountId, false); + public void addAccountToNetwork(long networkId, long accountId) { + addAccountToNetwork(networkId, accountId, false); } - - protected void addAccountToNetworkConfiguration(long configurationId, long accountId, boolean isOwner) { - NetworkAccountVO account = new NetworkAccountVO(configurationId, accountId, isOwner); + + protected void addAccountToNetwork(long networkId, long accountId, boolean isOwner) { + NetworkAccountVO account = new NetworkAccountVO(networkId, accountId, isOwner); _accountsDao.persist(account); } - + @Override public SearchBuilder createSearchBuilderForAccount() { return _accountsDao.createSearchBuilder(); } - + @Override public List getNetworksForOffering(long offeringId, long dataCenterId, long accountId) { SearchCriteria sc = RelatedConfigSearch.create(); @@ -200,23 +211,23 @@ public class NetworkDaoImpl extends GenericDaoBase implements N sc.setJoinParameters("account", "account", accountId); return search(sc, null); } - + @Override public List getRelatedNetworks(long related) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("related", related); return search(sc, null); } - + @Override public String getNextAvailableMacAddress(long networkConfigId) { SequenceFetcher fetch = SequenceFetcher.getInstance(); - + long seq = fetch.getNextSequence(Long.class, _tgMacAddress, networkConfigId); seq = seq | _prefix << 40| ((_rand.nextInt(Short.MAX_VALUE) << 16) & 0x00000000ffff0000l); return NetUtils.long2Mac(seq); } - + @Override public List listBy(long accountId, long networkId) { SearchCriteria sc = AccountNetworkSearch.create(); @@ -224,7 +235,7 @@ public class NetworkDaoImpl extends GenericDaoBase implements N sc.setJoinParameters("networkSearch", "accountId", accountId); return listBy(sc); } - + @Override public List listBy(long zoneId, String broadcastUri) { SearchCriteria sc = ZoneBroadcastUriSearch.create(); @@ -232,67 +243,68 @@ public class NetworkDaoImpl extends GenericDaoBase implements N sc.setParameters("broadcastUri", broadcastUri); return search(sc, null); } - + @Override public List listByZone(long zoneId) { SearchCriteria sc = ZoneBroadcastUriSearch.create(); sc.setParameters("dataCenterId", zoneId); return search(sc, null); } - + @Override public List listByZoneSecurityGroup(Long zoneId) { SearchCriteria sc = ZoneSecurityGroupSearch.create(); - if (zoneId != null) + if (zoneId != null) { sc.setParameters("dataCenterId", zoneId); + } sc.setParameters("securityGroup", true); return search(sc, null); } - + @Override public void changeActiveNicsBy(long networkId, int count) { _opDao.changeActiveNicsBy(networkId, count); } - + @Override public int getActiveNicsIn(long networkId) { return _opDao.getActiveNics(networkId); } - + @Override public List findNetworksToGarbageCollect() { return _opDao.getNetworksToGarbageCollect(); } - + @Override public void clearCheckForGc(long networkId) { _opDao.clearCheckForGc(networkId); } - + @Override public List listByOwner(long ownerId) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("account", ownerId); return listBy(sc); } - + @Override - public void addDomainToNetwork(long configurationId, long domainId) { - addDomainToNetworkConfiguration(configurationId, domainId); + public void addDomainToNetwork(long networkId, long domainId) { + addDomainToNetworknetwork(networkId, domainId); } - - protected void addDomainToNetworkConfiguration(long configurationId, long domainId) { - NetworkDomainVO domain = new NetworkDomainVO(configurationId, domainId); + + protected void addDomainToNetworknetwork(long networkId, long domainId) { + NetworkDomainVO domain = new NetworkDomainVO(networkId, domainId); _domainsDao.persist(domain); } - + @Override public List listNetworksBy(boolean isShared) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("isShared", isShared); return listBy(sc); } - + @Override public List listByZoneIncludingRemoved(long zoneId) { SearchCriteria sc = ZoneBroadcastUriSearch.create(); diff --git a/server/src/com/cloud/network/dao/NetworkTagDaoImpl.java b/server/src/com/cloud/network/dao/NetworkTagDaoImpl.java new file mode 100644 index 00000000000..5d8f79bee24 --- /dev/null +++ b/server/src/com/cloud/network/dao/NetworkTagDaoImpl.java @@ -0,0 +1,62 @@ +/** + * 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 . + * + */ +package com.cloud.network.dao; + +import java.util.List; + +import com.cloud.utils.db.GenericDao; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; + + +public class NetworkTagDaoImpl extends GenericDaoBase implements GenericDao { + private final GenericSearchBuilder TagSearch; + private final SearchBuilder AllFieldsSearch; + + protected NetworkTagDaoImpl() { + super(); + TagSearch = createSearchBuilder(String.class); + TagSearch.selectField(TagSearch.entity().getTag()); + TagSearch.and("networkid", TagSearch.entity().getNetworkId(), Op.EQ); + TagSearch.done(); + + AllFieldsSearch = createSearchBuilder(); + AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), Op.EQ); + AllFieldsSearch.and("networkid", AllFieldsSearch.entity().getNetworkId(), Op.EQ); + AllFieldsSearch.and("tag", AllFieldsSearch.entity().getTag(), Op.EQ); + AllFieldsSearch.done(); + } + + public List getTags(long networkId) { + SearchCriteria sc = TagSearch.create(); + sc.setParameters("networkid", networkId); + + return customSearch(sc, null); + } + + public int clearTags(long networkId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("networkid", networkId); + + return remove(sc); + } + +} diff --git a/server/src/com/cloud/network/dao/NetworkTagVO.java b/server/src/com/cloud/network/dao/NetworkTagVO.java new file mode 100644 index 00000000000..1afd0339fe9 --- /dev/null +++ b/server/src/com/cloud/network/dao/NetworkTagVO.java @@ -0,0 +1,68 @@ +/** + * 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 . + * + */ +package com.cloud.network.dao; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +/** + * This class is just used to work with the DAO. It shouldn't be used anywhere. + * + */ +@Entity +@Table(name = "network_tags") +public class NetworkTagVO { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "network_id") + private long networkId; + + @Column(name = "tag") + private String tag; + + /** + * There should never be a public constructor for this class. Since it's + * only here to define the table for the DAO class. + */ + protected NetworkTagVO() { + } + + protected NetworkTagVO(long networkId, String tag) { + this.networkId = networkId; + this.tag = tag; + } + + public long getId() { + return id; + } + + public long getNetworkId() { + return networkId; + } + + public String getTag() { + return tag; + } +} diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 351bbd224a2..5f3e02faf45 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -112,6 +112,7 @@ DROP TABLE IF EXISTS `cloud`.`storage_pool_work`; DROP TABLE IF EXISTS `cloud`.`user_vm_details`; DROP TABLE IF EXISTS `cloud`.`vpn_users`; DROP TABLE IF EXISTS `cloud`.`data_center_details`; +DROP TABLE IF EXISTS `cloud`.`network_tags`; CREATE TABLE `cloud`.`version` ( `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id', @@ -190,6 +191,15 @@ CREATE TABLE `cloud`.`networks` ( INDEX `i_networks__removed`(`removed`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `cloud`.`network_tags` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `network_id` bigint unsigned NOT NULL COMMENT 'id of the network', + `tag` varchar(255) NOT NULL COMMENT 'tag', + PRIMARY KEY (`id`), + CONSTRAINT `fk_network_tags__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`), + UNIQUE KEY(`network_id`, `tag`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + CREATE TABLE `cloud`.`account_network_ref` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', `account_id` bigint unsigned NOT NULL COMMENT 'account id', diff --git a/setup/db/db/schema-225to226.sql b/setup/db/db/schema-225to226.sql index fe3f7a60ce4..481aa613b3b 100644 --- a/setup/db/db/schema-225to226.sql +++ b/setup/db/db/schema-225to226.sql @@ -31,6 +31,14 @@ CREATE TABLE `cloud`.`cmd_exec_log` ( CONSTRAINT `fk_cmd_exec_log_ref__inst_id` FOREIGN KEY (`instance_id`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `cloud`.`network_tags` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `network_id` bigint unsigned NOT NULL COMMENT 'id of the network', + `tag` varchar(255) NOT NULL COMMENT 'tag', + PRIMARY KEY (`id`), + CONSTRAINT `fk_network_tags__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`), + UNIQUE KEY(`network_id`, `tag`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `cloud`.`firewall_rules_cidrs` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', diff --git a/utils/src/com/cloud/utils/db/GenericDaoBase.java b/utils/src/com/cloud/utils/db/GenericDaoBase.java index 4c9f349a86b..1be42c4f5d9 100755 --- a/utils/src/com/cloud/utils/db/GenericDaoBase.java +++ b/utils/src/com/cloud/utils/db/GenericDaoBase.java @@ -49,6 +49,7 @@ import javax.persistence.EmbeddedId; import javax.persistence.EntityExistsException; import javax.persistence.EnumType; import javax.persistence.Enumerated; +import javax.persistence.OneToMany; import javax.persistence.TableGenerator; import net.sf.cglib.proxy.Callback; @@ -107,14 +108,14 @@ import com.cloud.utils.net.NetUtils; @DB public abstract class GenericDaoBase implements GenericDao { private final static Logger s_logger = Logger.getLogger(GenericDaoBase.class); - + protected final static TimeZone s_gmtTimeZone = TimeZone.getTimeZone("GMT"); - + protected final static Map, GenericDao> s_daoMaps = new HashMap, GenericDao>(71); protected Class _entityBeanType; protected String _table; - + protected String _tables; protected Field[] _embeddedFields; @@ -134,6 +135,7 @@ public abstract class GenericDaoBase implements Gene protected Map _idAttributes; protected Map _tgs; protected final Map _allAttributes; + protected List _oneToManyAttributes; protected final Map, Attribute> _allColumns; protected Enhancer _enhancer; protected Factory _factory; @@ -141,37 +143,37 @@ public abstract class GenericDaoBase implements Gene protected int _timeoutSeconds; protected final static CallbackFilter s_callbackFilter = new UpdateFilter(); - + protected static final String FOR_UPDATE_CLAUSE = " FOR UPDATE "; protected static final String SHARE_MODE_CLAUSE = " LOCK IN SHARE MODE"; protected static final String SELECT_LAST_INSERT_ID_SQL = "SELECT LAST_INSERT_ID()"; - + protected static final SequenceFetcher s_seqFetcher = SequenceFetcher.getInstance(); protected static PreparedStatement s_initStmt; static { - Connection conn = Transaction.getStandaloneConnection(); + Connection conn = Transaction.getStandaloneConnection(); try { s_initStmt = conn.prepareStatement("SELECT 1"); } catch (final SQLException e) { } finally { - try { - conn.close(); - } catch (SQLException e) { - } + try { + conn.close(); + } catch (SQLException e) { + } } } protected String _name; - + public static GenericDao getDao(Class entityType) { @SuppressWarnings("unchecked") GenericDao dao = (GenericDao)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; } - + @Override @SuppressWarnings("unchecked") public GenericSearchBuilder createSearchBuilder(Class resultType) { @@ -181,7 +183,7 @@ public abstract class GenericDaoBase implements Gene factory.setCallback(0, builder); return builder; } - + @SuppressWarnings("unchecked") protected GenericDaoBase() { Type t = getClass().getGenericSuperclass(); @@ -189,9 +191,9 @@ public abstract class GenericDaoBase implements Gene _entityBeanType = (Class)((ParameterizedType)t).getActualTypeArguments()[0]; } else { _entityBeanType = (Class)((ParameterizedType)((Class)t).getGenericSuperclass()).getActualTypeArguments()[0]; - + } - + s_daoMaps.put(_entityBeanType, this); Class[] interphaces = _entityBeanType.getInterfaces(); if (interphaces != null) { @@ -211,7 +213,7 @@ public abstract class GenericDaoBase implements Gene _idAttributes = generator.getIdAttributes(); _idField = _idAttributes.get(_table).length > 0 ? _idAttributes.get(_table)[0].field : null; - + _tables = generator.buildTableReferences(); _allAttributes = generator.getAllAttributes(); @@ -222,7 +224,8 @@ public abstract class GenericDaoBase implements Gene _deleteSqls = generator.buildDeleteSqls(); _removed = generator.getRemovedAttribute(); _tgs = generator.getTableGenerators(); - + _oneToManyAttributes = generator.getOneToManyAttributes(); + TableGenerator tg = this.getClass().getAnnotation(TableGenerator.class); if (tg != null) { _tgs.put(tg.name(), tg); @@ -231,19 +234,19 @@ public abstract class GenericDaoBase implements Gene if (tg != null) { _tgs.put(tg.name(), tg); } - + Callback[] callbacks = new Callback[] { NoOp.INSTANCE, new UpdateBuilder(_allAttributes) }; - + _enhancer = new Enhancer(); _enhancer.setSuperclass(_entityBeanType); _enhancer.setCallbackFilter(s_callbackFilter); _enhancer.setCallbacks(callbacks); _factory = (Factory)_enhancer.create(); - + _searchEnhancer = new Enhancer(); _searchEnhancer.setSuperclass(_entityBeanType); _searchEnhancer.setCallback(new UpdateBuilder(_allAttributes)); - + if (s_logger.isTraceEnabled()) { s_logger.trace("Select SQL: " + _partialSelectSql.first().toString()); s_logger.trace("Remove SQL: " + (_removeSql != null ? _removeSql.first() : "No remove sql")); @@ -315,9 +318,9 @@ public abstract class GenericDaoBase implements Gene public List searchIncludingRemoved(SearchCriteria sc, final Filter filter, final Boolean lock, final boolean cache) { String clause = sc != null ? sc.getWhereClause() : null; if (clause != null && clause.length() == 0) { - clause = null; + clause = null; } - + final StringBuilder str = createPartialSelectSql(sc, clause != null); if (clause != null) { str.append(clause); @@ -330,7 +333,7 @@ public abstract class GenericDaoBase implements Gene addJoins(str, joins); } } - + List groupByValues = addGroupBy(str, sc); addFilter(str, filter); @@ -348,15 +351,15 @@ public abstract class GenericDaoBase implements Gene pstmt = txn.prepareAutoCloseStatement(sql); int i = 0; if (clause != null) { - for (final Pair value : sc.getValues()) { - prepareAttribute(++i, pstmt, value.first(), value.second()); - } + for (final Pair value : sc.getValues()) { + prepareAttribute(++i, pstmt, value.first(), value.second()); + } } if (joins != null) { i = addJoinAttributes(i, pstmt, joins); } - + if (groupByValues != null) { for (Object value : groupByValues) { pstmt.setObject(i++, value); @@ -364,7 +367,7 @@ public abstract class GenericDaoBase implements Gene } if (s_logger.isDebugEnabled() && lock != null) { - txn.registerLock(pstmt.toString()); + txn.registerLock(pstmt.toString()); } final ResultSet rs = pstmt.executeQuery(); while (rs.next()) { @@ -377,14 +380,14 @@ public abstract class GenericDaoBase implements Gene throw new CloudRuntimeException("Caught: " + pstmt.toString(), e); } } - + @Override @SuppressWarnings("unchecked") @DB public List customSearchIncludingRemoved(SearchCriteria sc, final Filter filter) { String clause = sc != null ? sc.getWhereClause() : null; if (clause != null && clause.length() == 0) { clause = null; } - + final StringBuilder str = createPartialSelectSql(sc, clause != null); if (clause != null) { str.append(clause); @@ -397,7 +400,7 @@ public abstract class GenericDaoBase implements Gene addJoins(str, joins); } } - + List groupByValues = addGroupBy(str, sc); addFilter(str, filter); @@ -417,13 +420,13 @@ public abstract class GenericDaoBase implements Gene if (joins != null) { i = addJoinAttributes(i, pstmt, joins); } - + if (groupByValues != null) { for (Object value : groupByValues) { pstmt.setObject(i++, value); } } - + ResultSet rs = pstmt.executeQuery(); SelectType st = sc.getSelectType(); ArrayList results = new ArrayList(); @@ -449,35 +452,35 @@ public abstract class GenericDaoBase implements Gene throw new CloudRuntimeException("Caught: " + pstmt.toString(), e); } } - + @Override @DB(txn=false) public List customSearch(SearchCriteria sc, final Filter filter) { if (_removed != null) { sc.addAnd(_removed.second().field.getName(), SearchCriteria.Op.NULL); } - + return customSearchIncludingRemoved(sc, filter); } - + @DB(txn=false) protected void setField(Object entity, Field field, ResultSet rs, int index) throws SQLException { try { final Class type = field.getType(); if (type == String.class) { - byte[] bytes = rs.getBytes(index); - if(bytes != null) { - try { - field.set(entity, new String(bytes, "UTF-8")); - } catch (IllegalArgumentException e) { - assert(false); - throw new CloudRuntimeException("IllegalArgumentException when converting UTF-8 data"); - } catch (UnsupportedEncodingException e) { - assert(false); - throw new CloudRuntimeException("UnsupportedEncodingException when converting UTF-8 data"); - } - } else { - field.set(entity, null); - } + byte[] bytes = rs.getBytes(index); + if(bytes != null) { + try { + field.set(entity, new String(bytes, "UTF-8")); + } catch (IllegalArgumentException e) { + assert(false); + throw new CloudRuntimeException("IllegalArgumentException when converting UTF-8 data"); + } catch (UnsupportedEncodingException e) { + assert(false); + throw new CloudRuntimeException("UnsupportedEncodingException when converting UTF-8 data"); + } + } else { + field.set(entity, null); + } } else if (type == long.class) { field.setLong(entity, rs.getLong(index)); } else if (type == Long.class) { @@ -493,7 +496,7 @@ public abstract class GenericDaoBase implements Gene final Enum[] enums = (Enum[])field.getType().getEnumConstants(); for (final Enum e : enums) { if ((enumType == EnumType.STRING && e.name().equalsIgnoreCase(rs.getString(index))) || - (enumType == EnumType.ORDINAL && e.ordinal() == rs.getInt(index))) { + (enumType == EnumType.ORDINAL && e.ordinal() == rs.getInt(index))) { field.set(entity, e); return; } @@ -597,20 +600,20 @@ public abstract class GenericDaoBase implements Gene throw new CloudRuntimeException("Yikes! ", e); } } - + @DB(txn=false) @SuppressWarnings("unchecked") protected M getObject(Class type, ResultSet rs, int index) throws SQLException { if (type == String.class) { - byte[] bytes = rs.getBytes(index); - if(bytes != null) { - try { - return (M)new String(bytes, "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new CloudRuntimeException("UnsupportedEncodingException exception while converting UTF-8 data"); - } - } else { - return null; - } + byte[] bytes = rs.getBytes(index); + if(bytes != null) { + try { + return (M)new String(bytes, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new CloudRuntimeException("UnsupportedEncodingException exception while converting UTF-8 data"); + } + } else { + return null; + } } else if (type == int.class) { return (M)new Integer(rs.getInt(index)); } else if (type == Integer.class) { @@ -712,13 +715,13 @@ public abstract class GenericDaoBase implements Gene @DB(txn=false) protected int update(final ID id, final UpdateBuilder ub) { - SearchCriteria sc = createSearchCriteria(); - sc.addAnd(_idAttributes.get(_table)[0], SearchCriteria.Op.EQ, id); - int rowsUpdated = update(ub, sc, null); - if (_cache != null) { + SearchCriteria sc = createSearchCriteria(); + sc.addAnd(_idAttributes.get(_table)[0], SearchCriteria.Op.EQ, id); + int rowsUpdated = update(ub, sc, null); + if (_cache != null) { _cache.remove(id); - } - return rowsUpdated; + } + return rowsUpdated; } // @Override @@ -727,33 +730,33 @@ public abstract class GenericDaoBase implements Gene PreparedStatement pstmt = s_initStmt; final Transaction txn = Transaction.currentTxn(); try { - final String searchClause = sc.getWhereClause(); - + final String searchClause = sc.getWhereClause(); + sql = ub.toSql(_tables); if (sql == null) { - return 0; + return 0; } - + sql.append(searchClause); - + if (rows != null) { - sql.append(" LIMIT ").append(rows); + sql.append(" LIMIT ").append(rows); } - + txn.start(); pstmt = txn.prepareAutoCloseStatement(sql.toString()); - + Collection> changes = ub.getChanges(); - + int i = 1; for (final Ternary value : changes) { prepareAttribute(i++, pstmt, value.first(), value.third()); } - + for (Pair value : sc.getValues()) { - prepareAttribute(i++, pstmt, value.first(), value.second()); + prepareAttribute(i++, pstmt, value.first(), value.second()); } - + int result = pstmt.executeUpdate(); txn.commit(); ub.clear(); @@ -766,10 +769,10 @@ public abstract class GenericDaoBase implements Gene throw new CloudRuntimeException("DB Exception on: " + sqlStr, e); } } - + @DB(txn=false) protected Attribute findAttributeByFieldName(String name) { - return _allAttributes.get(name); + return _allAttributes.get(name); } @DB(txn=false) @@ -846,29 +849,29 @@ public abstract class GenericDaoBase implements Gene return lockRow(id, null); } } - + @Override @DB(txn=false) public T findByIdIncludingRemoved(ID id) { return findById(id, true, null); } - + @Override @DB(txn=false) public T findById(final ID id, boolean fresh) { - if(!fresh) { + if(!fresh) { return findById(id); } - + if (_cache != null) { - _cache.remove(id); + _cache.remove(id); } return lockRow(id, null); } - + @Override public T lockRow(ID id, Boolean lock) { return findById(id, false, lock); } - + protected T findById(ID id, boolean removed, Boolean lock) { StringBuilder sql = new StringBuilder(_selectByIdSql); if (!removed && _removed != null) { @@ -883,9 +886,9 @@ public abstract class GenericDaoBase implements Gene pstmt = txn.prepareAutoCloseStatement(sql.toString()); if (_idField.getAnnotation(EmbeddedId.class) == null) { - prepareAttribute(1, pstmt, _idAttributes.get(_table)[0], id); + prepareAttribute(1, pstmt, _idAttributes.get(_table)[0], id); } - + ResultSet rs = pstmt.executeQuery(); return rs.next() ? toEntityBean(rs, true) : null; } catch (SQLException e) { @@ -895,9 +898,9 @@ public abstract class GenericDaoBase implements Gene @Override @DB(txn=false) public T acquireInLockTable(ID id) { - return acquireInLockTable(id, _timeoutSeconds); + return acquireInLockTable(id, _timeoutSeconds); } - + @Override public T acquireInLockTable(final ID id, int seconds) { Transaction txn = Transaction.currentTxn(); @@ -905,35 +908,35 @@ public abstract class GenericDaoBase implements Gene boolean locked = false; try { if (!txn.lock(_table + id.toString(), seconds)) { - return null; + return null; } - + locked = true; t = findById(id); return t; } finally { - if (t == null && locked) { - txn.release(_table + id.toString()); - } + if (t == null && locked) { + txn.release(_table + id.toString()); + } } } @Override public boolean releaseFromLockTable(final ID id) { final Transaction txn = Transaction.currentTxn(); - return txn.release(_table + id); + return txn.release(_table + id); } - + @Override @DB(txn=false) public boolean lockInLockTable(final String id) { return lockInLockTable(id, _timeoutSeconds); } - + @Override public boolean lockInLockTable(final String id, int seconds) { Transaction txn = Transaction.currentTxn(); return txn.lock(_table + id, seconds); - } + } @Override public boolean unlockFromLockTable(final String id) { @@ -948,15 +951,15 @@ public abstract class GenericDaoBase implements Gene @DB(txn=false) protected List addGroupBy(final StringBuilder sql, SearchCriteria sc) { - Pair, List> groupBys = sc.getGroupBy(); - if (groupBys != null) { - groupBys.first().toSql(sql); - return groupBys.second(); - } else { - return null; - } + Pair, List> groupBys = sc.getGroupBy(); + if (groupBys != null) { + groupBys.first().toSql(sql); + return groupBys.second(); + } else { + return null; + } } - + @DB(txn=false) protected void addFilter(final StringBuilder sql, final Filter filter) { if (filter != null) { @@ -1071,7 +1074,7 @@ public abstract class GenericDaoBase implements Gene pstmt = txn.prepareAutoCloseStatement(sql); int i = 0; for (final Pair value : sc.getValues()) { - prepareAttribute(++i, pstmt, value.first(), value.second()); + prepareAttribute(++i, pstmt, value.first(), value.second()); } return pstmt.executeUpdate(); } catch (final SQLException e) { @@ -1088,14 +1091,14 @@ public abstract class GenericDaoBase implements Gene sql.delete(7, sql.indexOf(" FROM")); sc.getSelect(sql, 7); } - + if (!whereClause) { sql.delete(sql.length() - (_discriminatorClause == null ? 6 : 4), sql.length()); } return sql; } - + @DB(txn = false) protected void addJoins(StringBuilder str, Collection>> joins) { @@ -1110,9 +1113,9 @@ public abstract class GenericDaoBase implements Gene for (JoinBuilder> join : joins) { StringBuilder onClause = new StringBuilder(); onClause.append(" ").append(join.getType().getName()).append(" ").append(join.getSecondAttribute().table) - .append(" ON ").append(join.getFirstAttribute().table).append(".").append(join.getFirstAttribute().columnName) - .append("=").append(join.getSecondAttribute().table).append(".").append(join.getSecondAttribute().columnName) - .append(" "); + .append(" ON ").append(join.getFirstAttribute().table).append(".").append(join.getFirstAttribute().columnName) + .append("=").append(join.getSecondAttribute().table).append(".").append(join.getSecondAttribute().columnName) + .append(" "); str.insert(fromIndex, onClause); String whereClause = join.getT().getWhereClause(); if ((whereClause != null) && !"".equals(whereClause)) { @@ -1149,7 +1152,7 @@ public abstract class GenericDaoBase implements Gene final UpdateBuilder ub = getUpdateBuilder(entity); return update(ub, sc, rows); } - + @DB(txn=false) public int update(final T entity, final SearchCriteria sc) { final UpdateBuilder ub = getUpdateBuilder(entity); @@ -1170,7 +1173,7 @@ public abstract class GenericDaoBase implements Gene update(id, entity); return entity; } - + assert false : "Can't call persit if you don't have primary key"; } @@ -1218,7 +1221,7 @@ public abstract class GenericDaoBase implements Gene throw new CloudRuntimeException("DB Exception on: " + sqlStr, e); } } - + return _idField != null ? findByIdIncludingRemoved(id) : null; } @@ -1267,21 +1270,21 @@ public abstract class GenericDaoBase implements Gene // to support generic localization, utilize MySql UTF-8 support if (length < str.length()) { - try { - pstmt.setBytes(j, str.substring(0, column.length()).getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - // no-way it can't support UTF-8 encoding - assert(false); - throw new CloudRuntimeException("UnsupportedEncodingException when saving string as UTF-8 data"); - } + try { + pstmt.setBytes(j, str.substring(0, column.length()).getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + // no-way it can't support UTF-8 encoding + assert(false); + throw new CloudRuntimeException("UnsupportedEncodingException when saving string as UTF-8 data"); + } } else { - try { - pstmt.setBytes(j, str.getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - // no-way it can't support UTF-8 encoding - assert(false); - throw new CloudRuntimeException("UnsupportedEncodingException when saving string as UTF-8 data"); - } + try { + pstmt.setBytes(j, str.getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + // no-way it can't support UTF-8 encoding + assert(false); + throw new CloudRuntimeException("UnsupportedEncodingException when saving string as UTF-8 data"); + } } } else if (attr.field.getType() == Date.class) { final Date date = (Date)value; @@ -1376,6 +1379,10 @@ public abstract class GenericDaoBase implements Gene for (int index = 1, max = meta.getColumnCount(); index <= max; index++) { setField(entity, result, meta, index); } + for (Attribute attr : _oneToManyAttributes) { + OneToMany otm = attr.field.getAnnotation(OneToMany.class); + + } } @Override @@ -1398,7 +1405,7 @@ public abstract class GenericDaoBase implements Gene throw new CloudRuntimeException("DB Exception on " + sqlStr, e); } } - + @DB(txn=false) protected void setField(final Object entity, final ResultSet rs, ResultSetMetaData meta, final int index) throws SQLException { Attribute attr = _allColumns.get(new Pair(meta.getTableName(index), meta.getColumnName(index))); @@ -1441,14 +1448,14 @@ public abstract class GenericDaoBase implements Gene if (_removeSql == null) { return expunge(sc); } - + T vo = createForUpdate(); UpdateBuilder ub = getUpdateBuilder(vo); - + ub.set(vo, _removed.second(), new Date()); return update(ub, sc, null); } - + protected Cache _cache; @DB(txn=false) protected void createCache(final Map params) { @@ -1487,14 +1494,14 @@ public abstract class GenericDaoBase implements Gene public String getName() { return _name; } - + @DB(txn=false) public static UpdateBuilder getUpdateBuilder(final T entityObject) { final Factory factory = (Factory)entityObject; assert(factory != null); return (UpdateBuilder)factory.getCallback(1); } - + @SuppressWarnings("unchecked") @Override @DB(txn=false) public SearchBuilder createSearchBuilder() { @@ -1504,11 +1511,11 @@ public abstract class GenericDaoBase implements Gene factory.setCallback(0, builder); return builder; } - + @Override @DB(txn=false) public SearchCriteria createSearchCriteria() { - SearchBuilder builder = createSearchBuilder(); - return builder.create(); + SearchBuilder builder = createSearchBuilder(); + return builder.create(); } - + } diff --git a/utils/src/com/cloud/utils/db/SqlGenerator.java b/utils/src/com/cloud/utils/db/SqlGenerator.java index d504ef37901..9928dc1caec 100755 --- a/utils/src/com/cloud/utils/db/SqlGenerator.java +++ b/utils/src/com/cloud/utils/db/SqlGenerator.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Map; import javax.persistence.AttributeOverride; +import javax.persistence.CascadeType; import javax.persistence.DiscriminatorColumn; import javax.persistence.DiscriminatorType; import javax.persistence.DiscriminatorValue; @@ -36,6 +37,8 @@ import javax.persistence.Embeddable; import javax.persistence.Embedded; import javax.persistence.EmbeddedId; import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.OneToMany; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.SecondaryTable; import javax.persistence.TableGenerator; @@ -45,30 +48,32 @@ import com.cloud.utils.Ternary; import com.cloud.utils.db.Attribute.Flag; public class SqlGenerator { - Class _clazz; + Class _clazz; ArrayList _attributes; ArrayList _embeddeds; ArrayList> _tables; LinkedHashMap> _ids; HashMap _generators; - + ArrayList _otmAttrs; + public SqlGenerator(Class clazz) { - _clazz = clazz; + _clazz = clazz; _tables = new ArrayList>(); _attributes = new ArrayList(); + _otmAttrs = new ArrayList(); _embeddeds = new ArrayList(); _ids = new LinkedHashMap>(); _generators = new HashMap(); - + buildAttributes(clazz, DbUtil.getTableName(clazz), DbUtil.getAttributeOverrides(clazz), false, false); assert (_tables.size() > 0) : "Did you forget to put @Entity on " + clazz.getName(); handleDaoAttributes(clazz); } - + protected boolean checkMethods(Class clazz, Map attrs) { - Method[] methods = clazz.getMethods(); - for (Method method : methods) { - String name = method.getName(); + Method[] methods = clazz.getMethods(); + for (Method method : methods) { + String name = method.getName(); if (name.startsWith("get")) { String fieldName = Character.toLowerCase(name.charAt(3)) + name.substring(4); assert !attrs.containsKey(fieldName) : "Mismatch in " + clazz.getSimpleName() + " for " + name; @@ -79,39 +84,39 @@ public class SqlGenerator { String fieldName = Character.toLowerCase(name.charAt(3)) + name.substring(4); assert !attrs.containsKey(fieldName) : "Mismatch in " + clazz.getSimpleName() + " for " + name; } - } - return true; - + } + return true; + } - + protected void buildAttributes(Class clazz, String tableName, AttributeOverride[] overrides, boolean embedded, boolean isId) { if (!embedded && clazz.getAnnotation(Entity.class) == null) { return; } - + Class parent = clazz.getSuperclass(); if (parent != null) { buildAttributes(parent, DbUtil.getTableName(parent), DbUtil.getAttributeOverrides(parent), false, false); } - + if (!embedded) { _tables.add(clazz); _ids.put(tableName, new ArrayList()); } - + Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); - + TableGenerator tg = field.getAnnotation(TableGenerator.class); if (tg != null) { _generators.put(field.getName(), tg); } - + if (!DbUtil.isPersistable(field)) { continue; } - + if (field.getAnnotation(Embedded.class) != null) { _embeddeds.add(field); Class embeddedClass = field.getType(); @@ -119,7 +124,7 @@ public class SqlGenerator { buildAttributes(embeddedClass, tableName, DbUtil.getAttributeOverrides(field), true, false); continue; } - + if (field.getAnnotation(EmbeddedId.class) != null) { _embeddeds.add(field); Class embeddedClass = field.getType(); @@ -127,22 +132,44 @@ public class SqlGenerator { buildAttributes(embeddedClass, tableName, DbUtil.getAttributeOverrides(field), true, true); continue; } - + Attribute attr = new Attribute(clazz, overrides, field, tableName, embedded, isId); - + if (attr.isId()) { List attrs = _ids.get(tableName); attrs.add(attr); } - - _attributes.add(attr); + + if (field.getAnnotation(OneToMany.class) != null) { + assert supportsOneToMany(field) : "Doesn't support One To Many"; + _otmAttrs.add(attr); + } else { + _attributes.add(attr); + } } } - + + protected boolean supportsOneToMany(Field field) { + OneToMany otm = field.getAnnotation(OneToMany.class); + if (otm.fetch() == FetchType.LAZY) { + assert (false) : "Doesn't support laz fetch: " + field.getName(); + return false; + } + + for (CascadeType cascade : otm.cascade()) { + if (cascade == CascadeType.ALL || cascade == CascadeType.PERSIST || cascade == CascadeType.MERGE || cascade == CascadeType.REMOVE) { + assert (false) : "Doesn't support " + cascade + " for " + field.getName(); + return false; + } + } + + return true; + } + public Map getTableGenerators() { return _generators; } - + protected void handleDaoAttributes(Class clazz) { Attribute attr; Class current = clazz; @@ -173,7 +200,7 @@ public class SqlGenerator { attr.setTrue(Attribute.Flag.IntegerDT); } } - + PrimaryKeyJoinColumn[] pkjcs = DbUtil.getPrimaryKeyJoinColumns(current); if (pkjcs != null) { for (PrimaryKeyJoinColumn pkjc : pkjcs) { @@ -199,7 +226,7 @@ public class SqlGenerator { } current = current.getSuperclass(); } - + attr = findAttribute(GenericDao.CREATED_COLUMN); if (attr != null && attr.field.getType() == Date.class) { attr.setTrue(Attribute.Flag.DaoGenerated); @@ -211,7 +238,7 @@ public class SqlGenerator { attr.setFalse(Attribute.Flag.Nullable); attr.setTrue(Attribute.Flag.Created); } - + attr = findAttribute(GenericDao.REMOVED_COLUMN); if (attr != null && attr.field.getType() == Date.class) { attr.setTrue(Attribute.Flag.DaoGenerated); @@ -223,7 +250,7 @@ public class SqlGenerator { attr.setTrue(Attribute.Flag.Nullable); attr.setTrue(Attribute.Flag.Removed); } - + attr = findAttribute(GenericDao.XID_COLUMN); if (attr != null && attr.field.getType() == String.class) { attr.setTrue(Attribute.Flag.DaoGenerated); @@ -236,17 +263,21 @@ public class SqlGenerator { attr.setFalse(Attribute.Flag.Removed); } } - + + public List getOneToManyAttributes() { + return _otmAttrs; + } + public Attribute findAttribute(String name) { for (Attribute attr : _attributes) { if (attr.columnName == name || attr.columnName.equals(name)) { return attr; } } - + return null; } - + public static StringBuilder buildUpdateSql(String tableName, List attrs) { StringBuilder sql = new StringBuilder("UPDATE "); sql.append(tableName).append(" SET "); @@ -255,10 +286,10 @@ public class SqlGenerator { } sql.delete(sql.length() - 2, sql.length()); sql.append(" WHERE "); - + return sql; } - + public List> buildUpdateSqls() { ArrayList> sqls = new ArrayList>(_tables.size()); for (Class table : _tables) { @@ -272,45 +303,45 @@ public class SqlGenerator { if (attrs.size() != 0) { Pair pair = new Pair(buildUpdateSql(tableName, attrs), attrs.toArray(new Attribute[attrs.size()])); - sqls.add(pair); + sqls.add(pair); } } return sqls; } - + public static StringBuilder buildMysqlUpdateSql(String joins, Collection> setters) { - if (setters.size() == 0) { - return null; - } - + if (setters.size() == 0) { + return null; + } + StringBuilder sql = new StringBuilder("UPDATE "); - + sql.append(joins); - - sql.append(" SET "); - + + sql.append(" SET "); + for (Ternary setter : setters) { - Attribute attr = setter.first(); + Attribute attr = setter.first(); sql.append(attr.table).append(".").append(attr.columnName).append("="); if (setter.second() != null) { - sql.append(attr.table).append(".").append(attr.columnName).append(setter.second() ? "+" : "-"); + sql.append(attr.table).append(".").append(attr.columnName).append(setter.second() ? "+" : "-"); } sql.append("?, "); } sql.delete(sql.length() - 2, sql.length()); - + sql.append(" WHERE "); - + return sql; } - + public List> buildInsertSqls() { LinkedHashMap> map = new LinkedHashMap>(); for (Class table : _tables) { map.put(DbUtil.getTableName(table), new ArrayList()); } - + for (Attribute attr : _attributes) { if (attr.isInsertable()) { ArrayList attrs = map.get(attr.table); @@ -318,7 +349,7 @@ public class SqlGenerator { attrs.add(attr); } } - + List> sqls = new ArrayList>(map.size()); for (Map.Entry> entry : map.entrySet()) { ArrayList attrs = entry.getValue(); @@ -326,10 +357,10 @@ public class SqlGenerator { Pair pair = new Pair(sql.toString(), attrs.toArray(new Attribute[attrs.size()])); sqls.add(pair); } - + return sqls; } - + protected StringBuilder buildInsertSql(String table, ArrayList attrs) { StringBuilder sql = new StringBuilder("INSERT INTO "); sql.append(table).append(" ("); @@ -339,27 +370,27 @@ public class SqlGenerator { if (attrs.size() > 0) { sql.delete(sql.length() - 2, sql.length()); } - + sql.append(") VALUES ("); for (Attribute attr : attrs) { sql.append("?, "); } - + if (attrs.size() > 0) { sql.delete(sql.length() - 2, sql.length()); } - + sql.append(")"); - + return sql; } - + protected List> buildDeleteSqls() { LinkedHashMap> map = new LinkedHashMap>(); for (Class table : _tables) { map.put(DbUtil.getTableName(table), new ArrayList()); } - + for (Attribute attr : _attributes) { if (attr.isId()) { ArrayList attrs = map.get(attr.table); @@ -367,7 +398,7 @@ public class SqlGenerator { attrs.add(attr); } } - + List> sqls = new ArrayList>(map.size()); for (Map.Entry> entry : map.entrySet()) { ArrayList attrs = entry.getValue(); @@ -375,11 +406,11 @@ public class SqlGenerator { Pair pair = new Pair(sql, attrs.toArray(new Attribute[attrs.size()])); sqls.add(pair); } - + Collections.reverse(sqls); return sqls; } - + protected String buildDeleteSql(String table, ArrayList attrs) { StringBuilder sql = new StringBuilder("DELETE FROM "); sql.append(table).append(" WHERE "); @@ -389,50 +420,50 @@ public class SqlGenerator { sql.delete(sql.length() - 5, sql.length()); return sql.toString(); } - + public Pair buildRemoveSql() { Attribute attribute = findAttribute(GenericDao.REMOVED_COLUMN); if (attribute == null) { return null; } - + StringBuilder sql = new StringBuilder("UPDATE "); sql.append(attribute.table).append(" SET "); sql.append(attribute.columnName).append(" = ? WHERE "); - + List ids = _ids.get(attribute.table); - + // if ids == null, that means the removed column was added as a JOIN // value to another table. We ignore it here. if (ids == null) { - return null; + return null; } if (ids.size() == 0) { return null; } - + for (Attribute id : ids) { sql.append(id.table).append(".").append(id.columnName).append(" = ? AND "); } - + sql.delete(sql.length() - 5, sql.length()); - + Attribute[] attrs = ids.toArray(new Attribute[ids.size() + 1]); attrs[attrs.length - 1] = attribute; - + return new Pair(sql.toString(), attrs); } - + public Map getIdAttributes() { LinkedHashMap ids = new LinkedHashMap(_ids.size()); - + for (Map.Entry> entry : _ids.entrySet()) { ids.put(entry.getKey(), entry.getValue().toArray(new Attribute[entry.getValue().size()])); } - + return ids; } - + /** * @return a map of tables and maps of field names to attributes. */ @@ -443,10 +474,10 @@ public class SqlGenerator { attrs.put(attr.field.getName(), attr); } } - + return attrs; } - + public Map, Attribute> getAllColumns() { Map, Attribute> attrs = new LinkedHashMap, Attribute>(_attributes.size()); for (Attribute attr : _attributes) { @@ -454,10 +485,10 @@ public class SqlGenerator { attrs.put(new Pair(attr.table, attr.columnName), attr); } } - + return attrs; } - + protected static void addPrimaryKeyJoinColumns(StringBuilder sql, String fromTable, String toTable, String joinType, PrimaryKeyJoinColumn[] pkjcs) { if ("right".equalsIgnoreCase(joinType)) { sql.append(" RIGHT JOIN ").append(toTable).append(" ON "); @@ -472,33 +503,33 @@ public class SqlGenerator { sql.append("=").append(toTable).append(".").append(refColumn).append(" "); } } - + public Pair getRemovedAttribute() { Attribute removed = findAttribute(GenericDao.REMOVED_COLUMN); if (removed == null) { return null; } - + if (removed.field.getType() != Date.class) { return null; } - + StringBuilder sql = new StringBuilder(); sql.append(removed.table).append(".").append(removed.columnName).append(" IS NULL "); - + return new Pair(sql.toString(), removed); } - + protected static void buildJoins(StringBuilder innerJoin, Class clazz) { String tableName = DbUtil.getTableName(clazz); - + SecondaryTable[] sts = DbUtil.getSecondaryTables(clazz); ArrayList secondaryTables = new ArrayList(); for (SecondaryTable st : sts) { addPrimaryKeyJoinColumns(innerJoin, tableName, st.name(), st.join(), st.pkJoinColumns()); secondaryTables.add(st.name()); } - + Class parent = clazz.getSuperclass(); if (parent.getAnnotation(Entity.class) != null) { String table = DbUtil.getTableName(parent); @@ -508,63 +539,63 @@ public class SqlGenerator { } } - + public String buildTableReferences() { - StringBuilder sql = new StringBuilder(); + StringBuilder sql = new StringBuilder(); sql.append(DbUtil.getTableName(_tables.get(_tables.size() - 1))); - + for (Class table : _tables) { buildJoins(sql, table); } - + return sql.toString(); } - + public Pair buildSelectSql() { StringBuilder sql = new StringBuilder("SELECT "); - + ArrayList attrs = new ArrayList(); - + for (Attribute attr : _attributes) { if (attr.isSelectable()) { attrs.add(attr); sql.append(attr.table).append(".").append(attr.columnName).append(", "); } } - + if (attrs.size() > 0) { sql.delete(sql.length() - 2, sql.length()); } - + sql.append(" FROM ").append(buildTableReferences()); - + sql.append(" WHERE "); - + sql.append(buildDiscriminatorClause().first()); - + return new Pair(sql, attrs.toArray(new Attribute[attrs.size()])); } - + public Pair buildSelectSql(Attribute[] attrs) { StringBuilder sql = new StringBuilder("SELECT "); - + for (Attribute attr : attrs) { sql.append(attr.table).append(".").append(attr.columnName).append(", "); } - + if (attrs.length > 0) { sql.delete(sql.length() - 2, sql.length()); } - + sql.append(" FROM ").append(buildTableReferences()); - + sql.append(" WHERE "); - + sql.append(buildDiscriminatorClause().first()); - + return new Pair(sql, attrs); } - + /** * buildDiscriminatorClause builds the join clause when there are multiple tables. * @@ -573,7 +604,7 @@ public class SqlGenerator { public Pair> buildDiscriminatorClause() { StringBuilder sql = new StringBuilder(); Map values = new HashMap(); - + for (Class table : _tables) { DiscriminatorValue dv = table.getAnnotation(DiscriminatorValue.class); if (dv != null) { @@ -601,10 +632,10 @@ public class SqlGenerator { sql.append(" AND "); } } - + return new Pair>(sql, values); } - + public Field[] getEmbeddedFields() { return _embeddeds.toArray(new Field[_embeddeds.size()]); } diff --git a/utils/src/javax/persistence/ElementCollection.java b/utils/src/javax/persistence/ElementCollection.java new file mode 100644 index 00000000000..aaaa96edf25 --- /dev/null +++ b/utils/src/javax/persistence/ElementCollection.java @@ -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 . + * + */ +package javax.persistence; + +public interface ElementCollection { + +}