. Version History for a document now available in FreeMarker templating model

- new node API method:   document.versionHistory
 - returns a list of objects representing the version history of a document, such as name, created date, properties and content for the version
 - template example to show the version history for a document

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4762 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2007-01-09 13:25:48 +00:00
parent 13e6f22641
commit 5b375cc7a7
2 changed files with 296 additions and 23 deletions

View File

@@ -22,6 +22,7 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -38,6 +39,8 @@ import org.alfresco.service.cmr.audit.AuditInfo;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.lock.LockStatus; import org.alfresco.service.cmr.lock.LockStatus;
import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionHistory;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.QNameMap; import org.alfresco.service.namespace.QNameMap;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
@@ -67,7 +70,7 @@ public class TemplateNode implements Serializable
private static Log logger = LogFactory.getLog(TemplateNode.class); private static Log logger = LogFactory.getLog(TemplateNode.class);
private final static String NAMESPACE_BEGIN = "" + QName.NAMESPACE_BEGIN; private final static String NAMESPACE_BEGIN = "" + QName.NAMESPACE_BEGIN;
private final static String CONTENT_DEFAULT_URL = "/download/direct/{0}/{1}/{2}/{3}"; protected final static String CONTENT_DEFAULT_URL = "/download/direct/{0}/{1}/{2}/{3}";
private final static String CONTENT_PROP_URL = "/download/direct/{0}/{1}/{2}/{3}?property={4}"; private final static String CONTENT_PROP_URL = "/download/direct/{0}/{1}/{2}/{3}?property={4}";
private final static String FOLDER_BROWSE_URL = "/navigate/browse/{0}/{1}/{2}"; private final static String FOLDER_BROWSE_URL = "/navigate/browse/{0}/{1}/{2}";
@@ -84,7 +87,7 @@ public class TemplateNode implements Serializable
private String path; private String path;
private String id; private String id;
private Set<QName> aspects = null; private Set<QName> aspects = null;
private QNameMap<String, Object> properties; private QNameMap<String, Serializable> properties;
private List<String> permissions = null; private List<String> permissions = null;
private boolean propsRetrieved = false; private boolean propsRetrieved = false;
protected ServiceRegistry services = null; protected ServiceRegistry services = null;
@@ -126,7 +129,7 @@ public class TemplateNode implements Serializable
this.services = services; this.services = services;
this.imageResolver = resolver; this.imageResolver = resolver;
this.properties = new QNameMap<String, Object>(this.services.getNamespaceService()); this.properties = new QNameMap<String, Serializable>(this.services.getNamespaceService());
} }
@@ -239,7 +242,7 @@ public class TemplateNode implements Serializable
/** /**
* @return All the properties known about this node. * @return All the properties known about this node.
*/ */
public Map<String, Object> getProperties() public Map<String, Serializable> getProperties()
{ {
if (this.propsRetrieved == false) if (this.propsRetrieved == false)
{ {
@@ -269,6 +272,34 @@ public class TemplateNode implements Serializable
return this.properties; return this.properties;
} }
/**
* @return a list of objects representing the version history of this node.
* @see VersionHistoryNode
*/
public List<VersionHistoryNode> getVersionHistory()
{
List<VersionHistoryNode> records = Collections.<VersionHistoryNode>emptyList();
if (this.getAspects().contains(ContentModel.ASPECT_VERSIONABLE))
{
VersionHistory history = this.services.getVersionService().getVersionHistory(this.nodeRef);
if (history != null)
{
records = new ArrayList<VersionHistoryNode>(8);
for (Version version : history.getAllVersions())
{
// create a wrapper for the version information
VersionHistoryNode record = new VersionHistoryNode(version, this);
// add the client side version to the list
records.add(record);
}
}
}
return records;
}
/** /**
* @return true if this Node is a container (i.e. a folder) * @return true if this Node is a container (i.e. a folder)
*/ */
@@ -415,9 +446,8 @@ public class TemplateNode implements Serializable
*/ */
public String getContent() public String getContent()
{ {
ContentService contentService = this.services.getContentService(); TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
ContentReader reader = contentService.getReader(this.nodeRef, ContentModel.PROP_CONTENT); return content != null ? content.getContent() : "";
return (reader != null && reader.exists()) ? reader.getContentString() : "";
} }
/** /**
@@ -430,25 +460,25 @@ public class TemplateNode implements Serializable
{ {
if (getIsDocument() == true) if (getIsDocument() == true)
{ {
try try
{ {
return MessageFormat.format(CONTENT_DEFAULT_URL, new Object[] { return MessageFormat.format(CONTENT_DEFAULT_URL, new Object[] {
nodeRef.getStoreRef().getProtocol(), nodeRef.getStoreRef().getProtocol(),
nodeRef.getStoreRef().getIdentifier(), nodeRef.getStoreRef().getIdentifier(),
nodeRef.getId(), nodeRef.getId(),
StringUtils.replace(URLEncoder.encode(getName(), "UTF-8"), "+", "%20") } ); StringUtils.replace(URLEncoder.encode(getName(), "UTF-8"), "+", "%20") } );
} }
catch (UnsupportedEncodingException err) catch (UnsupportedEncodingException err)
{ {
throw new TemplateException("Failed to encode content URL for node: " + nodeRef, err); throw new TemplateException("Failed to encode content URL for node: " + nodeRef, err);
} }
} }
else else
{ {
return MessageFormat.format(FOLDER_BROWSE_URL, new Object[] { return MessageFormat.format(FOLDER_BROWSE_URL, new Object[] {
nodeRef.getStoreRef().getProtocol(), nodeRef.getStoreRef().getProtocol(),
nodeRef.getStoreRef().getIdentifier(), nodeRef.getStoreRef().getIdentifier(),
nodeRef.getId() } ); nodeRef.getId() } );
} }
} }

View File

@@ -0,0 +1,243 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.alfresco.service.cmr.repository;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.Date;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.TemplateNode.TemplateContentData;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionType;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.QNameMap;
import org.springframework.util.StringUtils;
/**
* Template Node wrapper representing a record in the version history of a node.
* Provides access to basic properties and version information for the frozen state record.
*
* @author Kevin Roast
*/
public class VersionHistoryNode implements Serializable
{
private QNameMap<String, Serializable> properties;
private boolean propsRetrieved = false;
private Version version;
private TemplateNode parent;
/**
* Constructor
*
* @param version Descriptor of the node version information
*/
public VersionHistoryNode(Version version, TemplateNode parent)
{
if (version == null)
{
throw new IllegalArgumentException("Version history descriptor is mandatory.");
}
if (parent == null)
{
throw new IllegalArgumentException("Parent TemplateNode is mandatory.");
}
this.version = version;
this.parent = parent;
this.properties = new QNameMap<String, Serializable>(parent.services.getNamespaceService());
}
/**
* @return The GUID for the frozen state NodeRef
*/
public String getId()
{
return this.version.getFrozenStateNodeRef().getId();
}
/**
* @return Returns the frozen state NodeRef this record represents
*/
public NodeRef getNodeRef()
{
return this.version.getFrozenStateNodeRef();
}
/**
* @return Returns the type.
*/
public QName getType()
{
return parent.services.getNodeService().getType(this.version.getFrozenStateNodeRef());
}
/**
* Helper method to get the item name.
*
* @return the item name
*/
public String getName()
{
return (String)this.getProperties().get(ContentModel.PROP_NAME);
}
/**
* Helper method to get the created date from the version property data.
*
* @return the date the version was created
*/
public Date getCreatedDate()
{
return this.version.getCreatedDate();
}
/**
* Helper method to get the creator of the version.
*
* @return the creator of the version
*/
public String getCreator()
{
return this.version.getCreator();
}
/**
* Helper method to get the version label from the version property data.
*
* @return the version label
*/
public String getVersionLabel()
{
return this.version.getVersionLabel();
}
/**
* Helper method to get the version type.
*
* @return true if this is a major version, false otherwise.
*/
public boolean getIsMajorVersion()
{
return (this.version.getVersionType() == VersionType.MAJOR);
}
/**
* Helper method to get the version description.
*
* @return the version description
*/
public String getDescription()
{
return this.version.getDescription();
}
/**
* Get the map containing the version property values.
*
* @return the map containing the version properties
*/
public Map<String, Serializable> getProperties()
{
if (propsRetrieved == false)
{
Map<QName, Serializable> props = parent.services.getNodeService().getProperties(
this.version.getFrozenStateNodeRef());
for (QName qname : props.keySet())
{
Serializable propValue = props.get(qname);
if (propValue instanceof NodeRef)
{
// NodeRef object properties are converted to new TemplateNode objects
// so they can be used as objects within a template
propValue = new TemplateNode(((NodeRef)propValue), parent.services, parent.imageResolver);
}
else if (propValue instanceof ContentData)
{
// ContentData object properties are converted to TemplateContentData objects
// so the content and other properties of those objects can be accessed
propValue = parent.new TemplateContentData((ContentData)propValue, qname);
}
this.properties.put(qname.toString(), propValue);
}
propsRetrieved = true;
}
return this.properties;
}
// ------------------------------------------------------------------------------
// Content API
/**
* @return the content String for this node from the default content property
* (@see ContentModel.PROP_CONTENT)
*/
public String getContent()
{
TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
return content != null ? content.getContent() : "";
}
/**
* @return For a content document, this method returns the URL to the content stream for
* the default content property (@see ContentModel.PROP_CONTENT)
* <p>
* For a container node, this method return the URL to browse to the folder in the web-client
*/
public String getUrl()
{
NodeRef nodeRef = this.version.getFrozenStateNodeRef();
try
{
return MessageFormat.format(parent.CONTENT_DEFAULT_URL, new Object[] {
nodeRef.getStoreRef().getProtocol(),
nodeRef.getStoreRef().getIdentifier(),
nodeRef.getId(),
StringUtils.replace(URLEncoder.encode(getName(), "UTF-8"), "+", "%20") } );
}
catch (UnsupportedEncodingException err)
{
throw new TemplateException("Failed to encode content URL for node: " + nodeRef, err);
}
}
/**
* @return The mimetype encoding for content attached to the node from the default content property
* (@see ContentModel.PROP_CONTENT)
*/
public String getMimetype()
{
TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
return (content != null ? content.getMimetype() : null);
}
/**
* @return The size in bytes of the content attached to the node from the default content property
* (@see ContentModel.PROP_CONTENT)
*/
public long getSize()
{
TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
return (content != null ? content.getSize() : 0L);
}
}