UIDiff.java
/*
* Copyright (C) 2003-2007 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero 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 org.exoplatform.ecm.webui.component.explorer.versions;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Locale;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.version.Version;
import javax.jcr.version.VersionHistory;
import org.apache.commons.lang.StringUtils;
import org.exoplatform.commons.diff.DiffResult;
import org.exoplatform.commons.diff.DiffService;
import org.exoplatform.ecm.webui.component.explorer.UIDocumentWorkspace;
import org.exoplatform.ecm.webui.utils.Utils;
import org.exoplatform.portal.webui.util.Util;
import org.exoplatform.services.document.DocumentReader;
import org.exoplatform.services.document.DocumentReaderService;
import org.exoplatform.services.document.HandlerNotFoundException;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.wcm.utils.WCMCoreUtils;
import org.exoplatform.webui.config.annotation.ComponentConfig;
import org.exoplatform.webui.config.annotation.EventConfig;
import org.exoplatform.webui.core.UIComponent;
import org.exoplatform.webui.event.Event;
import org.exoplatform.webui.event.EventListener;
/**
* Created by The eXo Platform SARL Author : Pham Tuan tuan.pham@exoplatform.com
* May 3, 2007
*/
@ComponentConfig(template = "app:/groovy/webui/component/explorer/versions/UIDiff.gtmpl", events = {
@EventConfig(listeners = UIDiff.CompareActionListener.class),
@EventConfig(listeners = UIDiff.CloseCompareActionListener.class) })
public class UIDiff extends UIComponent {
private static final String EXO_LAST_MODIFIED_DATE = "exo:lastModifiedDate";
private static final Log LOG = ExoLogger.getLogger(UIDiff.class.getName());
public static final String FROM_PARAM = "from";
public static final String TO_PARAM = "to";
private String baseVersionName_;
private String baseVersionDate_;
private String baseVersionAuthor_;
private String baseVersionLabel_;
private String versionName_;
private String versionDate_;
private String versionAuthor_;
private String versionLabel_;
private String previousText_ = null;
private String currentText_ = null;
private boolean versionCompareable_ = true;
private String diffResultHTML_ = null;
private boolean isImage_ = false;
private String baseImage_ = null;
private String currentImage_ = null;
public void setVersions(Node baseVersion, Node version) throws Exception {
UIDocumentWorkspace uiDocumentWorkspace = getAncestorOfType(UIDocumentWorkspace.class);
UIVersionInfo uiVersionInfo = uiDocumentWorkspace.getChild(UIVersionInfo.class);
versionCompareable_ = baseVersion != null && version != null && !baseVersion.getUUID().equals(version.getUUID());
if (!versionCompareable_) {
throw new IllegalStateException("Can't compare both versions");
} else {
Node versionRootVersion = null;
if (version instanceof Version) {
versionRootVersion = ((Version) version).getContainingHistory().getRootVersion();
} else {
versionRootVersion = version.getVersionHistory().getRootVersion();
}
Node baseVersionRootVersion = null;
if (baseVersion instanceof Version) {
baseVersionRootVersion = ((Version) baseVersion).getContainingHistory().getRootVersion();
} else {
baseVersionRootVersion = baseVersion.getVersionHistory().getRootVersion();
}
versionCompareable_ = baseVersionRootVersion.getUUID().endsWith(versionRootVersion.getUUID());
if (!versionCompareable_) {
throw new IllegalStateException("Versions to compare are the same");
}
}
Node currentNode = uiVersionInfo.getCurrentNode();
VersionHistory versionHistory = currentNode.getVersionHistory();
Version rootVersion = versionHistory.getRootVersion();
// Make baseVersion parameter always the oldest version
if (currentNode.getUUID().equals(baseVersion.getUUID())) {
// switch version and baseVersion to make sure that baseVersion is the
// oldest
Node tmpNode = baseVersion;
baseVersion = version;
version = tmpNode;
} else if (currentNode.getUUID().equals(version.getUUID())) {
// It's ok, the version' indice > baseVersion indice
} else if (baseVersion instanceof Version && version instanceof Version) {
// compare versions by indice
int baseVersionIndice = Integer.parseInt(baseVersion.getName());
int versionNumIndice = Integer.parseInt(version.getName());
if (baseVersionIndice == versionNumIndice) {
throw new IllegalStateException("Can't compare the same version");
} else if (baseVersionIndice > versionNumIndice) {
Node tmpNode = baseVersion;
baseVersion = version;
version = tmpNode;
}
}
// Base version is of type Version all the time
baseVersionName_ = ((Version) baseVersion).getName();
// Current version can be of type Version or Node (draft node)
versionName_ = version instanceof Version ? version.getName() : uiVersionInfo.getRootVersionNum();
// Base version is of type Version all the time
Calendar modifiedDate = getModifiedDate(baseVersion);
baseVersionDate_ = formatDate(modifiedDate);
// Current version can be of type Version or Node (draft node)
modifiedDate = getModifiedDate(version);
versionDate_ = formatDate(modifiedDate);
baseVersionAuthor_ = getLastModifier(baseVersion);
versionAuthor_ = getLastModifier(version);
// Base version is of type Version all the time
String[] baseVersionLabels = versionHistory.getVersionLabels((Version) baseVersion);
baseVersionLabel_ = baseVersionLabels == null || baseVersionLabels.length == 0 ? null : baseVersionLabels[0];
// Current version can be of type Version or Node (draft node)
if (version instanceof Version) {
String[] versionLabels = versionHistory.getVersionLabels((Version) version);
versionLabel_ = versionLabels == null || versionLabels.length == 0 ? null : versionLabels[0];
} else {
String[] versionLabels = versionHistory.getVersionLabels(rootVersion);
versionLabel_ = versionLabels == null || versionLabels.length == 0 ? null : versionLabels[0];
}
isImage_ = isOriginalNodeImage(version) && isOriginalNodeImage(baseVersion);
previousText_ = null;
currentText_ = null;
diffResultHTML_ = null;
currentImage_ = null;
baseImage_ = null;
isImage_ = isOriginalNodeImage(version) && isOriginalNodeImage(baseVersion);
if (isImage_) {
String wsName = currentNode.getSession().getWorkspace().getName();
String originalNodePath = currentNode.getPath();
String basePath = "/" + WCMCoreUtils.getPortalName() + "/" + WCMCoreUtils.getRestContextName() + "/jcr/"
+ WCMCoreUtils.getRepository().getConfiguration().getName() + "/" + wsName + originalNodePath;
long timeInMS = Calendar.getInstance().getTimeInMillis();
currentImage_ = basePath + (currentNode.getUUID().equals(version.getUUID()) ? "?" + timeInMS : ("?version=" + version.getName() + "&" + timeInMS));
baseImage_ = basePath + (currentNode.getUUID().equals(baseVersion.getUUID()) ? "?" + timeInMS : "?version=" + baseVersion.getName() + "&" + timeInMS);
} else {
try {
previousText_ = getText(baseVersion);
currentText_ = getText(version);
} catch (HandlerNotFoundException e) {
versionCompareable_ = false;
}
if (versionCompareable_) {
if (StringUtils.isBlank(previousText_) && StringUtils.isBlank(currentText_)) {
versionCompareable_ = false;
} else if ((previousText_ != null) && (currentText_ != null)) {
DiffService diffService = WCMCoreUtils.getService(DiffService.class);
DiffResult diffResult = diffService.getDifferencesAsHTML(previousText_, currentText_, true);
diffResultHTML_ = diffResult.getDiffHTML();
}
}
}
}
public String getBaseVersionNum() throws Exception {
return baseVersionName_;
}
public String getCurrentVersionNum() throws Exception {
return versionName_;
}
public String getBaseVersionDate() throws Exception {
return baseVersionDate_;
}
public String getCurrentVersionDate() throws Exception {
return versionDate_;
}
public String getBaseVersionAuthor() {
return baseVersionAuthor_;
}
public String getCurrentVersionAuthor() {
return versionAuthor_;
}
public String getBaseVersionLabel() {
return baseVersionLabel_;
}
public String getCurrentVersionLabel() {
return versionLabel_;
}
public String getBaseImage() throws Exception {
return baseImage_;
}
public String getCurrentImage() throws Exception {
return currentImage_;
}
public boolean isCompareable() {
return versionCompareable_;
}
public String getDifferences() throws Exception {
return diffResultHTML_;
}
public boolean isImage() {
return isImage_;
}
private Calendar getModifiedDate(Node node) throws RepositoryException {
Property property = getProperty(node, EXO_LAST_MODIFIED_DATE);
return property == null ? null : property.getDate();
}
private String getLastModifier(Node node) throws RepositoryException {
Property property = getProperty(node, Utils.EXO_LASTMODIFIER);
return property == null ? null : property.getString();
}
private boolean isOriginalNodeImage(Node node) throws Exception {
Property mimeProperty = getProperty(node, Utils.JCR_MIMETYPE);
String mimeType = mimeProperty == null ? null : mimeProperty.getString();
return StringUtils.isNotBlank(mimeType) && mimeType.startsWith("image");
}
private String getText(Node node) throws Exception {
Property mimeProperty = getProperty(node, Utils.JCR_MIMETYPE);
Property dataProperty = getProperty(node, Utils.JCR_DATA);
if (mimeProperty != null && dataProperty != null) {
String mimeType = mimeProperty.getString();
if (mimeType.startsWith("text")) {
return dataProperty.getString();
}
DocumentReaderService readerService = getApplicationComponent(DocumentReaderService.class);
DocumentReader documentReader = readerService.getDocumentReader(mimeType);
if (documentReader != null) {
try {
return documentReader.getContentAsText(dataProperty.getStream());
} catch (Exception e) {
LOG.warn("An error occured while getting text from file " + node.getPath() + " with mimeType " + mimeType
+ " with document reader = " + documentReader + ". File comparaison will be disabled", e);
}
}
}
throw new HandlerNotFoundException();
}
private Property getProperty(Node node, String propertyName) throws RepositoryException, PathNotFoundException {
Property property = null;
if (node instanceof Version) {
if (node.hasNode(Utils.JCR_FROZEN)) {
node = node.getNode(Utils.JCR_FROZEN);
} else {
return null;
}
}
if (node.hasProperty(propertyName)) {
property = node.getProperty(propertyName);
} else if (node.hasNode(Utils.JCR_CONTENT)) {
Node content = node.getNode(Utils.JCR_CONTENT);
if (content.hasProperty(propertyName)) {
property = content.getProperty(propertyName);
}
}
return property;
}
private String formatDate(Calendar calendar) {
Locale currentLocale = Util.getPortalRequestContext().getLocale();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, currentLocale);
return dateFormat.format(calendar.getTime());
}
static public class CloseCompareActionListener extends EventListener<UIDiff> {
public void execute(Event<UIDiff> event) throws Exception {
UIDiff uiDiff = event.getSource();
if (uiDiff.isRendered()) {
uiDiff.setRendered(false);
}
UIDocumentWorkspace uiDocumentWorkspace = uiDiff.getAncestorOfType(UIDocumentWorkspace.class);
UIVersionInfo uiVersionInfo = uiDocumentWorkspace.getChild(UIVersionInfo.class);
uiVersionInfo.setRendered(true);
event.getRequestContext().addUIComponentToUpdateByAjax(uiDocumentWorkspace);
}
}
static public class CompareActionListener extends EventListener<UIDiff> {
public void execute(Event<UIDiff> event) throws Exception {
UIDiff uiDiff = (UIDiff) event.getSource();
String fromVersionName = event.getRequestContext().getRequestParameter(FROM_PARAM);
String toVersionName = event.getRequestContext().getRequestParameter(TO_PARAM);
UIDocumentWorkspace uiDocumentWorkspace = uiDiff.getAncestorOfType(UIDocumentWorkspace.class);
UIVersionInfo uiVersionInfo = uiDocumentWorkspace.getChild(UIVersionInfo.class);
uiDiff.setVersions(uiVersionInfo.getVersion(fromVersionName), uiVersionInfo.getVersion(toVersionName));
}
}
}