/* * 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.faq.service.impl; import java.util.ArrayList; import java.util.Date; import java.util.GregorianCalendar; import java.util.List; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.Value; import org.exoplatform.faq.service.Answer; import org.exoplatform.faq.service.Comment; import org.exoplatform.faq.service.FAQNodeTypes; import org.exoplatform.faq.service.QuestionLanguage; import org.exoplatform.faq.service.Utils; import org.exoplatform.ks.common.jcr.PropertyReader; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; /** * MultiLanguages class allow question and category have multi language. * Question content and category's name is can written by one or * more languages. But only default language (only one language is default * in system) is set as property of question/ category, * other languages is children of question/category. * * @author Hung Nguyen Quang * @since Jul 10, 2007 */ public class MultiLanguages implements FAQNodeTypes { static private Log log = ExoLogger.getLogger(MultiLanguages.class); /** * Class constructor, instantiates a new multi languages. * * @throws Exception the exception */ public MultiLanguages() throws Exception { } private static Node getLanguageNodeByLanguage(Node questionNode, String language) throws Exception { if (language.equals(questionNode.getProperty(EXO_LANGUAGE).getString())) { return questionNode; } NodeIterator nodeIterator = questionNode.getNode(Utils.LANGUAGE_HOME).getNodes(); Node languageNode = null; while (nodeIterator.hasNext()) { languageNode = nodeIterator.nextNode(); if (languageNode.getProperty(EXO_LANGUAGE).getString().equals(language)) { return languageNode; } } return null; } /** * Adds the language node, when question have multi language, * each language is a child node of question node. * * @param questionNode the question node which have multi language * @param language the language which is added in to questionNode * @throws Exception throw an exception when save a new language node */ public static void addLanguage(Node questionNode, QuestionLanguage language) throws Exception { if (!questionNode.isNodeType(MIX_FAQI_1_8N)) { questionNode.addMixin(MIX_FAQI_1_8N); } Node languageHome = null; try { languageHome = questionNode.getNode(Utils.LANGUAGE_HOME); } catch (Exception e) { languageHome = questionNode.addNode(Utils.LANGUAGE_HOME, EXO_QUESTION_LANGUAGE_HOME); } Node langNode = null; try { langNode = languageHome.getNode(language.getId()); } catch (Exception e) { langNode = languageHome.addNode(language.getId(), EXO_FAQ_LANGUAGE); } langNode.setProperty(EXO_LANGUAGE, language.getLanguage()); langNode.setProperty(EXO_NAME, language.getDetail()); langNode.setProperty(EXO_TITLE, language.getQuestion()); langNode.setProperty(EXO_QUESTION_ID, questionNode.getName()); langNode.setProperty(EXO_CATEGORY_ID, questionNode.getProperty(EXO_CATEGORY_ID).getString()); if (langNode.isNew()) questionNode.getSession().save(); else questionNode.save(); } public static void deleteAnswerQuestionLang(Node questionNode, String answerId, String language) throws Exception { Node answerNode; if (language != null && language.length() > 0) { Node languageNode = getLanguageNodeByLanguage(questionNode, language); answerNode = languageNode.getNode(Utils.ANSWER_HOME).getNode(answerId); } else { answerNode = questionNode.getNode(Utils.ANSWER_HOME).getNode(answerId); } answerNode.remove(); questionNode.save(); } public static void deleteCommentQuestionLang(Node questionNode, String commentId, String language) throws Exception { Node languageNode = getLanguageNodeByLanguage(questionNode, language); Node commnetNode = languageNode.getNode(Utils.COMMENT_HOME).getNode(commentId); commnetNode.remove(); questionNode.save(); } public static QuestionLanguage getQuestionLanguageByLanguage(Node questionNode, String language) throws Exception { // QuestionLanguage questionLanguage = new QuestionLanguage(); // questionLanguage.setLanguage(language); Node languageNode = getLanguageNodeByLanguage(questionNode, language); /* * questionLanguage.setId(getName()); questionLanguage.setLanguage(reader.string(EXO_LANGUAGE, "")); questionLanguage.setDetail(getProperty(EXO_NAME).getString()); questionLanguage.setQuestion(getProperty(EXO_TITLE).getString()); */ return getQuestionLanguage(languageNode); } private static QuestionLanguage getQuestionLanguage(Node questionNode) throws Exception { QuestionLanguage questionLanguage = new QuestionLanguage(); PropertyReader reader = new PropertyReader(questionNode); questionLanguage.setState(QuestionLanguage.VIEW); questionLanguage.setId(questionNode.getName()); questionLanguage.setLanguage(reader.string(EXO_LANGUAGE, "")); questionLanguage.setQuestion(reader.string(EXO_TITLE, "")); questionLanguage.setDetail(reader.string(EXO_NAME, "")); Comment[] comments = getComment(questionNode); Answer[] answers = getAnswers(questionNode); questionLanguage.setComments(comments); questionLanguage.setAnswers(answers); return questionLanguage; } private static Comment[] getComment(Node questionNode) throws Exception { try { if (!questionNode.hasNode(Utils.COMMENT_HOME)) return new Comment[] {}; NodeIterator nodeIterator = questionNode.getNode(Utils.COMMENT_HOME).getNodes(); Comment[] comments = new Comment[(int) nodeIterator.getSize()]; Node commentNode = null; int i = 0; while (nodeIterator.hasNext()) { commentNode = nodeIterator.nextNode(); comments[i] = getCommentByNode(commentNode); i++; } return comments; } catch (Exception e) { return new Comment[] {}; } } private static Comment getCommentByNode(Node commentNode) throws Exception { Comment comment = new Comment(); comment.setId(commentNode.getName()); PropertyReader reader = new PropertyReader(commentNode); comment.setComments((reader.string(EXO_COMMENTS, ""))); comment.setCommentBy((reader.string(EXO_COMMENT_BY, ""))); comment.setDateComment((commentNode.getProperty(EXO_DATE_COMMENT).getDate().getTime())); comment.setFullName((reader.string(EXO_FULL_NAME, ""))); comment.setPostId(reader.string(EXO_POST_ID, "")); return comment; } private static Answer[] getAnswers(Node questionNode) throws Exception { try { if (!questionNode.hasNode(Utils.ANSWER_HOME)) return new Answer[] {}; NodeIterator nodeIterator = questionNode.getNode(Utils.ANSWER_HOME).getNodes(); List<Answer> answers = new ArrayList<Answer>(); Answer ans; String language = questionNode.getProperty(EXO_LANGUAGE).getString(); while (nodeIterator.hasNext()) { try { ans = getAnswerByNode(nodeIterator.nextNode()); ans.setLanguage(language); answers.add(ans); } catch (Exception e) { } } return answers.toArray(new Answer[] {}); } catch (Exception e) { log.error("Fail to get answers: ", e); } return new Answer[] {}; } private static Answer getAnswerByNode(Node answerNode) throws Exception { PropertyReader reader = new PropertyReader(answerNode); Answer answer = new Answer(); answer.setId(answerNode.getName()); answer.setResponses((reader.string(EXO_RESPONSES, ""))); answer.setResponseBy((reader.string(EXO_RESPONSE_BY, ""))); answer.setFullName((reader.string(EXO_FULL_NAME, ""))); answer.setDateResponse((answerNode.getProperty(EXO_DATE_RESPONSE).getDate().getTime())); answer.setUsersVoteAnswer(reader.strings(EXO_USERS_VOTE_ANSWER, new String[] {})); answer.setMarkVotes(reader.l(EXO_MARK_VOTES)); answer.setApprovedAnswers(reader.bool(EXO_APPROVE_RESPONSES, true)); answer.setActivateAnswers(reader.bool(EXO_ACTIVATE_RESPONSES, true)); answer.setPostId(reader.string(EXO_POST_ID, "")); String path = answerNode.getPath(); answer.setPath(path.substring(path.indexOf(Utils.FAQ_APP) + Utils.FAQ_APP.length() + 1)); return answer; } public static Comment getCommentById(Node questionNode, String commentId, String language) throws Exception { try { Node commentNode; if (language != null && language.length() > 0) { Node languageNode = getLanguageNodeByLanguage(questionNode, language); commentNode = languageNode.getNode(Utils.COMMENT_HOME).getNode(commentId); } else { commentNode = questionNode.getNode(Utils.COMMENT_HOME).getNode(commentId); } Comment comment = new Comment(); PropertyReader reader = new PropertyReader(commentNode); comment.setId((reader.string(EXO_ID, ""))); comment.setComments((reader.string(EXO_COMMENTS, ""))); comment.setCommentBy((reader.string(EXO_COMMENT_BY, ""))); comment.setFullName((reader.string(EXO_FULL_NAME, ""))); comment.setDateComment(reader.date(EXO_DATE_COMMENT)); comment.setPostId(reader.string(EXO_POST_ID, "")); return comment; } catch (Exception e) { return null; } } public static Answer getAnswerById(Node questionNode, String answerid, String language) throws Exception { Answer answer = new Answer(); try { Node answerNode; if (language != null && language.length() > 0) { Node languageNode = getLanguageNodeByLanguage(questionNode, language); answerNode = languageNode.getNode(Utils.ANSWER_HOME).getNode(answerid); } else { answerNode = questionNode.getNode(Utils.ANSWER_HOME).getNode(answerid); } PropertyReader reader = new PropertyReader(answerNode); answer.setId((reader.string(EXO_ID, ""))); String path = answerNode.getPath(); answer.setPath(path.substring(path.indexOf(Utils.FAQ_APP) + Utils.FAQ_APP.length() + 1)); answer.setResponses((reader.string(EXO_RESPONSES, ""))); answer.setResponseBy((reader.string(EXO_RESPONSE_BY, ""))); answer.setFullName((reader.string(EXO_FULL_NAME, ""))); answer.setDateResponse(reader.date(EXO_DATE_RESPONSE)); answer.setUsersVoteAnswer(reader.strings(EXO_USERS_VOTE_ANSWER, new String[] {})); answer.setMarkVotes(reader.l(EXO_MARK_VOTES)); answer.setApprovedAnswers(reader.bool(EXO_APPROVE_RESPONSES, true)); answer.setActivateAnswers(reader.bool(EXO_ACTIVATE_RESPONSES, true)); answer.setPostId(reader.string(EXO_POST_ID, "")); answer.setLanguage(reader.string(EXO_RESPONSE_LANGUAGE, "")); return answer; } catch (Exception e) { } return null; } public static void saveAnswer(Node questionNode, Answer answer, String language) throws Exception { Node answerHome; Node answerNode; String defaultLang = questionNode.getProperty(EXO_LANGUAGE).getString(); if (language != null && language.length() > 0 && !language.equals(defaultLang)) { Node languageNode = getLanguageNodeByLanguage(questionNode, language); if (!languageNode.isNodeType(MIX_FAQI_1_8N)) { languageNode.addMixin(MIX_FAQI_1_8N); } try { answerHome = languageNode.getNode(Utils.ANSWER_HOME); } catch (Exception e) { answerHome = languageNode.addNode(Utils.ANSWER_HOME, EXO_ANSWER_HOME); } answer.setLanguage(language); } else { try { answerHome = questionNode.getNode(Utils.ANSWER_HOME); } catch (Exception e) { answerHome = questionNode.addNode(Utils.ANSWER_HOME, EXO_ANSWER_HOME); } answer.setLanguage(questionNode.getProperty(EXO_LANGUAGE).getString()); } try { answerNode = answerHome.getNode(answer.getId()); } catch (Exception e) { answerNode = answerHome.addNode(answer.getId(), EXO_ANSWER); } answerNode.setProperty(EXO_RESPONSES, answer.getResponses()); answerNode.setProperty(EXO_RESPONSE_BY, answer.getResponseBy()); answerNode.setProperty(EXO_FULL_NAME, answer.getFullName()); answerNode.setProperty(EXO_USERS_VOTE_ANSWER, answer.getUsersVoteAnswer()); answerNode.setProperty(EXO_MARK_VOTES, answer.getMarkVotes()); Date answerDate = null; if (answer.isNew()) { java.util.Calendar calendar = null; calendar = GregorianCalendar.getInstance(); answerDate = new Date(); calendar.setTime(answerDate); answerNode.setProperty(EXO_DATE_RESPONSE, calendar); answerNode.setProperty(EXO_ID, answer.getId()); answerNode.setProperty(EXO_QUESTION_ID, questionNode.getName()); answerNode.setProperty(EXO_RESPONSE_LANGUAGE, language); answerNode.setProperty(EXO_CATEGORY_ID, questionNode.getProperty(EXO_CATEGORY_ID).getString()); answerNode.setProperty(EXO_APPROVE_RESPONSES, answer.getApprovedAnswers()); answerNode.setProperty(EXO_ACTIVATE_RESPONSES, answer.getActivateAnswers()); } else { if (answerNode.hasProperty(EXO_DATE_RESPONSE)) { answerDate = answerNode.getProperty(EXO_DATE_RESPONSE).getDate().getTime(); } if (new PropertyReader(answerNode).bool(EXO_APPROVE_RESPONSES, false) != answer.getApprovedAnswers()) answerNode.setProperty(EXO_APPROVE_RESPONSES, answer.getApprovedAnswers()); if (new PropertyReader(answerNode).bool(EXO_ACTIVATE_RESPONSES, false) != answer.getActivateAnswers()) answerNode.setProperty(EXO_ACTIVATE_RESPONSES, answer.getActivateAnswers()); } if (answer.getPostId() != null && answer.getPostId().length() > 0) { answerNode.setProperty(EXO_POST_ID, answer.getPostId()); } if (questionNode.isNew()) { questionNode.getSession().save(); } else { questionNode.save(); } } public static void saveAnswer(Node quesNode, QuestionLanguage questionLanguage) throws Exception { Node quesLangNode; try { quesLangNode = quesNode.getNode(Utils.LANGUAGE_HOME).getNode(questionLanguage.getId()); } catch (Exception e) { quesLangNode = quesNode.getNode(Utils.LANGUAGE_HOME).addNode(questionLanguage.getId(), EXO_FAQ_LANGUAGE); quesNode.getSession().save(); } if (!quesLangNode.isNodeType(MIX_FAQI_1_8N)) { quesLangNode.addMixin(MIX_FAQI_1_8N); } Node answerHome = null; Node answerNode; Answer[] answers = questionLanguage.getAnswers(); try { answerHome = quesLangNode.getNode(Utils.ANSWER_HOME); } catch (Exception e) { answerHome = quesLangNode.addNode(Utils.ANSWER_HOME, EXO_ANSWER_HOME); } if (!answerHome.isNew()) { List<String> listNewAnswersId = new ArrayList<String>(); for (int i = 0; i < answers.length; i++) { listNewAnswersId.add(answers[i].getId()); } NodeIterator nodeIterator = answerHome.getNodes(); while (nodeIterator.hasNext()) { answerNode = nodeIterator.nextNode(); if (!listNewAnswersId.contains(answerNode.getName())) answerNode.remove(); } } for (Answer answer : answers) { answerNode = null; try { answerNode = answerHome.getNode(answer.getId()); } catch (Exception e) { answerNode = answerHome.addNode(answer.getId(), EXO_ANSWER); answerNode.setProperty(EXO_ID, answer.getId()); } Date answerDate = null; if (answerNode.isNew()) { java.util.Calendar calendar = null; calendar = null; calendar = GregorianCalendar.getInstance(); answerDate = new Date(); calendar.setTime(answerDate); answerNode.setProperty(EXO_DATE_RESPONSE, calendar); answerNode.setProperty(EXO_QUESTION_ID, quesNode.getName()); answerNode.setProperty(EXO_CATEGORY_ID, quesNode.getProperty(EXO_CATEGORY_ID).getString()); } else { if (answerNode.hasProperty(EXO_DATE_RESPONSE)) { answerDate = answerNode.getProperty(EXO_DATE_RESPONSE).getDate().getTime(); } } String language = answer.getLanguage(); if (language == null || language.length() == 0) language = questionLanguage.getLanguage(); answerNode.setProperty(EXO_RESPONSES, answer.getResponses()); answerNode.setProperty(EXO_RESPONSE_BY, answer.getResponseBy()); answerNode.setProperty(EXO_FULL_NAME, answer.getFullName()); answerNode.setProperty(EXO_APPROVE_RESPONSES, answer.getApprovedAnswers()); answerNode.setProperty(EXO_ACTIVATE_RESPONSES, answer.getActivateAnswers()); answerNode.setProperty(EXO_USERS_VOTE_ANSWER, answer.getUsersVoteAnswer()); answerNode.setProperty(EXO_MARK_VOTES, answer.getMarkVotes()); answerNode.setProperty(EXO_RESPONSE_LANGUAGE, language); if (answer.getPostId() != null && answer.getPostId().length() > 0) { answerNode.setProperty(EXO_POST_ID, answer.getPostId()); } if (answerNode.isNew()) quesNode.getSession().save(); else quesNode.save(); } } public static void saveComment(Node questionNode, Comment comment, String language) throws Exception { String lang; Node commentHome; Node commentNode; if (language != null && language.length() > 0) { Node languageNode = getLanguageNodeByLanguage(questionNode, language); lang = language; if (!languageNode.isNodeType(MIX_FAQI_1_8N)) { languageNode.addMixin(MIX_FAQI_1_8N); } try { commentHome = languageNode.getNode(Utils.COMMENT_HOME); } catch (Exception e) { commentHome = languageNode.addNode(Utils.COMMENT_HOME, EXO_COMMENT_HOME); } } else { try { commentHome = questionNode.getNode(Utils.COMMENT_HOME); } catch (Exception e) { commentHome = questionNode.addNode(Utils.COMMENT_HOME, EXO_COMMENT_HOME); } lang = questionNode.getProperty(EXO_LANGUAGE).getString(); } try { commentNode = commentHome.getNode(comment.getId()); } catch (Exception e) { commentNode = commentHome.addNode(comment.getId(), EXO_COMMENT); commentNode.setProperty(EXO_ID, comment.getId()); } commentNode.setProperty(EXO_COMMENTS, comment.getComments()); commentNode.setProperty(EXO_COMMENT_BY, comment.getCommentBy()); commentNode.setProperty(EXO_FULL_NAME, comment.getFullName()); commentNode.setProperty(EXO_CATEGORY_ID, questionNode.getProperty(EXO_CATEGORY_ID).getString()); commentNode.setProperty(EXO_QUESTION_ID, questionNode.getName()); commentNode.setProperty(EXO_COMMENT_LANGUAGE, lang); if (comment.getPostId() != null && comment.getPostId().length() > 0) { commentNode.setProperty(EXO_POST_ID, comment.getPostId()); } Date commentTime = null; if (commentNode.isNew()) { java.util.Calendar calendar = null; calendar = GregorianCalendar.getInstance(); commentTime = new Date(); calendar.setTime(commentTime); commentNode.setProperty(EXO_DATE_COMMENT, calendar); // questionNode.getSession().save(); } questionNode.save(); } protected Value[] booleanToValues(Node node, Boolean[] bools) throws Exception { if (bools == null) return new Value[] { node.getSession().getValueFactory().createValue(true) }; Value[] values = new Value[bools.length]; for (int i = 0; i < values.length; i++) { values[i] = node.getSession().getValueFactory().createValue(bools[i]); } return values; } /** * Removes the language, when question have multi language, and now one of them * is not helpful, and admin or moderator want to delete it, this function will * be called. And this function will do: * <p> * Get all children nodes of question node, and compare them with list language * is inputted in this function. Each language node, if it's name is not contained * in list language, it will be deleted. * <p> * After that, the remains of language nodes will be saved as children node of * question node. * * @param questionNode the question node which have multilanguage * @param listLanguage the list languages will be saved */ public static void removeLanguage(Node questionNode, List<String> listLanguage) { try { if (!questionNode.hasNode(Utils.LANGUAGE_HOME)) return; Node languageNode = questionNode.getNode(Utils.LANGUAGE_HOME); NodeIterator nodeIterator = languageNode.getNodes(); Node node = null; while (nodeIterator.hasNext()) { node = nodeIterator.nextNode(); if (!listLanguage.contains(node.getProperty(EXO_LANGUAGE).getString())) { node.remove(); } } questionNode.getSession().save(); } catch (Exception e) { log.error("Fail to remove language from a list of language: ", e); } } public static void removeLanguage(Node questionNode, QuestionLanguage lang) { try { if (!questionNode.hasNode(Utils.LANGUAGE_HOME)) return; Node languageNode = questionNode.getNode(Utils.LANGUAGE_HOME); languageNode.getNode(lang.getId()).remove(); questionNode.save(); } catch (Exception e) { log.error("Fail to remove language from a question language: ", e); } } public static void voteAnswer(Node answerNode, String userName, boolean isUp) throws Exception { boolean isVoted = false; long mark = 0; List<String> users = new ArrayList<String>(); if (answerNode.hasProperty(EXO_USERS_VOTE_ANSWER) && answerNode.hasProperty(EXO_MARK_VOTES)) { PropertyReader reader = new PropertyReader(answerNode); users = reader.list(EXO_USERS_VOTE_ANSWER, new ArrayList<String>()); mark = reader.l(EXO_MARK_VOTES); int i = 0; for (String user : users) { if (user.indexOf(userName) > -1) { String[] values = user.split("/"); if (values[1].equals("1")) { // up if (!isUp) { mark = mark - 2; users.add(i, userName + "/-1"); } } else { // -1: down if (isUp) { mark = mark + 2; users.add(i, userName + "/1"); } } isVoted = true; break; } i++; } } if (isVoted) { answerNode.setProperty(EXO_USERS_VOTE_ANSWER, users.toArray(new String[] {})); answerNode.setProperty(EXO_MARK_VOTES, mark); } else { List<String> newUsers = users; // if(users.length > 0) newUsers = Arrays.asList(users) ; if (isUp) { mark = mark + 1; newUsers.add(userName + "/1"); } else { mark = mark - 1; newUsers.add(userName + "/-1"); } answerNode.setProperty(EXO_USERS_VOTE_ANSWER, newUsers.toArray(new String[] {})); answerNode.setProperty(EXO_MARK_VOTES, mark); } // System.out.println("mark ==>" + mark); answerNode.save(); } public static void voteQuestion(Node questionNode, String userName, int number) throws Exception { if (questionNode.hasProperty(EXO_MARK_VOTE) && questionNode.hasProperty(EXO_USERS_VOTE)) { double mark = questionNode.getProperty(EXO_MARK_VOTE).getDouble(); List<String> currentUsers = new ArrayList<String>(); currentUsers.addAll(new PropertyReader(questionNode).list(EXO_USERS_VOTE, new ArrayList<String>())); double currentMark = (mark * currentUsers.size() + number) / (currentUsers.size() + 1); currentUsers.add(userName + "/" + number); questionNode.setProperty(EXO_MARK_VOTE, currentMark); questionNode.setProperty(EXO_USERS_VOTE, currentUsers.toArray(new String[] {})); } else { double mark = number; questionNode.setProperty(EXO_MARK_VOTE, mark); questionNode.setProperty(EXO_USERS_VOTE, new String[] { userName + "/" + number }); } questionNode.save(); } public static void unVoteQuestion(Node questionNode, String userName) throws Exception { PropertyReader reader = new PropertyReader(questionNode); List<String> userList = reader.list(EXO_USERS_VOTE, new ArrayList<String>()); List<String> newList = new ArrayList<String>(); double mark = 0; for (String user : userList) { // System.out.println("User ==>" + user); if (user.indexOf(userName + "/") == 0) { int number = Integer.parseInt(user.substring(user.indexOf("/") + 1)); mark = reader.d(EXO_MARK_VOTE); if (userList.size() > 1) { mark = ((mark * userList.size()) - number) / (userList.size() - 1); } else { mark = 0; } } else { newList.add(user); } } // System.out.println("size ==>" + newList.size()); questionNode.setProperty(EXO_MARK_VOTE, mark); questionNode.setProperty(EXO_USERS_VOTE, newList.toArray(new String[newList.size()])); questionNode.save(); } }