/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.contrib.mailarchive.internal.data;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.commons.lang.StringUtils;
import org.codehaus.plexus.util.ExceptionUtils;
import org.slf4j.Logger;
import org.xwiki.component.annotation.Component;
import org.xwiki.component.manager.ComponentManager;
import org.xwiki.component.phase.Initializable;
import org.xwiki.component.phase.InitializationException;
import org.xwiki.contrib.mailarchive.IMASource;
import org.xwiki.contrib.mailarchive.IMailArchiveConfiguration;
import org.xwiki.contrib.mailarchive.IMailMatcher;
import org.xwiki.contrib.mailarchive.IMailingList;
import org.xwiki.contrib.mailarchive.IMailingListGroup;
import org.xwiki.contrib.mailarchive.IType;
import org.xwiki.contrib.mailarchive.LoadingSession;
import org.xwiki.contrib.mailarchive.exceptions.MailArchiveException;
import org.xwiki.contrib.mailarchive.xwiki.IExtendedDocumentAccessBridge;
import org.xwiki.contrib.mailarchive.xwiki.internal.XWikiPersistence;
import org.xwiki.query.Query;
import org.xwiki.query.QueryManager;
import org.xwiki.text.XWikiToStringBuilder;
/**
* @version $Id$
*/
@Component
@Singleton
public class MailArchiveConfiguration implements IMailArchiveConfiguration, Initializable
{
private static final String CLASS_ADMIN = XWikiPersistence.SPACE_CODE + ".AdminClass";
private String adminPrefsPage;
/* ***** GLOBAL PARAMETERS ***** */
private List<IMASource> servers;
private Map<String, IMailingList> lists;
private Map<String, IMailingListGroup> mailingListGroups;
private Map<String, IType> types;
private Map<String, LoadingSession> loadingSessions;
private String loadingUser;
private String defaultHomeView;
private String defaultTopicsView;
private String defaultMailsOpeningMode;
private boolean manageTimeline;
private int maxTimelineItemsToLoad;
private boolean matchProfiles;
private boolean matchLdap;
private boolean ldapCreateMissingProfiles;
private boolean ldapForcePhotoUpdate;
private String ldapPhotoFieldName;
private String ldapPhotoFieldContent;
private boolean cropTopicIds;
private String itemsSpaceName;
private boolean useStore;
private String emailIgnoredText;
private boolean noLdMatch;
// Components
@Inject
private QueryManager queryManager;
@Inject
private Logger logger;
@Inject
private IFactory factory;
@Inject
@Named("extended")
private IExtendedDocumentAccessBridge bridge;
@Inject
private ComponentManager componentManager;
/*
* @Inject private IMailArchive mailArchive;
*/
/**
* {@inheritDoc}
*
* @see org.xwiki.component.phase.Initializable#initialize()
*/
@Override
public void initialize() throws InitializationException
{
logger.debug("initialize()");
this.adminPrefsPage = XWikiPersistence.SPACE_PREFS + ".GlobalParameters";
}
@Override
public void reloadConfiguration() throws MailArchiveException
{
if (!bridge.exists(adminPrefsPage)) {
throw new MailArchiveException("Preferences page does not exist");
}
this.loadingUser = bridge.getStringValue(adminPrefsPage, CLASS_ADMIN, "user");
this.defaultHomeView = bridge.getStringValue(adminPrefsPage, CLASS_ADMIN, "defaulthomeview");
this.defaultTopicsView = bridge.getStringValue(adminPrefsPage, CLASS_ADMIN, "defaulttopicsview");
this.defaultMailsOpeningMode = bridge.getStringValue(adminPrefsPage, CLASS_ADMIN, "mailsopeningmode");
this.manageTimeline = bridge.getBooleanValue(adminPrefsPage, CLASS_ADMIN, "timeline");
this.maxTimelineItemsToLoad = bridge.getIntValue(adminPrefsPage, CLASS_ADMIN, "timelinemaxload");
this.matchProfiles = bridge.getBooleanValue(adminPrefsPage, CLASS_ADMIN, "matchwikiprofiles");
this.matchLdap = bridge.getBooleanValue(adminPrefsPage, CLASS_ADMIN, "matchldap");
this.ldapCreateMissingProfiles = bridge.getBooleanValue(adminPrefsPage, CLASS_ADMIN, "createmissingprofiles");
this.ldapForcePhotoUpdate = bridge.getIntValue(adminPrefsPage, CLASS_ADMIN, "ldapphotoforceupdate") != 0;
this.ldapPhotoFieldName = bridge.getStringValue(adminPrefsPage, CLASS_ADMIN, "ldapphotofield");
this.ldapPhotoFieldContent = bridge.getStringValue(adminPrefsPage, CLASS_ADMIN, "ldapphototype");
this.cropTopicIds = bridge.getBooleanValue(adminPrefsPage, CLASS_ADMIN, "adv_croptopicid");
this.itemsSpaceName = bridge.getStringValue(adminPrefsPage, CLASS_ADMIN, "adv_itemsspace");
this.useStore = bridge.getBooleanValue(adminPrefsPage, CLASS_ADMIN, "store");
this.noLdMatch = bridge.getBooleanValue(adminPrefsPage, CLASS_ADMIN, "noldmatch");
// TODO test, load only "on demand" and not everything everytime, just load params everytime
/*List<IMASource> sources = loadServersDefinitions();
sources.addAll(loadStoresDefinitions());
this.servers = sources;
this.lists = loadMailingListsDefinitions();
this.mailingListGroups = loadMailingListGroupsDefinitions();
this.types = loadMailTypesDefinitions();
this.loadingSessions = loadLoadingSessions();
*/
if (logger.isDebugEnabled()) {
logger.debug("loaded mail archive configuration: " + toString());
}
}
/**
* Loads the mailing-lists definitions.
*
* @return A map of mailing-lists definitions with key being the mailing-list pattern to check, and value an array
* [displayName, Tag]
* @throws MailArchiveException
*/
protected HashMap<String, IMailingList> loadMailingListsDefinitions() throws MailArchiveException
{
logger.debug("Loading configured mailing-lists");
final HashMap<String, IMailingList> lists = new HashMap<String, IMailingList>();
String xwql =
"select list.pattern, list.displayname, list.Tag, list.color from Document doc, doc.object('"
+ XWikiPersistence.CLASS_MAIL_LISTS + "') as list where doc.space='" + XWikiPersistence.SPACE_PREFS
+ "'";
try {
List<Object[]> props = this.queryManager.createQuery(xwql, Query.XWQL).execute();
for (Object[] prop : props) {
if (StringUtils.isNotBlank((String) prop[0])) {
IMailingList list =
factory.createMailingList((String) prop[0], (String) prop[1], (String) prop[2],
(String) prop[3]);
lists.put(list.getDisplayName(), list);
logger.info("Loaded list " + list);
} else {
logger.warn("Incorrect mailing-list found in db " + prop[1]);
}
}
} catch (Exception e) {
throw new MailArchiveException("Failed to load configured mailing-lists", e);
}
logger.debug("Loaded {} mailing-lists from configuration", lists.size());
return lists;
}
/**
* Loads the mailing-lists definitions.
*
* @return A map of mailing-lists definitions with key being the mailing-list pattern to check, and value an array
* [name, IMailingListItem]
* @throws MailArchiveException
*/
protected HashMap<String, IMailingListGroup> loadMailingListGroupsDefinitions() throws MailArchiveException
{
logger.debug("Loading mailing-list groups configuration");
final HashMap<String, IMailingListGroup> listgroups = new HashMap<String, IMailingListGroup>();
String xwql =
"select listgroup.name, listgroup.mailingLists, listgroup.loadingUser, listgroup.destinationWiki, listgroup.destinationSpace from Document doc, doc.object('"
+ XWikiPersistence.CLASS_MAIL_LIST_GROUPS
+ "') as listgroup where doc.space='"
+ XWikiPersistence.SPACE_PREFS + "'";
try {
List<Object[]> props = this.queryManager.createQuery(xwql, Query.XWQL).execute();
for (Object[] prop : props) {
final String mailingListGroupName = (String) prop[0];
final String loadingUser = (String) prop[2];
final String destinationWiki = (String) prop[3];
final String destinationSpace = (String) prop[4];
List<IMailingList> mailingListItems = new ArrayList<IMailingList>();
if (StringUtils.isNotBlank(mailingListGroupName)) {
logger.debug("Searching mailing-lists for group {}", mailingListGroupName);
final String mailingListsString = (String) prop[1];
if (StringUtils.isNotBlank(mailingListsString)) {
String[] splittedList = mailingListsString.split("|");
if (splittedList.length > 0) {
for (String list : splittedList) {
if (this.getMailingLists().containsKey(list)) {
final MailingList mailingListItem = (MailingList) this.getMailingLists().get(list);
mailingListItems.add(mailingListItem);
logger.debug("Added list {}", mailingListItem.getDisplayName());
}
}
}
}
IMailingListGroup listgroup =
factory.createMailingListGroup(mailingListGroupName, mailingListItems, loadingUser,
destinationWiki, destinationSpace);
listgroups.put(listgroup.getName(), listgroup);
// Attach the group back to each mailing-list
for (IMailingList list : listgroup.getMailingLists()) {
((MailingList) list).setGroup(listgroup);
}
logger.debug("Loaded list group {}", listgroup);
} else {
logger.warn("Incorrect mailing-list group {}", prop[1]);
}
}
} catch (Exception e) {
throw new MailArchiveException("Failed to load configured mailing-list groups",
ExceptionUtils.getRootCause(e));
}
logger.debug("Loaded {} mailing-list groups from configuration", listgroups.size());
return listgroups;
}
/**
* Loads mail types from database.
*
* @return A map of mail types definitions, key of map entries being the type name, and value the IType
* representation.
* @throws MailArchiveException
*/
protected Map<String, IType> loadMailTypesDefinitions() throws MailArchiveException
{
logger.debug("Loading mail types");
Map<String, IType> mailTypes = new HashMap<String, IType>();
String xwql =
"select type.id, type.name, type.icon, doc.fullName from Document doc, doc.object("
+ XWikiPersistence.CLASS_MAIL_TYPES + ") as type where doc.space='" + XWikiPersistence.SPACE_PREFS
+ "' and type.id<>'mail' and type.id<>'calendar' and type.id<>'attachedMail'";
try {
List<Object[]> types = this.queryManager.createQuery(xwql, Query.XWQL).execute();
for (Object[] type : types) {
try {
IType typeobj = factory.createMailType((String) type[0], (String) type[1], (String) type[2]);
logger.debug("Loaded type {}", typeobj);
if (typeobj != null) {
logger.debug("Loading matchers for type");
xwql =
"select matcher.fields, matcher.expression, matcher.isAdvanced, matcher.isIgnoreCase, matcher.isMultiLine "
+ "from Document doc, doc.object(" + XWikiPersistence.CLASS_MAIL_MATCHERS
+ ") as matcher where " + "doc.fullName='" + (String) type[3] + "'";
List<Object[]> matchers = this.queryManager.createQuery(xwql, Query.XWQL).execute();
for (Object[] matcher : matchers) {
logger.debug("FIELDS " + matcher[0] + " " + matcher[0].getClass());
IMailMatcher matcherobj =
factory.createMailMatcher((String) matcher[0], (String) matcher[1],
(Integer) matcher[2], (Integer) matcher[3], (Integer) matcher[4]);
typeobj.getMatchers().add(matcherobj);
logger.debug("Loaded matcher {}", matcherobj);
}
mailTypes.put(typeobj.getId(), typeobj);
logger.debug("Loaded mail type {}", typeobj);
} else {
logger.warn("Invalid type {}", type[0]);
}
} catch (Exception e) {
logger.warn("Failed to load type", ExceptionUtils.getRootCause(e));
}
}
} catch (Exception e) {
throw new MailArchiveException("Failed to load configured mail types", e);
}
logger.debug("Loaded {} types from configuration", mailTypes.size());
return mailTypes;
}
/**
* Loads the mailing-lists
*
* @return
* @throws MailArchiveException
*/
protected List<IMASource> loadServersDefinitions() throws MailArchiveException
{
logger.debug("Loading servers from configuration");
final List<IMASource> servers = new ArrayList<IMASource>();
String xwql =
"select doc.fullName from Document doc, doc.object(" + XWikiPersistence.CLASS_MAIL_SERVERS
+ ") as server where doc.space='" + XWikiPersistence.SPACE_PREFS + "'";
try {
List<String> props = this.queryManager.createQuery(xwql, Query.XWQL).execute();
for (String serverPrefsDoc : props) {
logger.debug("Loading server definition from page " + serverPrefsDoc + " ...");
if (StringUtils.isNotBlank(serverPrefsDoc)) {
Server server = factory.createMailServer(serverPrefsDoc);
if (server != null) {
servers.add(server);
logger.debug("Loaded IServer connection definition {}", server);
} else {
logger.warn("Invalid server definition from document {}", serverPrefsDoc);
}
} else {
logger.info("Incorrect server preferences doc skipped");
}
}
} catch (Exception e) {
throw new MailArchiveException("Failed to load configured servers", e);
}
logger.debug("Loaded {} servers from configuration", servers.size());
return servers;
}
/**
* Loads the mailing-lists
*
* @return
* @throws MailArchiveException
*/
protected List<IMASource> loadStoresDefinitions() throws MailArchiveException
{
logger.debug("Loading stores from configuration");
final List<IMASource> stores = new ArrayList<IMASource>();
String xwql =
"select doc.fullName from Document doc, doc.object(" + XWikiPersistence.CLASS_MAIL_STORES
+ ") as store where doc.space='" + XWikiPersistence.SPACE_PREFS + "'";
try {
List<String> props = this.queryManager.createQuery(xwql, Query.XWQL).execute();
for (String storePrefsDoc : props) {
logger.debug("Loading store definition from page " + storePrefsDoc + " ...");
if (StringUtils.isNotBlank(storePrefsDoc)) {
MailStore store = factory.createMailStore(storePrefsDoc);
if (store != null) {
stores.add(store);
logger.debug("Loaded IServer connection definition {}", store);
} else {
logger.warn("Invalid server definition from document {}", storePrefsDoc);
}
} else {
logger.info("Incorrect IServer preferences doc");
}
}
} catch (Exception e) {
throw new MailArchiveException("Failed to load configured mail stores", e);
}
logger.debug("Loaded {} stores from configuration", stores.size());
return stores;
}
protected Map<String, LoadingSession> loadLoadingSessions() throws MailArchiveException
{
logger.debug("Loading loading sessions from configuration");
final Map<String, LoadingSession> sessions = new HashMap<String, LoadingSession>();
final String xwql =
"select doc.fullName from Document doc, doc.object(" + XWikiPersistence.CLASS_LOADING_SESSION
+ ") as session where doc.space='" + XWikiPersistence.SPACE_PREFS + "'";
try {
List<String> props = this.queryManager.createQuery(xwql, Query.XWQL).execute();
for (String sessionPrefsDoc : props) {
logger.debug("Loading loading session from page {} ...");
if (StringUtils.isNotBlank(sessionPrefsDoc)) {
// FIXME: ugly trick - MailArchiveConfiguration should not depend on IMailArchive...
LoadingSession session = factory.createLoadingSession(sessionPrefsDoc);
if (session != null) {
sessions.put(session.getId(), session);
logger.debug("Loaded Loading Session definition {}" + session);
} else {
logger.warn("Invalid loading session definition from document {}", sessionPrefsDoc);
}
} else {
logger.info("Incorrect LoadingSession preferences doc");
}
}
} catch (Exception e) {
throw new MailArchiveException("Failed to load configured loading sessions", e);
}
logger.debug("Loaded {} loading sessions from configuration", sessions.size());
return sessions;
}
@Override
public String getLoadingUser()
{
return loadingUser;
}
@Override
public String getDefaultHomeView()
{
return defaultHomeView;
}
@Override
public String getDefaultTopicsView()
{
return defaultTopicsView;
}
@Override
public String getDefaultMailsOpeningMode()
{
return defaultMailsOpeningMode;
}
@Override
public boolean isManageTimeline()
{
return manageTimeline;
}
@Override
public int getMaxTimelineItemsToLoad()
{
return maxTimelineItemsToLoad;
}
@Override
public boolean isMatchProfiles()
{
return matchProfiles;
}
@Override
public boolean isMatchLdap()
{
return matchLdap;
}
@Override
public boolean isLdapCreateMissingProfiles()
{
return ldapCreateMissingProfiles;
}
@Override
public boolean isLdapForcePhotoUpdate()
{
return ldapForcePhotoUpdate;
}
@Override
public String getLdapPhotoFieldName()
{
return ldapPhotoFieldName;
}
@Override
public String getLdapPhotoFieldContent()
{
return ldapPhotoFieldContent;
}
@Override
public boolean isCropTopicIds()
{
return cropTopicIds;
}
public void setCropTopicIds(boolean cropTopicIds)
{
this.cropTopicIds = cropTopicIds;
}
@Override
public String getItemsSpaceName()
{
return itemsSpaceName;
}
public void setItemsSpaceName(String itemsSpaceName)
{
this.itemsSpaceName = itemsSpaceName;
}
@Override
public boolean isUseStore()
{
return useStore;
}
public void setUseStore(boolean useStore)
{
this.useStore = useStore;
}
@Override
public boolean isNoLdMatch()
{
return noLdMatch;
}
public void setNoLdMatch(boolean noLdMatch)
{
this.noLdMatch = noLdMatch;
}
/**
* {@inheritDoc}
*
* @see org.xwiki.contrib.mailarchive.IMailArchiveConfiguration#getMailingLists()
*/
@Override
public Map<String, IMailingList> getMailingLists()
{
try {
this.lists = loadMailingListsDefinitions();
} catch (MailArchiveException e) {
logger.warn("Failed to load mailing-lists definitions {}", ExceptionUtils.getRootCause(e));
}
return this.lists;
}
/**
* @return the mailingListGroups
*/
@Override
public Map<String, IMailingListGroup> getMailingListGroups()
{
try {
this.mailingListGroups = loadMailingListGroupsDefinitions();
} catch (MailArchiveException e) {
logger.warn("Failed to load mailing-lists groups definitions {}", ExceptionUtils.getRootCause(e));
}
return mailingListGroups;
}
/**
* {@inheritDoc}
*
* @see org.xwiki.contrib.mailarchive.IMailArchiveConfiguration#getServers()
*/
@Override
public List<IMASource> getServers()
{
try {
List<IMASource> sources = loadServersDefinitions();
sources.addAll(loadStoresDefinitions());
this.servers = sources;
} catch (MailArchiveException e) {
logger.warn("Failed to load sources definitions {}", ExceptionUtils.getRootCause(e));
}
return this.servers;
}
/**
* {@inheritDoc}
*
* @see org.xwiki.contrib.mailarchive.IMailArchiveConfiguration#getMailTypes()
*/
@Override
public Map<String, IType> getMailTypes()
{
try {
this.types = loadMailTypesDefinitions();
} catch (MailArchiveException e) {
logger.warn("Failed to load types definitions {}", ExceptionUtils.getRootCause(e));
}
return this.types;
}
@Override
public Map<String, LoadingSession> getLoadingSessions()
{
try {
this.loadingSessions = loadLoadingSessions();
} catch (MailArchiveException e) {
logger.warn("Failed to load types definitions {}", ExceptionUtils.getRootCause(e));
}
return this.loadingSessions;
}
/**
* @return The page from which configuration is retrieved.
*/
@Override
public String getAdminPrefsPage()
{
return adminPrefsPage;
}
/**
* Update page to load configuration from, and triggers a reload of configuration from this page.
*
* @param adminPrefsPage
* @throws MailArchiveException
*/
public void setAdminPrefsPage(String adminPrefsPage) throws MailArchiveException
{
this.adminPrefsPage = adminPrefsPage;
reloadConfiguration();
}
@Override
public String getEmailIgnoredText()
{
return emailIgnoredText;
}
public void setEmailIgnoredText(String emailIgnoredText)
{
this.emailIgnoredText = emailIgnoredText;
}
@Override
public String toString()
{
XWikiToStringBuilder builder = new XWikiToStringBuilder(this);
if (adminPrefsPage != null)
builder.append("adminPrefsPage", adminPrefsPage);
if (servers != null)
builder.append("servers", servers);
if (lists != null)
builder.append("lists", lists);
if (mailingListGroups != null)
builder.append("mailingListGroups", mailingListGroups);
if (types != null)
builder.append("types", types);
if (loadingSessions != null)
builder.append("loadingSessions", loadingSessions);
if (loadingUser != null)
builder.append("loadingUser", loadingUser);
if (defaultHomeView != null)
builder.append("defaultHomeView", defaultHomeView);
if (defaultTopicsView != null)
builder.append("defaultTopicsView", defaultTopicsView);
if (defaultMailsOpeningMode != null)
builder.append("defaultMailsOpeningMode", defaultMailsOpeningMode);
builder.append("manageTimeline", manageTimeline);
builder.append("maxTimelineItemsToLoad", maxTimelineItemsToLoad);
builder.append("matchProfiles", matchProfiles);
builder.append("matchLdap", matchLdap);
builder.append("ldapCreateMissingProfiles", ldapCreateMissingProfiles);
builder.append("ldapForcePhotoUpdate", ldapForcePhotoUpdate);
if (ldapPhotoFieldName != null)
builder.append("ldapPhotoFieldName", ldapPhotoFieldName);
if (ldapPhotoFieldContent != null)
builder.append("ldapPhotoFieldContent", ldapPhotoFieldContent);
builder.append("cropTopicIds", cropTopicIds);
if (itemsSpaceName != null)
builder.append("itemsSpaceName", itemsSpaceName);
builder.append("useStore", useStore);
if (emailIgnoredText != null)
builder.append("emailIgnoredText", emailIgnoredText);
builder.append("noLdMatch", noLdMatch);
return builder.toString();
}
}