/*
* Copyright 2009-2010 the original author or authors.
*
* 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.internna.iwebmvc.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.servlet.http.HttpServletRequest;
import org.directwebremoting.annotations.DataTransferObject;
import org.directwebremoting.annotations.RemoteProperty;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Cascade;
import org.hibernate.search.annotations.ContainedIn;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.IndexedEmbedded;
import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.NotNull;
import org.hibernate.validator.Valid;
import org.internna.iwebmvc.dao.DAO;
import org.internna.iwebmvc.metadata.ui.GridColumn;
import org.internna.iwebmvc.security.UserManager;
import org.internna.iwebmvc.spring.util.RequestContextUtils;
import org.internna.iwebmvc.spring.util.WebApplicationContextUtils;
import org.springframework.util.CollectionUtils;
/**
* Domain class to represent a poll (question with several possible answers).
*
* @author Jose Noheda
* @since 2.0
*/
@Entity
@Indexed
@Table(name = "POLLS")
@DataTransferObject(javascript = "Poll")
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
@NamedQueries({
@NamedQuery(name = "Poll.findAll", query = "SELECT p FROM Poll p"),
@NamedQuery(name = "Poll.findActive", query = "SELECT p FROM Poll p WHERE active = true")
})
public class Poll extends AbstractDomainEntity {
private static final long serialVersionUID = -8804360496775858121L;
/**
* Named query to find all active polls.
*/
public static String FIND_ACTIVE_POLLS = "Poll.findActive";
@Valid
@NotNull
@IndexedEmbedded
@GridColumn(order = 1)
@JoinColumn(name = "QUESTION", nullable = false)
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private I18nText question;
@Column(name = "ACTIVATED")
@GridColumn(order = 0, relativeWidth = 0.4)
private boolean active;
@Column(name = "ALLOW_ANON")
private boolean allowAnonymousVotes;
@Column(name = "RANDOM_ORDER")
private boolean randomizeOptions;
@Column(name = "STORE_VOTES")
private boolean storeVotes;
@Column(name = "REQUIRE_VOTE")
private boolean requireVoteForResults;
@NotNull
@NotEmpty
@ContainedIn
@GridColumn(relativeWidth = 1.0, order = 1)
@Cascade({org.hibernate.annotations.CascadeType.DELETE_ORPHAN, org.hibernate.annotations.CascadeType.SAVE_UPDATE})
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Collection<PollOption> options;
@RemoteProperty public I18nText getQuestion() {
return question;
}
public void setQuestion(I18nText question) {
this.question = question;
}
@RemoteProperty public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
@RemoteProperty public boolean isAllowAnonymousVotes() {
return allowAnonymousVotes;
}
public void setAllowAnonymousVotes(boolean allowAnonymousVotes) {
this.allowAnonymousVotes = allowAnonymousVotes;
}
@RemoteProperty public boolean isRandomizeOptions() {
return randomizeOptions;
}
public void setRandomizeOptions(boolean randomizeOptions) {
this.randomizeOptions = randomizeOptions;
}
@RemoteProperty public boolean isStoreVotes() {
return storeVotes;
}
public void setStoreVotes(boolean storeVotes) {
this.storeVotes = storeVotes;
}
@RemoteProperty public boolean isRequireVoteForResults() {
return requireVoteForResults;
}
public void setRequireVoteForResults(boolean requireVoteForResults) {
this.requireVoteForResults = requireVoteForResults;
}
@RemoteProperty public Collection<PollOption> getOptions() {
return options == null ? null : Collections.unmodifiableCollection(options);
}
public void addOption(PollOption option) {
if (options == null) options = new ArrayList<PollOption>();
option.setPoll(this);
options.add(option);
}
public void removeOption(PollOption option) {
if ((options != null) && (options.contains(option))) {
option.setPoll(null);
options.remove(option);
if (CollectionUtils.isEmpty(options)) setOptions(null);
}
}
public void clearOptions() {
setOptions(null);
}
public void setOptions(Collection<PollOption> options) {
this.options = options;
}
/**
* Returns the collection of options ordered by the option.order property
* or randomized if poll.randomizeOptions is true.
*
* @return all the available options
*/
@RemoteProperty public Collection<PollOption> getOrderedOptions() {
List<PollOption> ordered = new ArrayList<PollOption>(getOptions());
if (isRandomizeOptions()) Collections.sort(ordered, new Comparator<PollOption>() {
@Override public int compare(PollOption o1, PollOption o2) {
return Math.random() > 0.5 ? 1 : -1;
}
});
else Collections.sort(ordered);
return Collections.unmodifiableList(ordered);
}
/**
* Obtain the vote made by the current user. This method implementation makes several assumptions
* that may not be safe! Try using @Configurable as a better alternative!
*
* @return null unless the current logged user has already voted this poll
*/
@RemoteProperty public PollVote getCurrentUserVote() {
HttpServletRequest request = RequestContextUtils.getActiveRequest();
if (request != null) {
UserManager userManager = (UserManager) WebApplicationContextUtils.getBean("sessionUserManager");
DAO dao = (DAO) WebApplicationContextUtils.getBean("baseDAO");
if ((userManager!= null) && (dao != null))
return getUserVote(userManager.getActiveUser(request), request.getRemoteAddr(), dao);
}
return null;
}
/**
* Obtain the vote made by the provided user
*
* @return null unless the user has already voted this poll
*/
public PollVote getUserVote(User user, String IPAddress, DAO dao) {
PollVote vote = null;
if (isStoreVotes()) {
Map<String, Object> params = new HashMap<String, Object>(3);
params.put("pollId", getId());
params.put("user", user == null || user.isAnonymous() ? null : user);
params.put("IPAddress", IPAddress);
List<PollVote> votes = dao.findByNamedQuery(PollVote.FIND_BY_POLL_AND_USER, 0, 1, params);
if (!CollectionUtils.isEmpty(votes)) vote = votes.get(0);
}
return vote;
}
/**
* Returns the total number of votes for this poll (in all options).
*
* @return zero or a positive number
*/
@RemoteProperty public long getTotalVotes() {
long total = 0;
if (!CollectionUtils.isEmpty(getOptions()))
for (PollOption option : getOptions())
total += option.getTotalVotes();
return total;
}
@RemoteProperty public long getMaxVotes() {
long total = 0;
if (!CollectionUtils.isEmpty(getOptions()))
for (PollOption option : getOptions())
if (option.getTotalVotes() > total)
total = option.getTotalVotes();
return total;
}
@Override public String getCaption(Locale locale) {
return question != null ? question.getCaption(locale) : "";
}
@Override public String toString() {
return getCaption(Locale.getDefault());
}
}