tags added

This commit is contained in:
Alex Huang 2011-05-25 16:58:12 -07:00
parent 6de2bef7cd
commit 67ff27496d
6 changed files with 205 additions and 77 deletions

View File

@ -22,11 +22,15 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
import javax.persistence.TableGenerator;
import javax.persistence.Transient;
@ -34,7 +38,6 @@ 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;
@ -73,7 +76,7 @@ public class NetworkVO implements Network {
String displayText;;
@Column(name="broadcast_uri")
URI broadcastUri;
URI broadcastUri;
@Column(name="gateway")
String gateway;
@ -132,7 +135,7 @@ public class NetworkVO implements Network {
Date created;
@Column(name="reservation_id")
String reservationId;
String reservationId;
@Column(name="is_default")
boolean isDefault;
@ -140,7 +143,9 @@ public class NetworkVO implements Network {
@Column(name="is_security_group_enabled")
boolean securityGroupEnabled;
@Transient
@ElementCollection(targetClass = String.class, fetch=FetchType.EAGER)
@Column(name="tag")
@CollectionTable(name="network_tags", joinColumns=@JoinColumn(name="network_id"))
List<String> tags;
public NetworkVO() {
@ -408,7 +413,7 @@ public class NetworkVO implements Network {
return isDefault;
}
@Override
@Override
public boolean isSecurityGroupEnabled() {
return securityGroupEnabled;
}
@ -464,10 +469,4 @@ public class NetworkVO implements Network {
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;
}
}

View File

@ -197,7 +197,7 @@ CREATE TABLE `cloud`.`network_tags` (
`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`),
CONSTRAINT `fk_network_tags__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`) ON DELETE CASCADE,
UNIQUE KEY(`network_id`, `tag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -21,6 +21,7 @@ import java.lang.reflect.Field;
import javax.persistence.AttributeOverride;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@ -54,49 +55,50 @@ public class Attribute {
CharDT(0x100000),
StringDT(0x200000),
IntegerDT(0x400000);
int place;
Flag(int place) {
this.place = place;
}
public int place() {
return place;
}
public boolean check(int value) {
return (value & place) == place;
}
public int setTrue(int value) {
return (value | place);
}
public int setFalse(int value) {
return (value & ~place);
}
}
protected String table;
protected String columnName;
protected Field field;
protected int flags;
protected Column column;
protected Object attache;
public Attribute(Class<?> clazz, AttributeOverride[] overrides, Field field, String tableName, boolean isEmbedded, boolean isId) {
this.field = field;
flags = 0;
table = tableName;
setupColumnInfo(clazz, overrides, tableName, isEmbedded, isId);
}
public Attribute(String table, String columnName) {
this.table = table;
this.columnName = columnName;
this.field = null;
this.column = null;
}
protected void setupColumnInfo(Class<?> clazz, AttributeOverride[] overrides, String tableName, boolean isEmbedded, boolean isId) {
flags = Flag.Selectable.setTrue(flags);
GeneratedValue gv = field.getAnnotation(GeneratedValue.class);
@ -122,7 +124,7 @@ public class Attribute {
if (isEmbedded) {
flags = Flag.Embedded.setTrue(flags);
}
if (isId) {
flags = Flag.Id.setTrue(flags);
} else {
@ -143,6 +145,12 @@ public class Attribute {
flags = Flag.Nullable.setTrue(flags);
}
}
ElementCollection ec = field.getAnnotation(ElementCollection.class);
if (ec != null) {
flags = Flag.Insertable.setFalse(flags);
flags = Flag.Selectable.setFalse(flags);
}
Temporal temporal = field.getAnnotation(Temporal.class);
if (temporal != null) {
if (temporal.value() == TemporalType.DATE) {
@ -153,50 +161,50 @@ public class Attribute {
flags = Flag.TimeStamp.setTrue(flags);
}
}
if (column != null && column.table().length() > 0) {
table = column.table();
}
columnName = DbUtil.getColumnName(field, overrides);
}
public final boolean isInsertable() {
return Flag.Insertable.check(flags);
}
public final boolean isUpdatable() {
return Flag.Updatable.check(flags);
}
public final boolean isNullable() {
return Flag.Nullable.check(flags);
}
public final boolean isId() {
return Flag.Id.check(flags);
}
public final boolean isSelectable() {
return Flag.Selectable.check(flags);
}
public final boolean is(Flag flag) {
return flag.check(flags);
}
public final void setTrue(Flag flag) {
flags = flag.setTrue(flags);
}
public final void setFalse(Flag flag) {
flags = flag.setFalse(flags);
}
public Field getField() {
return field;
}
public Object get(Object entity) {
try {
return field.get(entity);
@ -205,23 +213,23 @@ public class Attribute {
return null;
}
}
@Override
public int hashCode() {
return columnName.hashCode();
return columnName.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Attribute)) {
return false;
}
Attribute that = (Attribute)obj;
return columnName.equals(that.columnName) && table.equals(that.table);
if (!(obj instanceof Attribute)) {
return false;
}
Attribute that = (Attribute)obj;
return columnName.equals(that.columnName) && table.equals(that.table);
}
@Override
public String toString() {
return table + "." + columnName;

View File

@ -19,6 +19,7 @@ package com.cloud.utils.db;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
@ -36,6 +37,7 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -49,7 +51,6 @@ 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;
@ -72,6 +73,8 @@ import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.Ip;
import com.cloud.utils.net.NetUtils;
import edu.emory.mathcs.backport.java.util.Collections;
/**
* GenericDaoBase is a simple way to implement DAOs. It DOES NOT
* support the full EJB3 spec. It borrows some of the annotations from
@ -135,7 +138,7 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
protected Map<String, Attribute[]> _idAttributes;
protected Map<String, TableGenerator> _tgs;
protected final Map<String, Attribute> _allAttributes;
protected List<Attribute> _oneToManyAttributes;
protected List<Attribute> _ecAttributes;
protected final Map<Pair<String, String>, Attribute> _allColumns;
protected Enhancer _enhancer;
protected Factory _factory;
@ -224,7 +227,7 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
_deleteSqls = generator.buildDeleteSqls();
_removed = generator.getRemovedAttribute();
_tgs = generator.getTableGenerators();
_oneToManyAttributes = generator.getOneToManyAttributes();
_ecAttributes = generator.getElementCollectionAttributes();
TableGenerator tg = this.getClass().getAnnotation(TableGenerator.class);
if (tg != null) {
@ -261,6 +264,13 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
for (final Pair<String, Attribute[]> deletSql : _deleteSqls) {
s_logger.trace(deletSql.first());
}
s_logger.trace("Collection SQLs");
for (Attribute attr : _ecAttributes) {
EcInfo info = (EcInfo)attr.attache;
s_logger.trace(info.insertSql);
s_logger.trace(info.selectSql);
}
}
}
@ -610,7 +620,7 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
return (M)new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new CloudRuntimeException("UnsupportedEncodingException exception while converting UTF-8 data");
}
}
} else {
return null;
}
@ -767,7 +777,7 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
}
final String sqlStr = pstmt.toString();
throw new CloudRuntimeException("DB Exception on: " + sqlStr, e);
}
}
}
@DB(txn=false)
@ -892,8 +902,8 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
ResultSet rs = pstmt.executeQuery();
return rs.next() ? toEntityBean(rs, true) : null;
} catch (SQLException e) {
throw new CloudRuntimeException("DB Exception on: " + pstmt.toString(), e);
}
throw new CloudRuntimeException("DB Exception on: " + pstmt, e);
}
}
@Override @DB(txn=false)
@ -1212,6 +1222,30 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
}
}
}
for (Attribute attr : _ecAttributes) {
EcInfo ec = (EcInfo)attr.attache;
Object obj;
try {
obj = attr.field.get(entity);
if (ec.rawClass != null) {
Enumeration en = Collections.enumeration((Collection)obj);
while (en.hasMoreElements()) {
pstmt = txn.prepareAutoCloseStatement(ec.insertSql);
if (ec.targetClass == Date.class) {
pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), (Date)en.nextElement()));
} else {
pstmt.setObject(1, en.nextElement());
}
prepareAttribute(2, pstmt, _idAttributes.get(attr.table)[0], _idField.get(entity));
pstmt.executeUpdate();
}
}
} catch (IllegalArgumentException e) {
throw new CloudRuntimeException("Yikes! ", e);
} catch (IllegalAccessException e) {
throw new CloudRuntimeException("Yikes! ", e);
}
}
txn.commit();
} catch (final SQLException e) {
if (e.getSQLState().equals("23000") && e.getErrorCode() == 1062) {
@ -1235,7 +1269,7 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
} else if (attr.is(Attribute.Flag.AutoGV)) {
if (attr.columnName.equals(GenericDao.XID_COLUMN)) {
return UUID.randomUUID().toString();
}
}
assert (false) : "Auto generation is not supported.";
return null;
} else if (attr.is(Attribute.Flag.SequenceGV)) {
@ -1268,7 +1302,7 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
final Column column = attr.field.getAnnotation(Column.class);
final int length = column != null ? column.length() : 255;
// to support generic localization, utilize MySql UTF-8 support
// 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"));
@ -1379,9 +1413,78 @@ public abstract class GenericDaoBase<T, ID extends Serializable> 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);
for (Attribute attr : _ecAttributes) {
loadCollection(entity, attr);
}
}
@DB(txn = true)
@SuppressWarnings("unchecked")
protected void loadCollection(T entity, Attribute attr) {
EcInfo ec = (EcInfo)attr.attache;
Transaction txn = Transaction.currentTxn();
PreparedStatement pstmt = null;
try {
pstmt = txn.prepareAutoCloseStatement(ec.selectSql);
pstmt.setObject(1, _idField.get(entity));
ResultSet rs = pstmt.executeQuery();
ArrayList lst = new ArrayList();
if (ec.targetClass == Integer.class) {
while (rs.next()) {
lst.add(rs.getInt(1));
}
} else if (ec.targetClass == Long.class) {
while (rs.next()) {
lst.add(rs.getLong(1));
}
} else if (ec.targetClass == String.class) {
while (rs.next()) {
lst.add(rs.getString(1));
}
} else if (ec.targetClass == Short.class) {
while (rs.next()) {
lst.add(rs.getShort(1));
}
} else if (ec.targetClass == Date.class) {
while (rs.next()) {
lst.add(DateUtil.parseDateString(s_gmtTimeZone, rs.getString(1)));
}
} else if (ec.targetClass == Boolean.class) {
while (rs.next()) {
lst.add(rs.getBoolean(1));
}
} else {
assert (false) : "You'll need to add more classeses";
}
if (ec.rawClass == null) {
Object[] array = (Object[])Array.newInstance(ec.targetClass);
lst.toArray(array);
try {
attr.field.set(entity, array);
} catch (IllegalArgumentException e) {
throw new CloudRuntimeException("Come on we screen for this stuff, don't we?", e);
} catch (IllegalAccessException e) {
throw new CloudRuntimeException("Come on we screen for this stuff, don't we?", e);
}
} else {
try {
Collection coll = (Collection)ec.rawClass.newInstance();
coll.addAll(lst);
attr.field.set(entity, coll);
} catch (IllegalAccessException e) {
throw new CloudRuntimeException("Come on we screen for this stuff, don't we?", e);
} catch (InstantiationException e) {
throw new CloudRuntimeException("Never should happen", e);
}
}
} catch (SQLException e) {
throw new CloudRuntimeException("Error executing " + pstmt, e);
} catch (IllegalArgumentException e) {
throw new CloudRuntimeException("Error executing " + pstmt, e);
} catch (IllegalAccessException e) {
throw new CloudRuntimeException("Error executing " + pstmt, e);
}
}

View File

@ -29,16 +29,16 @@ import java.util.List;
import java.util.Map;
import javax.persistence.AttributeOverride;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.ElementCollection;
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;
@ -54,13 +54,13 @@ public class SqlGenerator {
ArrayList<Class<?>> _tables;
LinkedHashMap<String, List<Attribute>> _ids;
HashMap<String, TableGenerator> _generators;
ArrayList<Attribute> _otmAttrs;
ArrayList<Attribute> _ecAttrs;
public SqlGenerator(Class<?> clazz) {
_clazz = clazz;
_tables = new ArrayList<Class<?>>();
_attributes = new ArrayList<Attribute>();
_otmAttrs = new ArrayList<Attribute>();
_ecAttrs = new ArrayList<Attribute>();
_embeddeds = new ArrayList<Field>();
_ids = new LinkedHashMap<String, List<Attribute>>();
_generators = new HashMap<String, TableGenerator>();
@ -68,6 +68,7 @@ public class SqlGenerator {
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);
findEcAttributes();
}
protected boolean checkMethods(Class<?> clazz, Map<String, Attribute> attrs) {
@ -140,27 +141,33 @@ public class SqlGenerator {
attrs.add(attr);
}
if (field.getAnnotation(OneToMany.class) != null) {
assert supportsOneToMany(field) : "Doesn't support One To Many";
_otmAttrs.add(attr);
} else {
_attributes.add(attr);
_attributes.add(attr);
}
}
protected void findEcAttributes() {
for (Attribute attr : _attributes) {
ElementCollection ec = attr.field.getAnnotation(ElementCollection.class);
if (ec != null) {
Attribute idAttr = _ids.get(attr.table).get(0);
assert supportsElementCollection(attr.field) : "Doesn't support ElementCollection for " + attr.field.getName();
attr.attache = new EcInfo(attr, idAttr);
_ecAttrs.add(attr);
}
}
}
protected boolean supportsOneToMany(Field field) {
OneToMany otm = field.getAnnotation(OneToMany.class);
protected boolean supportsElementCollection(Field field) {
ElementCollection otm = field.getAnnotation(ElementCollection.class);
if (otm.fetch() == FetchType.LAZY) {
assert (false) : "Doesn't support laz fetch: " + field.getName();
return false;
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;
}
CollectionTable ct = field.getAnnotation(CollectionTable.class);
if (ct == null) {
assert (false) : "No collection table sepcified for " + field.getName();
return false;
}
return true;
@ -264,8 +271,8 @@ public class SqlGenerator {
}
}
public List<Attribute> getOneToManyAttributes() {
return _otmAttrs;
public List<Attribute> getElementCollectionAttributes() {
return _ecAttrs;
}
public Attribute findAttribute(String name) {

View File

@ -17,6 +17,17 @@
*/
package javax.persistence;
public interface ElementCollection {
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = { METHOD, FIELD })
@Retention(value = RetentionPolicy.RUNTIME)
public @interface ElementCollection {
FetchType fetch() default FetchType.LAZY;
Class<?> targetClass() default void.class;
}