/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/rwiki/trunk/rwiki-impl/impl/src/java/uk/ac/cam/caret/sakai/rwiki/component/service/impl/XLSTChangesHandler.java $
* $Id: XLSTChangesHandler.java 84224 2010-11-03 13:43:07Z david.horwitz@uct.ac.za $
***********************************************************************************
*
* Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
*
* Licensed under the Educational Community License, Version 1.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/ecl1.php
*
* 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 uk.ac.cam.caret.sakai.rwiki.component.service.impl;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.entity.api.Entity;
import org.sakaiproject.entity.api.ResourceProperties;
import org.sakaiproject.entity.cover.EntityManager;
import org.sakaiproject.site.api.Site;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import uk.ac.cam.caret.sakai.rwiki.component.Messages;
import uk.ac.cam.caret.sakai.rwiki.service.api.RWikiObjectService;
import uk.ac.cam.caret.sakai.rwiki.service.api.model.RWikiCurrentObject;
import uk.ac.cam.caret.sakai.rwiki.service.api.model.RWikiEntity;
import uk.ac.cam.caret.sakai.rwiki.service.api.model.RWikiHistoryObject;
import uk.ac.cam.caret.sakai.rwiki.service.api.model.RWikiObject;
import uk.ac.cam.caret.sakai.rwiki.utils.DebugContentHandler;
import uk.ac.cam.caret.sakai.rwiki.utils.NameHelper;
import uk.ac.cam.caret.sakai.rwiki.utils.SchemaNames;
import uk.ac.cam.caret.sakai.rwiki.utils.UserDisplayHelper;
/**
* Provides a XSLT Based handler, that outputs the changes on the object.
*
* @author ieb
*/
public class XLSTChangesHandler extends XSLTEntityHandler
{
private static final String RFC822DATE = "EEE, dd MMM yyyy HH:mm:ss Z"; //$NON-NLS-1$
private RWikiObjectService rwikiObjectService = null;
/**
* {@inheritDoc}
*/
public void outputContent(Entity entity, Entity sidebar, HttpServletRequest request,
HttpServletResponse res)
{
if (!isAvailable()) return;
if (!(entity instanceof RWikiEntity)) return;
try
{
Map rheaders = getResponseHeaders();
if (rheaders != null)
{
for (Iterator<Entry<String, String>> i = rheaders.entrySet().iterator(); i.hasNext();)
{
Entry<String, String> entry = i.next();
String name = entry.getKey() ;
String value = entry.getValue();
res.setHeader(name, value);
}
}
ContentHandler opch = getOutputHandler(res.getOutputStream());
ContentHandler ch = null;
if (false)
{
ch = new DebugContentHandler(opch);
}
else
{
ch = opch;
}
Decoded decodedReference = decode(entity.getReference() + getMinorType());
Attributes dummyAttributes = new AttributesImpl();
ch.startDocument();
ch.startElement(SchemaNames.NS_CONTAINER,
SchemaNames.EL_ENTITYSERVICE,
SchemaNames.EL_NSENTITYSERVICE, dummyAttributes);
{
AttributesImpl propA = new AttributesImpl();
propA.addAttribute("", SchemaNames.ATTR_REQUEST_PATH_INFO, //$NON-NLS-1$
SchemaNames.ATTR_REQUEST_PATH_INFO, "string", request //$NON-NLS-1$
.getPathInfo());
propA.addAttribute("", SchemaNames.ATTR_REQUEST_USER, //$NON-NLS-1$
SchemaNames.ATTR_REQUEST_USER, "string", request //$NON-NLS-1$
.getRemoteUser());
propA.addAttribute("", SchemaNames.ATTR_REQUEST_PROTOCOL, //$NON-NLS-1$
SchemaNames.ATTR_REQUEST_PROTOCOL, "string", request //$NON-NLS-1$
.getProtocol());
propA.addAttribute("", SchemaNames.ATTR_REQUEST_SERVER_NAME, //$NON-NLS-1$
SchemaNames.ATTR_REQUEST_SERVER_NAME, "string", request //$NON-NLS-1$
.getServerName());
propA.addAttribute("", SchemaNames.ATTR_REQUEST_SERVER_PORT, //$NON-NLS-1$
SchemaNames.ATTR_REQUEST_SERVER_PORT, "string", String //$NON-NLS-1$
.valueOf(request.getServerPort()));
propA.addAttribute("", SchemaNames.ATTR_REQUEST_REQUEST_URL, //$NON-NLS-1$
SchemaNames.ATTR_REQUEST_REQUEST_URL, "string", String //$NON-NLS-1$
.valueOf(request.getRequestURL()));
propA.addAttribute("", SchemaNames.ATTR_SERVER_URL, //$NON-NLS-1$
SchemaNames.ATTR_SERVER_URL, "string", //$NON-NLS-1$
ServerConfigurationService.getServerUrl());
ch.startElement(SchemaNames.NS_CONTAINER,
SchemaNames.EL_REQUEST_PROPERTIES,
SchemaNames.EL_NSREQUEST_PROPERTIES, propA);
}
addRequestAttributes(ch, request);
addRequestParameters(ch, request);
ch.endElement(SchemaNames.NS_CONTAINER,
SchemaNames.EL_REQUEST_PROPERTIES,
SchemaNames.EL_NSREQUEST_PROPERTIES);
ch.startElement(SchemaNames.NS_CONTAINER, SchemaNames.EL_ENTITY,
SchemaNames.EL_NSENTITY, dummyAttributes);
ch.startElement(SchemaNames.NS_CONTAINER,
SchemaNames.EL_XMLPROPERTIES,
SchemaNames.EL_NSXMLPROPERTIES, dummyAttributes);
ResourceProperties rp = entity.getProperties();
for (Iterator i = rp.getPropertyNames(); i.hasNext();)
{
Object key = i.next();
String name = String.valueOf(key);
String value = String.valueOf(rp.getProperty(name));
AttributesImpl propA = new AttributesImpl();
addPropertyElement(name, value, ch);
}
addPropertyElement("_handler", " XSLTEntity Handler", ch); //$NON-NLS-1$ //$NON-NLS-2$
Site site = (Site) m_siteService.getEntity(EntityManager.newReference(decodedReference.getContext()));
String title;
if (site != null) {
title = site.getTitle();
} else {
title = decodedReference.getContext();
}
addPropertyElement("_siteDisplay", title, ch); //$NON-NLS-1$
addPropertyElement("_container", decodedReference.getContainer(), ch); //$NON-NLS-1$
if (entity instanceof RWikiEntity)
{
RWikiEntity rwe = (RWikiEntity) entity;
if (!rwe.isContainer())
{
RWikiObject rwo = rwe.getRWikiObject();
title = Messages.getString("XLSTChangesHandler.19") + title + ":" + NameHelper.localizeName(rwo.getName(), decodedReference.getContext()); //$NON-NLS-1$ //$NON-NLS-2$
}
else
{
if (decodedReference.getContainer() != null && decodedReference.getContainer().length() > 1) {
title = Messages.getString("XLSTChangesHandler.21") + title + ":" + decodedReference.getContainer().substring(1); //$NON-NLS-1$ //$NON-NLS-2$
} else {
title = Messages.getString("XLSTChangesHandler.23") + title; //$NON-NLS-1$
}
}
addPropertyElement("_title", title, ch); //$NON-NLS-1$
}
{
addPropertyElement("_description", ServerConfigurationService.getString("ui.service"), ch); //$NON-NLS-1$ //$NON-NLS-2$
}
{
// 2006-02-16T18:28:03+01:00
SimpleDateFormat sd = new SimpleDateFormat(
RFC822DATE);
addPropertyElement("_datestamp", sd //$NON-NLS-1$
.format(new Date()), ch);
}
ch.endElement(SchemaNames.NS_CONTAINER,
SchemaNames.EL_XMLPROPERTIES,
SchemaNames.EL_NSXMLPROPERTIES);
if (entity instanceof RWikiEntity)
{
RWikiEntity rwe = (RWikiEntity) entity;
if (!rwe.isContainer())
{
RWikiObject rwo = rwe.getRWikiObject();
ch.startElement(SchemaNames.NS_CONTAINER,
SchemaNames.EL_RENDEREDCONTENT,
SchemaNames.EL_NSRENDEREDCONTENT, dummyAttributes);
renderToXML(rwo, ch, true, true);
ch.endElement(SchemaNames.NS_CONTAINER,
SchemaNames.EL_RENDEREDCONTENT,
SchemaNames.EL_NSRENDEREDCONTENT);
ch.startElement(SchemaNames.NS_CONTAINER,
SchemaNames.EL_CHANGES, SchemaNames.EL_NSCHANGES,
dummyAttributes);
changeHistoryToXML(rwo, ch);
ch.endElement(SchemaNames.NS_CONTAINER,
SchemaNames.EL_CHANGES, SchemaNames.EL_NSCHANGES);
}
else
{
ch.startElement(SchemaNames.NS_CONTAINER,
SchemaNames.EL_CHANGES, SchemaNames.EL_NSCHANGES,
dummyAttributes);
recentChangesToXML(rwe, ch);
ch.endElement(SchemaNames.NS_CONTAINER,
SchemaNames.EL_CHANGES, SchemaNames.EL_NSCHANGES);
}
}
ch.endElement(SchemaNames.NS_CONTAINER, SchemaNames.EL_ENTITY,
SchemaNames.EL_NSXMLSERVICE);
ch.endElement(SchemaNames.NS_CONTAINER,
SchemaNames.EL_ENTITYSERVICE, SchemaNames.EL_NSXMLSERVICE);
ch.endDocument();
}
catch (Exception ex)
{
ex.printStackTrace();
throw new RuntimeException("Failed to serialise " //$NON-NLS-1$
+ ex.getLocalizedMessage(), ex);
}
}
private void addPropertyElement(String property, String value, ContentHandler ch) throws SAXException
{
AttributesImpl propA = new AttributesImpl();
propA.addAttribute("", SchemaNames.ATTR_NAME, //$NON-NLS-1$
SchemaNames.ATTR_NAME, "string", property); //$NON-NLS-1$
addElement(ch, SchemaNames.NS_CONTAINER,
SchemaNames.EL_XMLPROPERTY,
SchemaNames.EL_NSXMLPROPERTY, propA,
value);
}
public void changeHistoryToXML(RWikiObject rwo, ContentHandler ch)
throws Exception
{
if (!isAvailable()) return;
String name = rwo.getName();
String localSpace = NameHelper.localizeSpace(name);
String aliasSpace;
// use alias if available
if (m_siteAlias) {
aliasSpace = NameHelper.aliasSpace(localSpace);
} else {
aliasSpace = localSpace;
}
// output current version as well
AttributesImpl propA = new AttributesImpl();
propA.addAttribute("", SchemaNames.ATTR_ID, SchemaNames.ATTR_ID, //$NON-NLS-1$
"string", rwo.getId()); //$NON-NLS-1$
String pageName = NameHelper.localizeName(name, localSpace);
name = aliasSpace + "/" + pageName;
// FIXME why do we know about "@" here?!
propA.addAttribute("", SchemaNames.ATTR_NAME, //$NON-NLS-1$
SchemaNames.ATTR_NAME, "string", name + "@" //$NON-NLS-1$ //$NON-NLS-2$
+ rwo.getRevision());
propA.addAttribute("", SchemaNames.ATTR_LOCAL_NAME, //$NON-NLS-1$
SchemaNames.ATTR_LOCAL_NAME, "string", NameHelper //$NON-NLS-1$
.localizeName(rwo.getName(), rwo.getRealm()));
propA.addAttribute("", SchemaNames.ATTR_OWNER, //$NON-NLS-1$
SchemaNames.ATTR_OWNER, "string", rwo.getOwner()); //$NON-NLS-1$
propA.addAttribute("", SchemaNames.ATTR_OWNER, //$NON-NLS-1$
SchemaNames.ATTR_REALM, "string", rwo.getRealm()); //$NON-NLS-1$
propA.addAttribute("", SchemaNames.ATTR_REFERENCED, //$NON-NLS-1$
SchemaNames.ATTR_REFERENCED, "string", rwo //$NON-NLS-1$
.getReferenced());
propA.addAttribute("", SchemaNames.ATTR_SHA1, //$NON-NLS-1$
SchemaNames.ATTR_SHA1, "string", rwo.getSha1()); //$NON-NLS-1$
propA.addAttribute("", SchemaNames.ATTR_USER, //$NON-NLS-1$
SchemaNames.ATTR_USER, "string", rwo.getUser()); //$NON-NLS-1$
propA.addAttribute("", SchemaNames.ATTR_DISPLAY_USER, //$NON-NLS-1$
SchemaNames.ATTR_DISPLAY_USER, "string", UserDisplayHelper //$NON-NLS-1$
.formatDisplayName(rwo.getUser(), rwo.getRealm()));
propA.addAttribute("", SchemaNames.ATTR_REVISION, //$NON-NLS-1$
SchemaNames.ATTR_REVISION, "string", String.valueOf(rwo //$NON-NLS-1$
.getRevision()));
SimpleDateFormat sd = new SimpleDateFormat(RFC822DATE);
propA.addAttribute("", SchemaNames.ATTR_LAST_CHANGE, //$NON-NLS-1$
SchemaNames.ATTR_LAST_CHANGE, "string", sd.format(rwo //$NON-NLS-1$
.getVersion()));
ch.startElement(SchemaNames.NS_CONTAINER, SchemaNames.EL_CHANGE,
SchemaNames.EL_NSCHANGE, propA);
renderToXML(rwo, ch,true,true);
ch.endElement(SchemaNames.NS_CONTAINER, SchemaNames.EL_CHANGE,
SchemaNames.EL_NSCHANGE);
// end of output current version
List changes = rwikiObjectService.findRWikiHistoryObjectsInReverse(rwo);
if (changes == null) return;
for (Iterator i = changes.iterator(); i.hasNext();)
{
RWikiHistoryObject rwco = (RWikiHistoryObject) i.next();
propA = new AttributesImpl();
propA.addAttribute("", SchemaNames.ATTR_ID, SchemaNames.ATTR_ID, //$NON-NLS-1$
"string", rwco.getId()); //$NON-NLS-1$
name = rwco.getName();
pageName = NameHelper.localizeName(name, localSpace);
name = aliasSpace + "/" + pageName;
// FIXME why do we know about "@" here?!
propA.addAttribute("", SchemaNames.ATTR_NAME, //$NON-NLS-1$
SchemaNames.ATTR_NAME, "string", name + "@" //$NON-NLS-1$ //$NON-NLS-2$
+ rwco.getRevision());
propA.addAttribute("", SchemaNames.ATTR_LOCAL_NAME, //$NON-NLS-1$
SchemaNames.ATTR_LOCAL_NAME, "string", NameHelper //$NON-NLS-1$
.localizeName(rwo.getName(), rwo.getRealm()));
propA.addAttribute("", SchemaNames.ATTR_OWNER, //$NON-NLS-1$
SchemaNames.ATTR_OWNER, "string", rwco.getOwner()); //$NON-NLS-1$
propA.addAttribute("", SchemaNames.ATTR_OWNER, //$NON-NLS-1$
SchemaNames.ATTR_REALM, "string", rwco.getRealm()); //$NON-NLS-1$
propA.addAttribute("", SchemaNames.ATTR_REFERENCED, //$NON-NLS-1$
SchemaNames.ATTR_REFERENCED, "string", rwco //$NON-NLS-1$
.getReferenced());
propA.addAttribute("", SchemaNames.ATTR_SHA1, //$NON-NLS-1$
SchemaNames.ATTR_SHA1, "string", rwco.getSha1()); //$NON-NLS-1$
propA.addAttribute("", SchemaNames.ATTR_USER, //$NON-NLS-1$
SchemaNames.ATTR_USER, "string", rwco.getUser()); //$NON-NLS-1$
propA.addAttribute("", SchemaNames.ATTR_DISPLAY_USER, //$NON-NLS-1$
SchemaNames.ATTR_DISPLAY_USER, "string", UserDisplayHelper //$NON-NLS-1$
.formatDisplayName(rwco.getUser(), rwco.getRealm()));
propA.addAttribute("", SchemaNames.ATTR_REVISION, //$NON-NLS-1$
SchemaNames.ATTR_REVISION, "string", String.valueOf(rwco //$NON-NLS-1$
.getRevision()));
propA.addAttribute("", SchemaNames.ATTR_LAST_CHANGE, //$NON-NLS-1$
SchemaNames.ATTR_LAST_CHANGE, "string", sd.format(rwco //$NON-NLS-1$
.getVersion()));
ch.startElement(SchemaNames.NS_CONTAINER, SchemaNames.EL_CHANGE,
SchemaNames.EL_NSCHANGE, propA);
renderToXML(rwco, ch, true, true);
ch.endElement(SchemaNames.NS_CONTAINER, SchemaNames.EL_CHANGE,
SchemaNames.EL_NSCHANGE);
}
}
public void recentChangesToXML(RWikiEntity rwe, ContentHandler ch)
throws Exception
{
if (!isAvailable()) return;
GregorianCalendar g = new GregorianCalendar();
g.setTime(new Date());
g.add(GregorianCalendar.YEAR, -1);
Decoded d = decode(rwe.getReference() + getMinorType());
String basepath = d.getContext() + d.getContainer();
List changes = rwikiObjectService.findAllChangedSince(g.getTime(),
basepath);
int nchanges = 0;
for (Iterator i = changes.iterator(); i.hasNext() && nchanges < 20;)
{
nchanges++;
RWikiCurrentObject rwco = (RWikiCurrentObject) i.next();
AttributesImpl propA = new AttributesImpl();
propA.addAttribute("", SchemaNames.ATTR_ID, SchemaNames.ATTR_ID, //$NON-NLS-1$
"string", rwco.getId()); //$NON-NLS-1$
propA.addAttribute("", SchemaNames.ATTR_NAME, //$NON-NLS-1$
SchemaNames.ATTR_NAME, "string", rwco.getName()); //$NON-NLS-1$
propA.addAttribute("", SchemaNames.ATTR_LOCAL_NAME, //$NON-NLS-1$
SchemaNames.ATTR_LOCAL_NAME, "string", NameHelper //$NON-NLS-1$
.localizeName(rwco.getName(), rwco.getRealm()));
propA.addAttribute("", SchemaNames.ATTR_OWNER, //$NON-NLS-1$
SchemaNames.ATTR_OWNER, "string", rwco.getOwner()); //$NON-NLS-1$
propA.addAttribute("", SchemaNames.ATTR_REALM, //$NON-NLS-1$
SchemaNames.ATTR_REALM, "string", rwco.getRealm()); //$NON-NLS-1$
propA
.addAttribute("", SchemaNames.ATTR_REFERENCED, //$NON-NLS-1$
SchemaNames.ATTR_REFERENCED, "string", rwco //$NON-NLS-1$
.getReferenced());
propA.addAttribute("", SchemaNames.ATTR_SHA1, //$NON-NLS-1$
SchemaNames.ATTR_SHA1, "string", rwco.getSha1()); //$NON-NLS-1$
propA.addAttribute("", SchemaNames.ATTR_USER, //$NON-NLS-1$
SchemaNames.ATTR_USER, "string", rwco.getUser()); //$NON-NLS-1$
propA.addAttribute("", SchemaNames.ATTR_DISPLAY_USER, //$NON-NLS-1$
SchemaNames.ATTR_DISPLAY_USER, "string", UserDisplayHelper //$NON-NLS-1$
.formatDisplayName(rwco.getUser(), rwco.getRealm()));
propA.addAttribute("", SchemaNames.ATTR_REVISION, //$NON-NLS-1$
SchemaNames.ATTR_REVISION, "string", String.valueOf(rwco //$NON-NLS-1$
.getRevision()));
SimpleDateFormat sd = new SimpleDateFormat(RFC822DATE);
propA.addAttribute("", SchemaNames.ATTR_LAST_CHANGE, //$NON-NLS-1$
SchemaNames.ATTR_LAST_CHANGE, "string", sd.format(rwco //$NON-NLS-1$
.getVersion()));
ch.startElement(SchemaNames.NS_CONTAINER, SchemaNames.EL_CHANGE,
SchemaNames.EL_NSCHANGE, propA);
renderToXML(rwco, ch, true, true);
ch.endElement(SchemaNames.NS_CONTAINER, SchemaNames.EL_CHANGE,
SchemaNames.EL_NSCHANGE);
}
}
/**
* @return Returns the rwikiObjectService.
*/
public RWikiObjectService getRwikiObjectService()
{
return rwikiObjectService;
}
/**
* @param rwikiObjectService
* The rwikiObjectService to set.
*/
public void setRwikiObjectService(RWikiObjectService rwikiObjectService)
{
this.rwikiObjectService = rwikiObjectService;
}
}