/* * Copyright 2010 - 2012 Interactive Media Management * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 dk.i2m.converge.jsf.beans; import dk.i2m.converge.core.DataNotFoundException; import dk.i2m.converge.core.content.ContentTag; import dk.i2m.converge.core.newswire.NewswireBasket; import dk.i2m.converge.core.newswire.NewswireItem; import dk.i2m.converge.core.newswire.NewswireService; import dk.i2m.converge.core.security.SystemPrivilege; import dk.i2m.converge.core.security.UserAccount; import dk.i2m.converge.core.workflow.Outlet; import dk.i2m.converge.domain.search.SearchResult; import dk.i2m.converge.domain.search.SearchResults; import dk.i2m.converge.ejb.facades.*; import dk.i2m.converge.ejb.services.NewswireServiceLocal; import dk.i2m.converge.jsf.components.tags.DialogAssignment; import dk.i2m.converge.jsf.components.tags.DialogEventSelection; import dk.i2m.jsf.JsfUtils; import static dk.i2m.jsf.JsfUtils.createMessage; import java.text.MessageFormat; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.PostConstruct; import javax.ejb.EJB; import javax.faces.application.FacesMessage; import javax.faces.event.ActionEvent; import javax.faces.model.DataModel; import javax.faces.model.ListDataModel; /** * Request-scoped backing bean for the {@code Newswire.jspx} page. * * @author Allan Lykke Christensen */ public class Newswire { private static final Logger LOG = Logger.getLogger(Newswire.class.getName()); @EJB private NewswireServiceLocal newswireService; @EJB private OutletFacadeLocal outletFacade; @EJB private UserFacadeLocal userFacade; @EJB private CalendarFacadeLocal calendarFacade; @EJB private NewsItemFacadeLocal newsItemFacade; @EJB private WorkflowFacadeLocal workflowFacade; @EJB private MetaDataFacadeLocal metaDataFacade; private NewswireService selectedService; private DataModel newsService = null; private DataModel news = null; private NewswireItem selectedItem = null; private NewswireBasket selectedBasket = null; private DialogAssignment dialogAssignment; private DialogEventSelection dialogEventSelection; private String keyword = ""; private DataModel searchResults = new ListDataModel(); private DataModel pages = new ListDataModel(new ArrayList()); private boolean showResults = false; private long resultsFound = 0; private String sortField = "score"; private String sortOrder = "false"; private boolean displayContentTags = false; private int show = 30; private String searchPhrase = ""; private String basketTag = ""; private SearchResults results = new SearchResults(); private List<String> filterQueries = new ArrayList<String>(); private DataModel baskets = null; private Map<String, NewswireService> availableNewswireServices = null; private String linkSearch = ""; @PostConstruct public void onInit() { displayContentTags = getUserAccount().isDefaultSearchEngineTags(); onShowTodaysNews(null); } /** * Event handler for showing todays news of the current user. * * @param event * Event that invoked the handler */ public void onShowTodaysNews(ActionEvent event) { getFilterQueries().clear(); setSortField("date"); setSortOrder("false"); // Ignore search if user hasn't subscribed to any services if (getUserAccount().getActiveNewswireServices().isEmpty()) { searchResults = new ListDataModel(new ArrayList()); pages = new ListDataModel(new ArrayList()); return; } StringBuilder query = new StringBuilder(); for (NewswireService service : getUserAccount().getActiveNewswireServices()) { if (query.length() > 0) { query.append(" || "); } else { query.append("("); } query.append("provider-id:").append(service.getId()); } if (query.length() > 0) { query.append(") && "); } query.append("date:[NOW-1DAY TO NOW]"); this.keyword = query.toString(); filterQueries.clear(); conductSearch(this.keyword, 0, getShow()); } public void onNewBasket(ActionEvent event) { this.basketTag = ""; java.util.Calendar now = java.util.Calendar.getInstance(); this.selectedBasket = new NewswireBasket(); this.selectedBasket.setTitle("Untitled"); this.selectedBasket.setCreated(now.getTime()); this.selectedBasket.setUpdated(now.getTime()); this.selectedBasket.setOwner(getUserAccount()); this.selectedBasket.setMailDelivery(false); this.selectedBasket.setMailFrequency(8); this.selectedBasket.setHourFirstDelivery(8); } public void onSaveBasket(ActionEvent event) { this.basketTag = ""; if (this.selectedBasket != null) { if (this.selectedBasket.getId() == null) { this.selectedBasket = newswireService.createBasket(selectedBasket); } else { this.selectedBasket = newswireService.updateBasket(selectedBasket); } } this.baskets = null; } /** * Dispatches the current basket as an e-mail. * * @param event Event that invoked the handler */ public void onDispatchBasket(ActionEvent event) { if (newswireService.dispatchBasket(selectedBasket.getId())) { createMessage("frmPage", FacesMessage.SEVERITY_INFO, Bundle.i18n.name(), "Newswire_BASKET_DISPATCHED"); } else { createMessage("frmPage", FacesMessage.SEVERITY_WARN, Bundle.i18n.name(), "Newswire_BASKET_EMPTY_NOT_DISPATCHED", new Object[]{selectedBasket.getMailFrequency()}); } } public void setDeleteTag(ContentTag tag) { getSelectedBasket().getTags().remove(tag); } public void onDeleteBasket(ActionEvent event) { if (this.selectedBasket != null) { newswireService.deleteBasket(selectedBasket); } this.baskets = null; } public void onAddTagSuggestion(ActionEvent event) { if (selectedBasket != null) { ContentTag tag = metaDataFacade.findOrCreateContentTag(basketTag); selectedBasket.getTags().add(tag); } this.basketTag = ""; } public List<ContentTag> onTagSuggestion(Object suggestion) { String tagName = (String) suggestion; List<ContentTag> suggested = metaDataFacade.findContentTagLikeName(tagName); return suggested; } /** * Gets the {@link DataModel} containing the current news items of the newswire services. * * @return {@link DataModel} containing the current news items of the newswire services. */ public DataModel getNews() { if (news == null) { news = new ListDataModel(newswireService.getNews()); } return news; } public DataModel getServices() { if (newsService == null) { newsService = new ListDataModel(getUserAccount().getActiveNewswireServices()); } return newsService; } public Map<String, NewswireService> getAvailableServices() { if (availableNewswireServices == null) { availableNewswireServices = new LinkedHashMap<String, NewswireService>(); List<NewswireService> services = newswireService.findAvailableNewswireServices(getUserAccount().getId()); for (NewswireService s : services) { availableNewswireServices.put(s.getSource(), s); } } return availableNewswireServices; } public DataModel getBaskets() { if (baskets == null) { baskets = new ListDataModel(newswireService.findBasketsByUser(getUserAccount().getId())); } return baskets; } public NewswireService getSelectedService() { return selectedService; } public void setSelectedService(NewswireService selectedService) { this.selectedService = selectedService; } public void onSelectService(ActionEvent event) { if (selectedService != null) { Long id = selectedService.getId(); setSortField("date"); setSortOrder("false"); setKeyword("*:*"); getFilterQueries().clear(); getFilterQueries().add("provider-id:" + selectedService.getId()); conductSearch(getKeyword(), 0, getShow()); } } public void onSelectBasket(ActionEvent event) { if (selectedBasket != null) { setSortField("date"); setSortOrder("false"); setKeyword(""); getFilterQueries().clear(); setKeyword(selectedBasket.getQuery()); conductSearch(getKeyword(), 0, getShow()); } } public void onClear(ActionEvent event) { setKeyword(""); getFilterQueries().clear(); results = null; searchResults = null; pages = null; } public void onShowAll(ActionEvent event) { news = new ListDataModel(newswireService.getNews()); } private UserAccount getUserAccount() { final String valueExpression = "#{userSession.user}"; return (UserAccount) JsfUtils.getValueOfValueExpression(valueExpression); } public NewswireItem getSelectedItem() { return selectedItem; } public void setSelectedItem(NewswireItem selectedItem) { this.selectedItem = selectedItem; } public NewswireBasket getSelectedBasket() { return selectedBasket; } public void setSelectedBasket(NewswireBasket selectedBasket) { this.selectedBasket = selectedBasket; } public void setSelectedSearchResult(SearchResult searchResult) { try { setSelectedItem(newswireService.findNewswireItemById(searchResult.getId())); } catch (DataNotFoundException ex) { JsfUtils.createMessage("frmPage", FacesMessage.SEVERITY_ERROR, Bundle.i18n.name(), "Newswire_STORY_NOT_FOUND"); } } public void setRemoveItem(SearchResult searchResult) { newswireService.removeItem(searchResult.getId()); } /** * Event handler for saving selected newswire subscriptions. * * @param event * Event that invoked the handler */ public void onSaveSubscriptions(ActionEvent event) { userFacade.update(getUserAccount()); // Reset list of current subscriptions newsService = null; // Refresh todays news onShowTodaysNews(event); JsfUtils.createMessage("frmPage", FacesMessage.SEVERITY_INFO, Bundle.i18n.name(), "Newswire_MY_NEWSWIRE_SUBSCRIPTIONS_UPDATED"); } public void onAssign(ActionEvent event) { dialogAssignment = new DialogAssignment(outletFacade, workflowFacade, userFacade, newsItemFacade, calendarFacade, getOutlets()); dialogAssignment.showStoryTab(); dialogAssignment.getAssignment().setAssigned(true); dialogAssignment.getAssignment().setAssignedBy(getUserAccount()); if (getUserAccount().getDefaultOutlet() != null) { dialogAssignment.getAssignment().setOutlet(getUserAccount().getDefaultOutlet()); } else if (!getOutlets().isEmpty()) { dialogAssignment.getAssignment().setOutlet(getOutlets().iterator().next()); } dialogAssignment.getAssignment().setTitle(selectedItem.getTitle()); dialogAssignment.getAssignment().setBrief(selectedItem.getSummary()); dialogAssignment.getAssignment().setStory(selectedItem.getContent()); if (selectedItem.getAuthor() != null && !selectedItem.getAuthor().trim().isEmpty()) { dialogAssignment.getAssignment().setByLine(selectedItem.getAuthor()); } else { dialogAssignment.getAssignment().setByLine(selectedItem.getNewswireService().getSource()); } dialogAssignment.onChangeOutlet(null); dialogAssignment.getAssignment().setDeadline(java.util.Calendar.getInstance()); dialogAssignment.getAssignment().getDeadline().setTimeZone(getUserAccount().getTimeZone()); dialogAssignment.getAssignment().getDeadline().set(java.util.Calendar.HOUR_OF_DAY, 15); dialogAssignment.getAssignment().getDeadline().set(java.util.Calendar.MINUTE, 0); dialogAssignment.getAssignment().getDeadline().set(java.util.Calendar.SECOND, 0); dialogEventSelection = new DialogEventSelection(calendarFacade); dialogEventSelection.setAssignment(dialogAssignment.getAssignment()); } /** * Gets a {@link List} of the {@link Outlet}s where the current user has * outlet planning privileges. * * @return {@link List} of the {@link Outlet}s where the current user has * outlet planning privileges */ public List<Outlet> getOutlets() { return getUserAccount().getPrivilegedOutlets(SystemPrivilege.OUTLET_PLANNING); } public DialogAssignment getDialogAssignment() { return dialogAssignment; } public void setDialogAssignment(DialogAssignment dialogAssignment) { this.dialogAssignment = dialogAssignment; } public DialogEventSelection getDialogEventSelection() { return dialogEventSelection; } public void setDialogEventSelection(DialogEventSelection dialogEventSelection) { this.dialogEventSelection = dialogEventSelection; } public List<String> getFilterQueries() { return filterQueries; } public void setFilterQueries(List<String> filterQueries) { this.filterQueries = filterQueries; } /** * Gets the keyword (query) being searched for. * * @return Keyword (query) being searched for */ public String getKeyword() { return keyword; } /** * Sets the keyword (query) to be searched for. * * @param keyword * Keyword (query) to be searched for */ public void setKeyword(String keyword) { this.keyword = keyword; } /** * Gets the search results. * * @return {@link DataModel} containing the {@link SearchResult}s */ public DataModel getSearchResults() { return searchResults; } /** * Determines if the results should be shown. * * @return {@code true} if the search results should be shown otherwise * {@code false} */ public boolean isShowResults() { return showResults; } public String getBasketTag() { return basketTag; } public void setBasketTag(String basketTag) { this.basketTag = basketTag; } /** * Event handler for starting the search. * * @param event * Event that invoked the handler */ public void onSearch(ActionEvent event) { if (!getKeyword().trim().isEmpty()) { conductSearch(keyword, 0, getShow()); } } public void onChangePage(ActionEvent event) { String changePage = JsfUtils.getRequestParameterMap().get("changePage"); if (changePage != null) { int newPage = Integer.valueOf(changePage); int newStart = (newPage - 1) * results.getResultsPerPage(); int rows = results.getResultsPerPage(); conductSearch(keyword, newStart, rows); } } public void onAddFacet(ActionEvent event) { String filterQuery = JsfUtils.getRequestParameterMap().get("addFacet"); if (filterQuery != null) { filterQueries.add(filterQuery); conductSearch(keyword, 0, getShow()); } } public void onRemoveFacet(ActionEvent event) { String filterQuery = JsfUtils.getRequestParameterMap().get("filterQuery"); if (filterQuery != null) { filterQueries.remove(filterQuery); conductSearch(keyword, 0, getShow()); } } private void conductSearch(String keyword, int start, int rows) { searchResults = new ListDataModel(new ArrayList()); pages = new ListDataModel(new ArrayList()); List<String> filters = new ArrayList<String>(); filters.addAll(filterQueries); if (keyword.equalsIgnoreCase("")) { keyword = "*:*"; this.keyword = "*:*"; } this.results = newswireService.search(keyword, start, rows, sortField, Boolean.valueOf(sortOrder), filters.toArray(new String[filters.size()])); if (results.getNumberOfResults() == 0) { showResults = false; searchResults = new ListDataModel(new ArrayList()); JsfUtils.createMessage("frmPage", FacesMessage.SEVERITY_INFO, Bundle.i18n.name(), "Newswire_NO_RESULTS_FOUND_FOR_X", new Object[]{getKeyword()}); } else { for (SearchResult hit : results.getHits()) { hit.setLink(MessageFormat.format(hit.getLink(), new Object[]{JsfUtils.getValueOfValueExpression("#{facesContext.externalContext.request.contextPath}")})); } searchResults = new ListDataModel(results.getHits()); for (long l = 0; l < results.getNumberOfPages(); l++) { if (l >= 20) { break; } SearchPage page = new SearchPage((l + 1), l * results.getResultsPerPage(), results.getNumberOfPages()); ((ArrayList) getPages().getWrappedData()).add(page); } showResults = true; } } public long getResultsFound() { return resultsFound; } public SearchResults getResults() { return results; } public void setResults(SearchResults results) { this.results = results; } public DataModel getPages() { return pages; } public void setPages(DataModel pages) { this.pages = pages; } public String getSortField() { return sortField; } public void setSortField(String sortField) { this.sortField = sortField; } public String getSortOrder() { return sortOrder; } public void setSortOrder(String sortOrder) { this.sortOrder = sortOrder; } public int getShow() { return show; } public void setShow(int show) { this.show = show; } public String getLinkSearch() { return linkSearch; } public void setLinkSearch(String linkSearch) { this.linkSearch = linkSearch; if (this.linkSearch != null) { this.keyword = linkSearch; onSearch(null); } } public class SearchPage { private long page = 1; private long start = 0; private long show = 0; public SearchPage(long page, long start, long show) { this.page = page; this.start = start; this.show = show; } public long getPage() { return page; } public void setPage(long page) { this.page = page; } public long getShow() { return show; } public void setShow(long show) { this.show = show; } public long getStart() { return start; } public void setStart(long start) { this.start = start; } } public boolean isDisplayContentTags() { return displayContentTags; } public void setDisplayContentTags(boolean displayContentTags) { this.displayContentTags = displayContentTags; } }