/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/portal/trunk/portal-impl/impl/src/java/org/sakaiproject/portal/charon/SessionRequestHolder.java $
* $Id: SessionRequestHolder.java 14690 2006-09-15 11:43:18Z ian@caret.cam.ac.uk $
***********************************************************************************
*
* Copyright (c) 2006, 2007, 2008 The Sakai Foundation
*
* Licensed under the Educational Community 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.opensource.org/licenses/ECL-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.sakaiproject.search.component.adapter.message;
import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.component.cover.ComponentManager;
import org.sakaiproject.entity.api.EntityManager;
import org.sakaiproject.entity.api.EntityProducer;
import org.sakaiproject.entity.api.Reference;
import org.sakaiproject.event.api.Event;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.exception.PermissionException;
import org.sakaiproject.message.api.Message;
import org.sakaiproject.message.api.MessageChannel;
import org.sakaiproject.message.api.MessageHeader;
import org.sakaiproject.message.api.MessageService;
import org.sakaiproject.search.api.EntityContentProducer;
import org.sakaiproject.search.api.SearchIndexBuilder;
import org.sakaiproject.search.api.SearchService;
import org.sakaiproject.search.api.SearchUtils;
import org.sakaiproject.search.model.SearchBuilderItem;
import org.sakaiproject.search.util.HTMLParser;
import org.sakaiproject.site.api.SiteService;
import org.sakaiproject.user.api.ContextualUserDisplayService;
import org.sakaiproject.util.ResourceLoader;
import org.sakaiproject.javax.PagingPosition;
/**
* @author ieb
*/
public class MessageContentProducer implements EntityContentProducer
{
private static final String BUNDLE_NAME = "org.sakaiproject.search.component.adapter.message.bundle.Messages"; //$NON-NLS-1$
private static final ResourceLoader RESOURCE_BUNDLE = new ResourceLoader(BUNDLE_NAME);
/**
* debug logger
*/
private static Log log = LogFactory.getLog(MessageContentProducer.class);
// runtime dependency
private String toolName = null;
// runtime dependency
private List addEvents = null;
// runtime dependency
private List removeEvents = null;
// injected dependency
private MessageService messageService = null;
// injected dependency
private SearchService searchService = null;
// injected dependency
private SearchIndexBuilder searchIndexBuilder = null;
// injected dependency
private EntityManager entityManager = null;
// injected dependency
private ServerConfigurationService serverConfigurationService;
//injected dependency
private SiteService siteService;
//ContextualDisplayService
ContextualUserDisplayService contextualUserDisplayService;
public void init()
{
if ("true".equals(serverConfigurationService.getString("search.enable", "false")))
{
for (Iterator i = addEvents.iterator(); i.hasNext();)
{
searchService.registerFunction((String) i.next());
}
for (Iterator i = removeEvents.iterator(); i.hasNext();)
{
searchService.registerFunction((String) i.next());
}
searchIndexBuilder.registerEntityContentProducer(this);
}
contextualUserDisplayService = (ContextualUserDisplayService) ComponentManager.get("org.sakaiproject.user.api.ContextualUserDisplayService");
}
/**
* {@inheritDoc}
*/
public boolean isContentFromReader(String reference)
{
return false;
}
/**
* {@inheritDoc}
*/
public Reader getContentReader(String reference)
{
return new StringReader(getContent(reference));
}
private Reference getReference(String reference)
{
try
{
Reference r = entityManager.newReference(reference);
if (log.isDebugEnabled())
{
log.debug("Message." + toolName + ".getReference" + reference + ":" + r);
}
return r;
}
catch (Exception ex)
{
log.debug(ex);
}
return null;
}
private EntityProducer getProducer(Reference ref)
{
try
{
return ref.getEntityProducer();
}
catch (Exception ex)
{
log.debug(ex);
}
return null;
}
/**
* {@inheritDoc}
*/
public String getContent(String reference)
{
Reference ref = getReference(reference);
EntityProducer ep = getProducer(ref);
if (ep instanceof MessageService)
{
try
{
MessageService ms = (MessageService) ep;
Message m = ms.getMessage(ref);
MessageHeader mh = m.getHeader();
StringBuilder sb = new StringBuilder();
Class c = mh.getClass();
try
{
Method getSubject = c.getMethod("getSubject", //$NON-NLS-1$
new Class[] {});
Object o = getSubject.invoke(mh, new Object[] {});
sb.append(RESOURCE_BUNDLE.getString("MessageContentProducer.5"));
SearchUtils.appendCleanString(o.toString(), sb);
sb.append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
}
catch (Exception ex)
{
// no subject, and I dont mind
log.debug("Didnt get Subject from " + mh, ex); //$NON-NLS-1$
}
sb.append(RESOURCE_BUNDLE.getString("MessageContentProducer.3")); //$NON-NLS-1$
sb.append(RESOURCE_BUNDLE.getString("MessageContentProducer.4"));
//is the user aliased in this context?
String displayName = null;
if (contextualUserDisplayService != null)
{
Reference ref1 = entityManager.newReference(m.getReference());
String context = siteService.siteReference(ref1.getContext());
displayName = contextualUserDisplayService.getUserDisplayName(mh.getFrom(), context);
//the service may return a null
if (displayName == null)
displayName = mh.getFrom().getDisplayName();
}
else
{
displayName = mh.getFrom().getDisplayName();
}
SearchUtils.appendCleanString(displayName, sb); //$NON-NLS-1$
sb.append("\n"); //$NON-NLS-1$
sb.append(RESOURCE_BUNDLE.getString("MessageContentProducer.11")); //$NON-NLS-1$
String mBody = m.getBody();
for (HTMLParser hp = new HTMLParser(mBody); hp.hasNext();)
{
SearchUtils.appendCleanString(hp.next(), sb);
sb.append(" ");
}
sb.append("\n"); //$NON-NLS-1$
log.debug("Message Content for " + ref.getReference() + " is " //$NON-NLS-1$ //$NON-NLS-2$
+ sb.toString());
// resolve attachments
List attachments = mh.getAttachments();
for (Iterator atti = attachments.iterator(); atti.hasNext();)
{
try
{
Reference attr = (Reference) atti.next();
String areference = attr.getReference();
EntityContentProducer ecp = searchIndexBuilder
.newEntityContentProducer(areference);
String attachementDigest = ecp.getContent(areference);
sb
.append(
RESOURCE_BUNDLE
.getString("MessageContentProducer.23")).append(attachementDigest) //$NON-NLS-1$
.append("\n"); //$NON-NLS-1$
}
catch (Exception ex)
{
log.info(" Failed to digest attachement " //$NON-NLS-1$
+ ex.getMessage());
}
}
String r = sb.toString();
if (log.isDebugEnabled())
{
log
.debug("Message." + toolName + ".getContent" + reference
+ ":" + r);
}
return r;
}
catch (IdUnusedException e)
{
throw new RuntimeException(" Failed to get message content ", e); //$NON-NLS-1$
}
catch (PermissionException e)
{
throw new RuntimeException(" Failed to get message content ", e); //$NON-NLS-1$
}
}
throw new RuntimeException(" Not a Message Entity " + reference); //$NON-NLS-1$
}
/**
* @{inheritDoc}
*/
public String getTitle(String reference)
{
Reference ref = getReference(reference);
EntityProducer ep = getProducer(ref);
if (ep instanceof MessageService)
{
try
{
MessageService ms = (MessageService) ep;
Message m = ms.getMessage(ref);
MessageHeader mh = m.getHeader();
Class c = mh.getClass();
String subject = RESOURCE_BUNDLE.getString("MessageContentProducer.2"); //$NON-NLS-1$
try
{
Method getSubject = c.getMethod("getSubject", //$NON-NLS-1$
new Class[] {});
Object o = getSubject.invoke(mh, new Object[] {});
subject = RESOURCE_BUNDLE.getString("MessageContentProducer.33") + o.toString() + " "; //$NON-NLS-1$ //$NON-NLS-2$
}
catch (Exception ex)
{
log.debug("Didnt get Subject from " + mh); //$NON-NLS-1$
}
//is the user aliased in this context?
String displayName = null;
if (contextualUserDisplayService != null)
{
Reference ref1 = entityManager.newReference(m.getReference());
String context = siteService.siteReference(ref1.getContext());
displayName = contextualUserDisplayService.getUserDisplayName(mh.getFrom(), context);
//the service may return a null
if (displayName == null)
displayName = mh.getFrom().getDisplayName();
}
else
{
displayName = mh.getFrom().getDisplayName();
}
String title = subject
+ RESOURCE_BUNDLE.getString("MessageContentProducer.36") //$NON-NLS-1$
+ displayName;
String r = SearchUtils.appendCleanString(title, null).toString();
if (log.isDebugEnabled())
{
log.debug("Message." + toolName + ".getTitle" + reference + ":" + r);
}
return r;
}
catch (IdUnusedException e)
{
throw new RuntimeException(" Failed to get message content ", e); //$NON-NLS-1$
}
catch (PermissionException e)
{
throw new RuntimeException(" Failed to get message content ", e); //$NON-NLS-1$
}
}
throw new RuntimeException(" Not a Message Entity " + reference); //$NON-NLS-1$
}
/**
* @{inheritDoc}
*/
public String getUrl(String reference)
{
Reference ref = getReference(reference);
return ref.getUrl();
}
/**
* @{inheritDoc}
*/
public boolean matches(String reference)
{
Reference ref = getReference(reference);
EntityProducer ep = getProducer(ref);
if (ep != null && ep.getClass().equals(messageService.getClass()))
{
return true;
}
return false;
}
/**
* @{inheritDoc}
*/
public Integer getAction(Event event)
{
String evt = event.getEvent();
if (evt == null) return SearchBuilderItem.ACTION_UNKNOWN;
for (Iterator i = addEvents.iterator(); i.hasNext();)
{
String match = (String) i.next();
if (evt.equals(match))
{
return SearchBuilderItem.ACTION_ADD;
}
}
for (Iterator i = removeEvents.iterator(); i.hasNext();)
{
String match = (String) i.next();
if (evt.equals(match))
{
return SearchBuilderItem.ACTION_DELETE;
}
}
return SearchBuilderItem.ACTION_UNKNOWN;
}
/**
* @{inheritDoc}
*/
public boolean matches(Event event)
{
return matches(event.getResource());
}
/**
* @{inheritDoc}
*/
public String getTool()
{
return toolName;
}
/**
* @return Returns the addEvents.
*/
public List getAddEvents()
{
return addEvents;
}
/**
* @param addEvents
* The addEvents to set.
*/
public void setAddEvents(List addEvents)
{
this.addEvents = addEvents;
}
/**
* @return Returns the messageService.
*/
public MessageService getMessageService()
{
return messageService;
}
/**
* @param messageService
* The messageService to set.
*/
public void setMessageService(MessageService messageService)
{
this.messageService = messageService;
}
/**
* @return Returns the toolName.
*/
public String getToolName()
{
return toolName;
}
/**
* @param toolName
* The toolName to set.
*/
public void setToolName(String toolName)
{
this.toolName = toolName;
}
/**
* @return Returns the removeEvents.
*/
public List getRemoveEvents()
{
return removeEvents;
}
/**
* @param removeEvents
* The removeEvents to set.
*/
public void setRemoveEvents(List removeEvents)
{
this.removeEvents = removeEvents;
}
private String getSiteId(Reference ref)
{
return ref.getContext();
}
public String getSiteId(String resourceName)
{
return getSiteId(entityManager.newReference(resourceName));
}
public List getSiteContent(String context)
{
List<String> all = new ArrayList<String>();
List l = messageService.getChannelIds(context);
for (Iterator i = l.iterator(); i.hasNext();)
{
String chanellId = (String) i.next();
try
{
MessageChannel c = messageService.getChannel(messageService
.channelReference(context, chanellId));
List messages = c.getMessages(null, true);
// WARNING: I think the implementation caches on thread, if this
// is
// a builder
// thread this may not work
for (Iterator mi = messages.iterator(); mi.hasNext();)
{
Message m = (Message) mi.next();
all.add(m.getReference());
}
}
catch (Exception ex)
{
ex.printStackTrace();
log.warn("Failed to get channel " + chanellId); //$NON-NLS-1$
}
}
return all;
}
public Iterator getSiteContentIterator(final String context)
{
List l = messageService.getChannelIds(context);
final Iterator ci = l.iterator();
return new Iterator()
{
MessageChannel mc = null;
int messageCount = -1;
int nextMessage = -1; // Index overall messages - Starts at 1
List messages = null;
int listPos = 0; // Index each chunk - Starts at zero
int chunkSize = 100; // Retrieve 100 at a time
public boolean hasNext()
{
if (mc == null)
{
return nextIterator();
}
else
{
if (messageCount > 1 && nextMessage <= messageCount)
{
return true;
}
else
{
return nextIterator();
}
}
}
private boolean nextIterator()
{
while (ci.hasNext())
{
String chanellId = (String) ci.next();
try
{
mc = messageService.getChannel(messageService
.channelReference(context, chanellId));
messageCount = mc.getCount();
if (messageCount > 0 )
{
nextMessage = 1; // Pager starts at 1
return true;
}
}
catch (Exception ex)
{
ex.printStackTrace();
log.warn("Failed to get channel " + chanellId); //$NON-NLS-1$
}
}
mc = null;
nextMessage = -1;
messageCount = -1;
return false;
}
/*
* Loop though the messages in the channel grabbing them
* in chunkSize chunks for efficiency.
*/
public Object next()
{
if ( messages != null && listPos >= 0 && listPos < messages.size() )
{
Message m = (Message) messages.get(listPos);
nextMessage = nextMessage + 1;
listPos = listPos + 1;
return m.getReference();
}
// Retrieve the next "chunk"
PagingPosition pages = new PagingPosition(nextMessage, (nextMessage + chunkSize - 1));
try
{
messages = mc.getMessages(null, true, pages);
if ( messages != null && messages.size() > 0 )
{
listPos = 0;
Message m = (Message) messages.get(listPos);
nextMessage = nextMessage + 1;
listPos = listPos + 1;
return m.getReference();
}
}
catch (Exception ex)
{
ex.printStackTrace();
log.warn("Failed to get message " + nextMessage); //$NON-NLS-1$
}
// We are done looping through this channel
nextMessage = messageCount + 1;
return null;
}
public void remove()
{
throw new UnsupportedOperationException("Remove not implemented"); //$NON-NLS-1$
}
};
}
public boolean isForIndex(String reference)
{
Reference ref = getReference(reference);
EntityProducer ep = getProducer(ref);
if (ep instanceof MessageService)
{
try
{
MessageService ms = (MessageService) ep;
Message m = ms.getMessage(ref);
if (m == null)
{
log.debug("Rejected null message " + ref.getReference()); //$NON-NLS-1$
return false;
}
}
catch (IdUnusedException e)
{
log.debug("Rejected Missing message or Collection " //$NON-NLS-1$
+ ref.getReference());
return false;
}
catch (PermissionException e)
{
log.warn("Rejected private message " + ref.getReference()); //$NON-NLS-1$
return false;
}
return true;
}
return false;
}
public boolean canRead(String reference)
{
Reference ref = getReference(reference);
EntityProducer ep = getProducer(ref);
if (ep instanceof MessageService)
{
try
{
MessageService ms = (MessageService) ep;
ms.getMessage(ref);
return true;
}
catch (Exception ex)
{
log.debug(ex);
}
}
return false;
}
public Map getCustomProperties(String ref)
{
return null;
}
public String getCustomRDF(String ref)
{
return null;
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.search.api.EntityContentProducer#getId(java.lang.String)
*/
public String getId(String reference)
{
try
{
String r = getReference(reference).getId();
if (log.isDebugEnabled())
{
log.debug("Message." + toolName + ".getContainer" + reference + ":" + r);
}
return r;
}
catch (Exception ex)
{
return "";
}
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.search.api.EntityContentProducer#getSubType(java.lang.String)
*/
public String getSubType(String reference)
{
try
{
String r = getReference(reference).getSubType();
if (log.isDebugEnabled())
{
log.debug("Message." + toolName + ".getContainer" + reference + ":" + r);
}
return r;
}
catch (Exception ex)
{
return "";
}
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.search.api.EntityContentProducer#getType(java.lang.String)
*/
public String getType(String reference)
{
try
{
String r = getReference(reference).getType();
if (log.isDebugEnabled())
{
log.debug("Message." + toolName + ".getContainer" + reference + ":" + r);
}
return r;
}
catch (Exception ex)
{
return "";
}
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.search.api.EntityContentProducer#getType(java.lang.String)
*/
public String getContainer(String reference)
{
try
{
String r = getReference(reference).getContainer();
if (log.isDebugEnabled())
{
log.debug("Message." + toolName + ".getContainer" + reference + ":" + r);
}
return r;
}
catch (Exception ex)
{
return "";
}
}
/**
* @return the entityManager
*/
public EntityManager getEntityManager()
{
return entityManager;
}
/**
* @param entityManager
* the entityManager to set
*/
public void setEntityManager(EntityManager entityManager)
{
this.entityManager = entityManager;
}
/**
* @return the searchIndexBuilder
*/
public SearchIndexBuilder getSearchIndexBuilder()
{
return searchIndexBuilder;
}
/**
* @param searchIndexBuilder
* the searchIndexBuilder to set
*/
public void setSearchIndexBuilder(SearchIndexBuilder searchIndexBuilder)
{
this.searchIndexBuilder = searchIndexBuilder;
}
/**
* @return the searchService
*/
public SearchService getSearchService()
{
return searchService;
}
/**
* @param searchService
* the searchService to set
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* @return the serverConfigurationService
*/
public ServerConfigurationService getServerConfigurationService()
{
return serverConfigurationService;
}
/**
* @param serverConfigurationService
* the serverConfigurationService to set
*/
public void setServerConfigurationService(
ServerConfigurationService serverConfigurationService)
{
this.serverConfigurationService = serverConfigurationService;
}
public void setSiteService(SiteService siteService) {
this.siteService = siteService;
}
}