/* * Copyright 2012 Nodeable 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 com.streamreduce.core.model.messages; import com.google.code.morphia.annotations.Embedded; import com.google.code.morphia.annotations.Entity; import com.google.code.morphia.annotations.Index; import com.google.code.morphia.annotations.Indexes; import com.google.code.morphia.annotations.PrePersist; import com.streamreduce.core.model.Connection; import com.streamreduce.core.model.ObjectWithId; import com.streamreduce.core.model.SobaObject; import com.streamreduce.core.model.Taggable; import com.streamreduce.core.model.messages.details.SobaMessageDetails; import com.streamreduce.util.HashtagUtil; import org.bson.types.ObjectId; import javax.validation.constraints.NotNull; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Set; import java.util.TreeSet; @SuppressWarnings("rawtypes") @Entity(value = "messages", noClassnameStored = true) @Indexes({ @Index("senderId, ownerId, visibility, hashtags, modified") // regular queries }) public final class SobaMessage extends ObjectWithId implements Taggable, Comparable { private static final long serialVersionUID = -839370297341737935L; @NotNull protected MessageType type; // SOBA-1050 (types changed) @NotNull protected SobaObject.Visibility visibility = SobaObject.Visibility.ACCOUNT; @NotNull protected ObjectId ownerId; @NotNull protected ObjectId senderId; protected String senderName; // set name for posterity and for the DTO later on. protected String senderConnectionName; // set name for posterity and for the DTO later on, may be null for User message protected ObjectId senderAccountId; protected ObjectId connectionId; // ie, cloudId, projectId - may be null protected String providerId; // jira, github, aws, etc... - may be null @Embedded protected List<MessageComment> comments = new ArrayList<>(); protected String transformedMessage; protected Long dateGenerated; protected Set<String> hashtags = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); @Embedded protected SobaMessageDetails details; private SobaMessage() { } @PrePersist public void generateCreatedDateIfMissing() { // if the user doesn't pass this, set it to be equal to creation date if (dateGenerated == null) { dateGenerated = created; } } /** * Adds a comment to the first position of the array. Also updates the modified date of this object * * @param comment - valid comment object */ public void addComment(MessageComment comment) { // always add to the first position. comments.add(0, comment); modified = comment.getCreated(); } public List<MessageComment> getComments() { return comments; } public void setHashtags(Set<String> hashtags) { if (hashtags != null) { for (String tag : hashtags) { addHashtag(tag); } } } @Override public void addHashtags(Set<String> hashtags) { setHashtags(hashtags); } /** * Adds, but also normalizes the tag and updates the modified date of this object * * @param tag - the tag */ @Override public void addHashtag(String tag) { if (tag != null && !tag.isEmpty()) { tag = HashtagUtil.normalizeTag(tag); hashtags.add(tag); modified = new Date().getTime(); } } /** * Remoevs and updates the modified date of this object * * @param tag - the tag */ @Override public void removeHashtag(String tag) { if (tag != null && !tag.isEmpty()) { tag = HashtagUtil.normalizeTag(tag); hashtags.remove(tag); modified = new Date().getTime(); } } public MessageType getType() { return type; } public ObjectId getSenderId() { return senderId; } public String getSenderName() { return senderName; } public String getSenderConnectionName() { return senderConnectionName; } public ObjectId getSenderAccountId() { return senderAccountId; } public String getTransformedMessage() { return transformedMessage; } public Long getCreated() { return created; } public Long getModified() { return modified; } public Long getDateGenerated() { return dateGenerated; } public Set<String> getHashtags() { return hashtags; } public ObjectId getConnectionId() { return connectionId; } public String getProviderId() { return providerId; } public SobaObject.Visibility getVisibility() { return visibility; } public void setVisibility(SobaObject.Visibility visibility) { this.visibility = visibility; } public ObjectId getOwnerId() { return ownerId; } public SobaMessageDetails getDetails() { return details; } @Override public int compareTo(Object o) { long result = modified.compareTo(((SobaMessage) o).modified); if (result < 0) { return -1; } else if (result > 0) { return 1; } else { return 0; } } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SobaMessage message = (SobaMessage) o; if (connectionId != null ? !connectionId.equals(message.connectionId) : message.connectionId != null) { return false; } if (ownerId != null ? !ownerId.equals(message.ownerId) : message.ownerId != null) { return false; } if (providerId != null ? !providerId.equals(message.providerId) : message.providerId != null) { return false; } if (visibility != message.visibility) { return false; } if (senderConnectionName != null ? !senderConnectionName.equals(message.senderConnectionName) : message.senderConnectionName != null) { return false; } if (senderId != null ? !senderId.equals(message.senderId) : message.senderId != null) { return false; } if (transformedMessage != null ? !transformedMessage.equals(message.transformedMessage) : message.transformedMessage != null) { return false; } if (type != message.type) { return false; } return true; } @Override public int hashCode() { int result = type != null ? type.hashCode() : 0; result = 31 * result + (visibility != null ? visibility.hashCode() : 0); result = 31 * result + (senderId != null ? senderId.hashCode() : 0); result = 31 * result + (senderConnectionName != null ? senderConnectionName.hashCode() : 0); result = 31 * result + (connectionId != null ? connectionId.hashCode() : 0); result = 31 * result + (ownerId != null ? ownerId.hashCode() : 0); result = 31 * result + (providerId != null ? providerId.hashCode() : 0); result = 31 * result + (transformedMessage != null ? transformedMessage.hashCode() : 0); return result; } public static class Builder { private SobaMessage message; private Connection connection; @SuppressWarnings("unchecked") public Builder() { message = new SobaMessage(); } public Builder type(MessageType type) { message.type = type; return this; } public Builder connection(Connection connection) { if (connection != null) { message.connectionId = connection.getId(); message.providerId = connection.getProviderId(); message.senderConnectionName = connection.getAlias(); // we'll use this in the build method to check for visibility overrides this.connection = connection; } return this; } public Builder providerId(String providerId) { message.providerId = providerId; return this; } /** * Sets the senderId, senderName, ownverId and Visibity to the sender values * * @param sender * @return */ public Builder sender(SobaObject sender) { if (sender != null) { message.senderId = sender.getId(); message.senderName = sender.getAlias(); message.senderAccountId = sender.getAccount().getId(); message.ownerId = sender.getUser().getId(); // defaults to sender visibility message.visibility = sender.getVisibility(); } return this; } // you shouldn't really need this except to override sender and/or connection values public Builder visibility(SobaObject.Visibility visibility) { message.visibility = visibility; return this; } public Builder dateGenerated(Long dateGenerated) { message.dateGenerated = dateGenerated; return this; } public Builder hashtags(Set<String> hashTags) { message.setHashtags(hashTags); return this; } public Builder transformedMessage(String transformedMessage) { message.transformedMessage = transformedMessage; return this; } public Builder details(SobaMessageDetails details) { message.details = details; return this; } public SobaMessage build() { //verify required fields are non-null if (this.message.type == null || this.message.visibility == null || this.message.ownerId == null || this.message.senderId == null) { throw new IllegalStateException("SobaMessage must have a non-null type, visibility, ownerId, and senderId."); } // SOBA-1885: override and use connection for the fringe case of pubic types if (this.connection != null && this.connection.getVisibility().equals(SobaObject.Visibility.PUBLIC)) { message.visibility = this.connection.getVisibility(); } return this.message; } } public void setTransformedMessage(String transformedMessage) { this.transformedMessage = transformedMessage; } public void setDetails(SobaMessageDetails details) { this.details = details; } }