/* * Copyright 2014 JBoss Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.artificer.repository.hibernate.entity; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Nullable; import javax.persistence.AttributeOverride; import javax.persistence.AttributeOverrides; import javax.persistence.Cacheable; import javax.persistence.CascadeType; import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.JoinColumn; import javax.persistence.Lob; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Transient; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.artificer.repository.hibernate.audit.ArtificerAuditEntry; import org.artificer.repository.hibernate.query.ArtificerTikaBridge; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.Index; import org.hibernate.annotations.Table; import org.hibernate.search.annotations.Analyzer; import org.hibernate.search.annotations.Field; import org.hibernate.search.annotations.FieldBridge; import org.hibernate.search.annotations.Indexed; import org.hibernate.search.annotations.IndexedEmbedded; /** * @author Brett Meyer. */ @Entity @Inheritance(strategy = InheritanceType.JOINED) @Table(appliesTo = "Artifact", indexes = { // Note that the indexes all include 'trashed', since 'trashed=false' is used on all queries. @Index(name = "artifact_uuid_idx", columnNames = {"uuid", "trashed"}), @Index(name = "artifact_name_idx", columnNames = {"name", "trashed"}), @Index(name = "artifact_model_idx", columnNames = {"model", "trashed"}), @Index(name = "artifact_type_idx", columnNames = {"type", "trashed"}), @Index(name = "artifact_model_type_idx", columnNames = {"model", "type", "trashed"})}) @Cacheable @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) @Indexed @Analyzer(impl = StandardAnalyzer.class) @javax.persistence.Table(name = "Artifact") public class ArtificerArtifact implements Serializable { private long id; private String uuid; private String name; private String model; private String type; private String description; private ArtificerUser createdBy; private ArtificerUser modifiedBy; private List<ArtificerRelationship> relationships = new ArrayList<>(); // Note: At first glance, it seems like these should probably be actual references to ArtificerOntologyClass. // However, the hierarchical queries become *much* easier when it's a simple element collection... private List<String> classifiers = new ArrayList<>(); private List<String> normalizedClassifiers = new ArrayList<>(); private List<ArtificerComment> comments = new ArrayList<>(); private boolean trashed; private ArtificerArtifact derivedFrom; private List<ArtificerArtifact> derivedArtifacts = new ArrayList<>(); private Set<ArtificerProperty> properties = new HashSet<>(); // TODO: Temporary! private String version; private boolean derived; private List<ArtificerAuditEntry> auditEntries = new ArrayList<>(); // Note: content and contentPath are mutually exclusive. See FileManager impls. private byte[] content; // Note: content and contentPath are mutually exclusive. See FileManager impls. private String contentPath; private String mimeType; private long contentSize; private String contentHash; private String contentEncoding; private boolean expandedFromArchive; private ArtificerArtifact expandedFrom; private List<ArtificerArtifact> expandedArtifacts = new ArrayList<>(); private String expandedFromArchivePath; @Id @GeneratedValue public long getId() { return id; } public void setId(long id) { this.id = id; } @Column(columnDefinition = "char(36)") public String getUuid() { return uuid; } public void setUuid(String uuid) { this.uuid = uuid; } @Field public String getName() { return name; } public void setName(String name) { this.name = name; } @Field public String getModel() { return model; } public void setModel(String model) { this.model = model; } @Field public String getType() { return type; } public void setType(String type) { this.type = type; } @Field public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @Embedded @AttributeOverrides({ @AttributeOverride(name = "username", column = @Column(name="createdByUsername", length = 50)), @AttributeOverride(name = "lastActionTime", column = @Column(name="createdTime")) }) public ArtificerUser getCreatedBy() { return createdBy; } public void setCreatedBy(ArtificerUser createdBy) { this.createdBy = createdBy; } @Embedded @AttributeOverrides({ @AttributeOverride(name = "username", column = @Column(name="modifiedByUsername", length = 50)), @AttributeOverride(name = "lastActionTime", column = @Column(name="modifiedTime")) }) public ArtificerUser getModifiedBy() { return modifiedBy; } public void setModifiedBy(ArtificerUser modifiedBy) { this.modifiedBy = modifiedBy; } @OneToMany(mappedBy = "owner", orphanRemoval = true, cascade = CascadeType.ALL) public List<ArtificerRelationship> getRelationships() { return relationships; } public void setRelationships(List<ArtificerRelationship> relationships) { this.relationships = relationships; } @ElementCollection @CollectionTable(name = "Artifact_classifiers", joinColumns = @JoinColumn(name = "Artifact_Id")) public List<String> getClassifiers() { return classifiers; } public void setClassifiers(List<String> classifiers) { this.classifiers = classifiers; } @ElementCollection @CollectionTable(name = "Artifact_normalizedClassifiers", joinColumns = @JoinColumn(name = "Artifact_Id")) public List<String> getNormalizedClassifiers() { return normalizedClassifiers; } public void setNormalizedClassifiers(List<String> normalizedClassifiers) { this.normalizedClassifiers = normalizedClassifiers; } @OneToMany(mappedBy = "artifact", orphanRemoval = true, cascade = CascadeType.ALL) @IndexedEmbedded public List<ArtificerComment> getComments() { return comments; } public void setComments(List<ArtificerComment> comments) { this.comments = comments; } @Field public boolean isTrashed() { return trashed; } public void setTrashed(boolean trashed) { this.trashed = trashed; } public boolean isDerived() { return derived; } public void setDerived(boolean derived) { this.derived = derived; } @ManyToOne public ArtificerArtifact getDerivedFrom() { return derivedFrom; } public void setDerivedFrom(ArtificerArtifact derivedFrom) { this.derivedFrom = derivedFrom; } @OneToMany(mappedBy = "derivedFrom", orphanRemoval = true, cascade = CascadeType.ALL) public List<ArtificerArtifact> getDerivedArtifacts() { return derivedArtifacts; } public void setDerivedArtifacts(List<ArtificerArtifact> derivedArtifacts) { this.derivedArtifacts = derivedArtifacts; } @OneToMany(mappedBy = "owner", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER) @IndexedEmbedded public Set<ArtificerProperty> getProperties() { return properties; } public void setProperties(Set<ArtificerProperty> properties) { this.properties = properties; } @Transient public boolean isDocument() { return false; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } @OneToMany(mappedBy = "artifact", orphanRemoval = true) public List<ArtificerAuditEntry> getAuditEntries() { return auditEntries; } public void setAuditEntries(List<ArtificerAuditEntry> auditEntries) { this.auditEntries = auditEntries; } @Lob @Field @FieldBridge(impl = ArtificerTikaBridge.class) @Nullable @Column(length = 20971520, nullable = true) public byte[] getContent() { return content; } public void setContent(byte[] content) { this.content = content; } @Field @FieldBridge(impl = ArtificerTikaBridge.class) public String getContentPath() { return contentPath; } public void setContentPath(String contentPath) { this.contentPath = contentPath; } @Column(length = 100) public String getMimeType() { return mimeType; } public void setMimeType(String mimeType) { this.mimeType = mimeType; } public long getContentSize() { return contentSize; } public void setContentSize(long contentSize) { this.contentSize = contentSize; } @Column(columnDefinition = "char(40)") public String getContentHash() { return contentHash; } public void setContentHash(String contentHash) { this.contentHash = contentHash; } public String getContentEncoding() { return contentEncoding; } public void setContentEncoding(String contentEncoding) { this.contentEncoding = contentEncoding; } public boolean isExpandedFromArchive() { return expandedFromArchive; } public void setExpandedFromArchive(boolean expandedFromArchive) { this.expandedFromArchive = expandedFromArchive; } @ManyToOne public ArtificerArtifact getExpandedFrom() { return expandedFrom; } public void setExpandedFrom(ArtificerArtifact expandedFrom) { this.expandedFrom = expandedFrom; } @OneToMany(mappedBy = "expandedFrom", orphanRemoval = true, cascade = CascadeType.ALL) public List<ArtificerArtifact> getExpandedArtifacts() { return expandedArtifacts; } public void setExpandedArtifacts(List<ArtificerArtifact> expandedArtifacts) { this.expandedArtifacts = expandedArtifacts; } public String getExpandedFromArchivePath() { return expandedFromArchivePath; } public void setExpandedFromArchivePath(String expandedFromArchivePath) { this.expandedFromArchivePath = expandedFromArchivePath; } public final Map<String, String> snapshotProperties() { Map<String, String> snapshotProperties = new HashMap<>(); snapshotProperties.put("name", name); snapshotProperties.put("description", description); snapshotProperties.put("version", version); for (ArtificerProperty property : properties) { snapshotProperties.put(property.getKey(), property.getValue()); } return snapshotProperties; } protected void addSnapshotProperties(Map<String, String> snapshotProperties) {} }