VotingServiceImpl.java
/*
* Copyright (C) 2003-2007 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see<http://www.gnu.org/licenses/>.
*/
package org.exoplatform.services.cms.voting.impl;
import java.text.DecimalFormat;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.nodetype.NoSuchNodeTypeException;
import org.exoplatform.services.cms.i18n.MultiLanguageService;
import org.exoplatform.services.cms.voting.VotingService;
import org.exoplatform.services.jcr.core.ManageableRepository;
import org.exoplatform.services.wcm.utils.WCMCoreUtils;
/**
* Created by The eXo Platform SAS
* Author : Pham Xuan Hoa
* hoa.pham@exoplatform.com
* Jan 17, 2007
*/
public class VotingServiceImpl implements VotingService {
final static String VOTABLE = "mix:votable";
final static String VOTER_PROP = "exo:voter";
final static String VOTER_VOTEVALUE_PROP = "exo:voterVoteValues";
final static String VOTING_RATE_PROP = "exo:votingRate";
final static String VOTE_TOTAL_PROP = "exo:voteTotal";
final static String VOTE_TOTAL_LANG_PROP = "exo:voteTotalOfLang";
private static final String LANGUAGES = "languages";
private static final String SPACE = " ";
private MultiLanguageService multiLangService_ ;
public VotingServiceImpl(MultiLanguageService multiLangService) {
multiLangService_ = multiLangService ;
}
/**
* {@inheritDoc}
*/
public long getVoteTotal(Node node) throws Exception {
long voteTotal = 0;
if(!node.hasNode(LANGUAGES) && node.hasProperty(VOTE_TOTAL_PROP)) {
return node.getProperty(VOTE_TOTAL_LANG_PROP).getLong() ;
}
Node multiLanguages = node.getNode(LANGUAGES) ;
voteTotal = node.getProperty(VOTE_TOTAL_LANG_PROP).getLong() ;
NodeIterator nodeIter = multiLanguages.getNodes() ;
while(nodeIter.hasNext()) {
Node languageNode = nodeIter.nextNode() ;
if(node.isNodeType("nt:file")) {
languageNode = getFileLangNode(languageNode) ;
}
if(languageNode.hasProperty(VOTE_TOTAL_LANG_PROP)) {
voteTotal = voteTotal + languageNode.getProperty(VOTE_TOTAL_LANG_PROP).getLong() ;
}
}
return voteTotal ;
}
/**
* Getting node is "nt:file" node type.
* @param currentNode
* @return
*/
public Node getFileLangNode(Node currentNode) throws Exception {
if(currentNode.getNodes().getSize() > 0) {
NodeIterator nodeIter = currentNode.getNodes() ;
while(nodeIter.hasNext()) {
Node ntFile = nodeIter.nextNode() ;
if(ntFile.isNodeType("nt:file")) {
return ntFile ;
}
}
return currentNode ;
}
return currentNode ;
}
/**
* {@inheritDoc}
*/
public void vote(Node node, double rate, String userName, String language) throws Exception {
Session session = node.getSession();
node = handleUser(session, node, userName);
//add mixin exo:votable
if(!node.isNodeType(VOTABLE)) {
if(node.canAddMixin(VOTABLE)) node.addMixin(VOTABLE) ;
else throw new NoSuchNodeTypeException() ;
}
Node languageNode = handleLanguage(node, language);
if(!languageNode.isNodeType(VOTABLE)) {
if(languageNode.canAddMixin(VOTABLE)) languageNode.addMixin(VOTABLE) ;
else throw new NoSuchNodeTypeException() ;
}
// get data to calculate
long voteTotalOfLang = languageNode.getProperty(VOTE_TOTAL_LANG_PROP).getLong() ;
double votingRate = languageNode.getProperty(VOTING_RATE_PROP).getDouble() ;
Value voterVoteValue = getVoterVoteValue(languageNode, userName);
//set new vote rating
double newRating = 0;
if (voterVoteValue != null) {
String oldUserRateValueStr = voterVoteValue.getString().substring(voterVoteValue.getString().lastIndexOf(SPACE) + 1);
double oldUserRate = Double.parseDouble(oldUserRateValueStr);
newRating = ((voteTotalOfLang*votingRate)+rate - oldUserRate)/(voteTotalOfLang) ;
} else {
newRating = ((voteTotalOfLang*votingRate)+rate)/(voteTotalOfLang+1) ;
}
DecimalFormat format = new DecimalFormat("###.##") ;
double formatedRating= format.parse(format.format(newRating)).doubleValue() ;
//set new voters
Value[] voterVoteValues = {} ;
Value[] newVoterVoteValues = null;
if(languageNode.hasProperty(VOTER_VOTEVALUE_PROP)) {
voterVoteValues = languageNode.getProperty(VOTER_VOTEVALUE_PROP).getValues() ;
}
if (voterVoteValue != null) {
newVoterVoteValues = replaceOldValue(voterVoteValues, userName, rate, languageNode.getSession());
} else {
Value newVoterVoteValue = languageNode.getSession().getValueFactory().createValue(userName + SPACE + rate);
newVoterVoteValues = new Value[voterVoteValues.length + (userName == null ? 0 : 1)];
System.arraycopy(voterVoteValues, 0, newVoterVoteValues, 0, voterVoteValues.length);
if (userName != null)
newVoterVoteValues[voterVoteValues.length] = newVoterVoteValue;
}
languageNode.setProperty(VOTER_VOTEVALUE_PROP, newVoterVoteValues);
//set total vote size and vote rate.
node.setProperty(VOTE_TOTAL_PROP,getVoteTotal(node)+(voterVoteValue == null ? 1 : 0)) ;
languageNode.setProperty(VOTE_TOTAL_LANG_PROP,voteTotalOfLang+(voterVoteValue == null ? 1 : 0)) ;
languageNode.setProperty(VOTING_RATE_PROP,formatedRating) ;
node.getSession().save() ;
languageNode.getSession().save();
}
//get the VoterVoteValue object from node
private Value getVoterVoteValue(Node languageNode, String userName) throws Exception {
if (!languageNode.hasProperty(VOTER_VOTEVALUE_PROP)) {
return null;
}
Value ret = null;
for (Value voterVoteValue : languageNode.getProperty(VOTER_VOTEVALUE_PROP).getValues()) {
if (voterVoteValue.getString().startsWith(userName + SPACE)) {
return voterVoteValue;
}
}
return ret;
}
//replace old VoterVoteValue by the new one
private Value[] replaceOldValue(Value[] voterVoteValues, String userName, double rate, Session session)
throws Exception {
for (int i = 0; i < voterVoteValues.length; i++) {
if (voterVoteValues[i].getString().startsWith(userName + SPACE)) {
voterVoteValues[i] = session.getValueFactory().createValue(userName + SPACE + rate);
break;
}
}
return voterVoteValues;
}
public boolean isVoted(Node node, String userName, String language) throws Exception {
return getVoteValueOfUser(node, userName, language) > 0;
}
private Node handleLanguage(Node node, String language) throws Exception {
String defaultLang = multiLangService_.getDefault(node) ;
Node multiLanguages =null, languageNode= null ;
if((defaultLang == null && language == null) || language.equals(defaultLang)) {
languageNode = node ;
} else {
if(node.hasNode(LANGUAGES)) {
multiLanguages = node.getNode(LANGUAGES) ;
if(multiLanguages.hasNode(language)) {
languageNode = multiLanguages.getNode(language) ;
if(node.isNodeType("nt:file")) {
languageNode = getFileLangNode(languageNode) ;
}
}
} else {
languageNode = node;
}
}
return languageNode;
}
private Node handleUser(Session session, Node node, String userName) throws Exception {
if (userName == null || "__anonim".equals(userName)) {
String strWorkspaceName = node.getSession().getWorkspace().getName();
ManageableRepository manageRepository = WCMCoreUtils.getRepository();
session = WCMCoreUtils.getSystemSessionProvider().getSession(strWorkspaceName,
manageRepository);
String uid = node.getUUID();
node = session.getNodeByUUID(uid);
}
return node;
}
@Override
public double getVoteValueOfUser(Node node, String userName, String language) throws Exception {
Session session = node.getSession();
node = handleUser(session, node, userName);
if(!node.isNodeType(VOTABLE)) {
if(node.canAddMixin(VOTABLE)) node.addMixin(VOTABLE) ;
else throw new NoSuchNodeTypeException() ;
}
Node languageNode = handleLanguage(node, language);
Value voterVoteValue = getVoterVoteValue(languageNode, userName);
if (voterVoteValue != null) {
String stValue = voterVoteValue.getString();
return Double.parseDouble(stValue.substring(stValue.indexOf(SPACE) + 1));
}
return 0;
}
}