Commit d1e979ff by Tuomas Riihimäki

Merge branch 'feature/meta' into 'master'

JSON metadata fields for entities

Adds meta JSON field to all GenericEntity entities. The field is of type json in PostgreSQL and of type JSONObject in Java. There are getMeta() and setMeta() accessors in GenericEntity and EntityMeta interface.

Reviewed-By: @tuomari
2 parents 92d97874 802b96bf
...@@ -23,6 +23,25 @@ public class BootstrapBean implements BootstrapBeanLocal { ...@@ -23,6 +23,25 @@ public class BootstrapBean implements BootstrapBeanLocal {
public BootstrapBean() { public BootstrapBean() {
} }
/**
* Runs a "ALTER TABLE
* <table>
* <statement>" for each of tables.
*
* @param alterStatement
* e.g. "ADD meta json"
* @param tables
* table name strings
* @return1
*/
private static final String[] alterTables(String alterStatement, String... tables) {
String[] strings = new String[tables.length];
for (int i = 0; i < tables.length; i++) {
strings[i] = "ALTER TABLE \"" + tables[i] + "\" " + alterStatement;
}
return strings;
}
private static final List<String[]> dbUpdates = new ArrayList<String[]>(); private static final List<String[]> dbUpdates = new ArrayList<String[]>();
static { static {
// {"Query1","Query2",...} // {"Query1","Query2",...}
...@@ -60,7 +79,76 @@ public class BootstrapBean implements BootstrapBeanLocal { ...@@ -60,7 +79,76 @@ public class BootstrapBean implements BootstrapBeanLocal {
dbUpdates.add(new String[] { dbUpdates.add(new String[] {
"alter table compos add hidden boolean default false not null" "alter table compos add hidden boolean default false not null"
}); });
dbUpdates.add(alterTables("ADD COLUMN meta json",
"account_events",
"actionlog_message_responses",
"actionlog_message_tags",
"actionlog_messages",
"api_application_instances",
"api_applications",
"application_permissions",
"approvals",
"bill_lines",
"bills",
"card_code",
"card_templates",
"compo_entries",
"compo_entry_files",
"compo_entry_participations",
"compo_votes",
"compos",
"discount_instances",
"discounts",
"event_domains",
"event_log",
"event_log_types",
"event_organiser",
"event_private_properties",
"event_properties",
"event_users",
"events",
"feedback",
"food_wave_templates",
"food_waves",
"game_ids",
"group_memberships",
"groups",
"inventory_events",
"licensetargets",
"licensecodes",
"locations",
"maps",
"match_results",
"matches",
"menu_navigation",
"menuitem",
"news",
"news_groups",
"org_roles",
"places",
"poll",
"poll_answer",
"poll_question",
"possible_answer",
"printed_cards",
"product_limitations",
"products",
"reader_events",
"readers",
"roles",
"sales_entity",
"salespoint",
"site_page_content",
"site_pages",
"tournament_games",
"tournament_participants",
"tournament_rules",
"tournament_team_members",
"tournaments",
"user_approvals",
"user_images",
"user_notes",
"users"));
} }
@EJB @EJB
......
...@@ -57,5 +57,10 @@ ...@@ -57,5 +57,10 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.3-1100-jdbc41</version>
</dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
...@@ -15,6 +15,7 @@ public class MoyaPostgreSQLPlatform extends PostgreSQLPlatform { ...@@ -15,6 +15,7 @@ public class MoyaPostgreSQLPlatform extends PostgreSQLPlatform {
map.put(String.class, new FieldTypeDefinition("TEXT", false)); map.put(String.class, new FieldTypeDefinition("TEXT", false));
map.put(java.sql.Timestamp.class, new FieldTypeDefinition("TIMESTAMPTZ", false)); map.put(java.sql.Timestamp.class, new FieldTypeDefinition("TIMESTAMPTZ", false));
map.put(javax.json.JsonObject.class, new FieldTypeDefinition("JSON", false));
return map; return map;
} }
......
...@@ -4,22 +4,44 @@ import java.util.Date; ...@@ -4,22 +4,44 @@ import java.util.Date;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Temporal; import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
import fi.codecrew.moya.utilities.jpa.ModelInterface;
@Entity @Entity
@Table(name = "db_models") @Table(name = "db_models")
public class DBModel extends GenericEntity { public class DBModel implements ModelInterface {
private static final long serialVersionUID = 5073284536090477220L; private static final long serialVersionUID = 5073284536090477221L;
public static final String ID_COLUMN = "id";
@Column(name="revision", nullable=false) @Id
@Column(name = ID_COLUMN, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "revision", nullable = false)
private Integer revision; private Integer revision;
@Column(name="applied_at") @Column(name = "applied_at")
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
private Date appliedAt = new Date(); private Date appliedAt = new Date();
@Override
public final Integer getId() {
return id;
}
@Override
public final void setId(Integer id) {
this.id = id;
}
public Date getAppliedAt() { public Date getAppliedAt() {
return appliedAt; return appliedAt;
} }
......
package fi.codecrew.moya.model;
import javax.json.JsonObject;
/**
* Entities that have a JSON meta data column implement this interface.
*
* Meta data can be just about anything that is not deemed to be essential
* enough to have it's own column. Including people's shirt sizes etc.
*
* @author jkj
*/
public interface EntityMeta {
/**
* Get JSON metadata associated with the entity.
*
* @return JsonObject from meta column in DB.
*/
public JsonObject getMeta();
/**
* Associate JSON metadata to entity.
*
* @param meta
* JsonObject that goes into meta column in DB.
*/
public void setMeta(JsonObject meta);
}
package fi.codecrew.moya.model; package fi.codecrew.moya.model;
import javax.json.JsonObject;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType; import javax.persistence.GenerationType;
...@@ -10,7 +11,7 @@ import fi.codecrew.moya.utilities.jpa.EntityEquals; ...@@ -10,7 +11,7 @@ import fi.codecrew.moya.utilities.jpa.EntityEquals;
import fi.codecrew.moya.utilities.jpa.ModelInterface; import fi.codecrew.moya.utilities.jpa.ModelInterface;
@MappedSuperclass @MappedSuperclass
public class GenericEntity extends EntityEquals implements ModelInterface { public class GenericEntity extends EntityEquals implements ModelInterface, EntityMeta {
private static final long serialVersionUID = -9041737052951021560L; private static final long serialVersionUID = -9041737052951021560L;
public static final String ID_COLUMN = "id"; public static final String ID_COLUMN = "id";
...@@ -20,6 +21,8 @@ public class GenericEntity extends EntityEquals implements ModelInterface { ...@@ -20,6 +21,8 @@ public class GenericEntity extends EntityEquals implements ModelInterface {
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id; private Integer id;
private JsonObject meta;
@Override @Override
public final Integer getId() { public final Integer getId() {
return id; return id;
...@@ -30,4 +33,14 @@ public class GenericEntity extends EntityEquals implements ModelInterface { ...@@ -30,4 +33,14 @@ public class GenericEntity extends EntityEquals implements ModelInterface {
this.id = id; this.id = id;
} }
@Override
public JsonObject getMeta() {
return meta;
}
@Override
public void setMeta(JsonObject meta) {
this.meta = meta;
}
} }
...@@ -22,7 +22,7 @@ import org.eclipse.persistence.annotations.OptimisticLockingType; ...@@ -22,7 +22,7 @@ import org.eclipse.persistence.annotations.OptimisticLockingType;
* *
*/ */
@Entity @Entity
@Table(name = "licenseTargets") @Table(name = "licensetargets")
@OptimisticLocking(type = OptimisticLockingType.CHANGED_COLUMNS) @OptimisticLocking(type = OptimisticLockingType.CHANGED_COLUMNS)
public class LicenseTarget extends GenericEntity { public class LicenseTarget extends GenericEntity {
......
package fi.codecrew.moya.model.converters;
import java.io.StringReader;
import java.sql.SQLException;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import org.postgresql.util.PGobject;
@Converter(autoApply = true)
public class JsonAttributeConverter implements AttributeConverter<JsonObject, PGobject> {
public PGobject convertToDatabaseColumn(JsonObject attribute) {
if (attribute == null) {
return null;
}
final PGobject dataValue = new PGobject();
dataValue.setType("json");
try {
dataValue.setValue(attribute.toString());
} catch (SQLException e) {
// This will never run because PGobject.setValue() cannot really
// throw an SQLException. There is nothing but setting a property.
throw new RuntimeException("THIS SHOULD NEVER HAPPEN", e);
}
return dataValue;
}
public JsonObject convertToEntityAttribute(PGobject dbData) {
// Has any?
if (dbData == null) {
return null;
}
// Correct type of object?
if (dbData.getType().equals("json") == false) {
throw new RuntimeException("Expected JSON object from database");
}
// Read as JSON object
final StringReader stringReader = new StringReader(dbData.getValue());
final JsonReader jsonReader = Json.createReader(stringReader);
return jsonReader.readObject();
}
}
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
<dependent-module archiveName="org.ancoron.postgresql.jpa-9.1.901.jdbc4.1-rc9.jar" deploy-path="/lib" handle="module:/classpath/var/M2_REPO/org/ancoron/postgresql/org.ancoron.postgresql.jpa/9.1.901.jdbc4.1-rc9/org.ancoron.postgresql.jpa-9.1.901.jdbc4.1-rc9.jar"> <dependent-module archiveName="org.ancoron.postgresql.jpa-9.1.901.jdbc4.1-rc9.jar" deploy-path="/lib" handle="module:/classpath/var/M2_REPO/org/ancoron/postgresql/org.ancoron.postgresql.jpa/9.1.901.jdbc4.1-rc9/org.ancoron.postgresql.jpa-9.1.901.jdbc4.1-rc9.jar">
<dependency-type>uses</dependency-type> <dependency-type>uses</dependency-type>
</dependent-module> </dependent-module>
<dependent-module archiveName="postgresql-9.3-1100-jdbc41.jar" deploy-path="/lib" handle="module:/classpath/var/M2_REPO/org/postgresql/postgresql/9.3-1100-jdbc41/postgresql-9.3-1100-jdbc41.jar">
<dependency-type>uses</dependency-type>
</dependent-module>
<dependent-module archiveName="pdfjet-0.0.0-2013-08-19.jar" deploy-path="/lib" handle="module:/classpath/var/M2_REPO/fi/iudex/pdfjet/pdfjet/0.0.0-2013-08-19/pdfjet-0.0.0-2013-08-19.jar"> <dependent-module archiveName="pdfjet-0.0.0-2013-08-19.jar" deploy-path="/lib" handle="module:/classpath/var/M2_REPO/fi/iudex/pdfjet/pdfjet/0.0.0-2013-08-19/pdfjet-0.0.0-2013-08-19.jar">
<dependency-type>uses</dependency-type> <dependency-type>uses</dependency-type>
</dependent-module> </dependent-module>
......
...@@ -81,7 +81,7 @@ ...@@ -81,7 +81,7 @@
<dependency> <dependency>
<groupId>org.primefaces</groupId> <groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId> <artifactId>primefaces</artifactId>
<version>5.0.RC2</version> <version>5.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!