mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-30 18:15:39 +00:00
75134: Merged BRANCHES/DEV/KEVINR3 to BRANCHES/DEV/HEAD-BUG-FIX 71905: Merged BRANCHES/DEV/KEVINR2 to BRANCHES/DEV/KEVINR3 71779: Activities prototype - PDF Previewer link to original PDF correction 71776: Activities prototype - Slingshot download urls for Image Preview dashlet and PDF Previewer components. 71752: Activities prototype - Added activity feed items for Preview and Download actions 71913: Activities prototype - styling and UX 72000: Activities prototype - improved CSS 73462: Activities prototype - CSS tweaks 75128: Activities prototype - CSS tweaks git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@77438 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
507 lines
17 KiB
Java
507 lines
17 KiB
Java
/*
|
|
* Copyright (C) 2005-2013 Alfresco Software Limited.
|
|
*
|
|
* This file is part of Alfresco
|
|
*
|
|
* Alfresco 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 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package org.alfresco.repo.jscript.app;
|
|
|
|
import java.io.Serializable;
|
|
import java.text.MessageFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.Date;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
import org.alfresco.model.ContentModel;
|
|
import org.alfresco.service.ServiceRegistry;
|
|
import org.alfresco.service.cmr.lock.LockService;
|
|
import org.alfresco.service.cmr.lock.LockStatus;
|
|
import org.alfresco.service.cmr.model.FileFolderService;
|
|
import org.alfresco.service.cmr.model.FileInfo;
|
|
import org.alfresco.service.cmr.repository.ContentData;
|
|
import org.alfresco.service.cmr.repository.ContentService;
|
|
import org.alfresco.service.cmr.repository.MimetypeService;
|
|
import org.alfresco.service.cmr.repository.NodeRef;
|
|
import org.alfresco.service.cmr.repository.NodeService;
|
|
import org.alfresco.service.cmr.security.AccessPermission;
|
|
import org.alfresco.service.cmr.security.AccessStatus;
|
|
import org.alfresco.service.cmr.security.PermissionService;
|
|
import org.alfresco.service.cmr.security.PublicServiceAccessService;
|
|
import org.alfresco.service.namespace.NamespaceException;
|
|
import org.alfresco.service.namespace.NamespaceService;
|
|
import org.alfresco.service.namespace.QName;
|
|
import org.alfresco.util.ISO8601DateFormat;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
import org.json.JSONException;
|
|
import org.json.simple.JSONArray;
|
|
import org.json.simple.JSONAware;
|
|
import org.json.simple.JSONObject;
|
|
import org.springframework.extensions.surf.util.URLEncoder;
|
|
|
|
/**
|
|
* JSON Conversion Component
|
|
*
|
|
* @author Roy Wetherall
|
|
* @author Kevin Roast
|
|
*/
|
|
public class JSONConversionComponent
|
|
{
|
|
/** Content download API URL template */
|
|
private final static String CONTENT_DOWNLOAD_API_URL = "/slingshot/node/content/{0}/{1}/{2}/{3}";
|
|
|
|
/** Logger */
|
|
private static Log logger = LogFactory.getLog(JSONConversionComponent.class);
|
|
|
|
/** Registered decorators */
|
|
protected Map<QName, PropertyDecorator> propertyDecorators = new HashMap<QName, PropertyDecorator>(8);
|
|
|
|
/** User permissions */
|
|
protected String[] userPermissions;
|
|
|
|
/** Thread local cache of namespace prefixes for long QName to short prefix name conversions */
|
|
protected static ThreadLocal<Map<String, String>> namespacePrefixCache = new ThreadLocal<Map<String, String>>()
|
|
{
|
|
@Override
|
|
protected Map<String, String> initialValue()
|
|
{
|
|
return new HashMap<String, String>(8);
|
|
}
|
|
};
|
|
|
|
/** Services */
|
|
protected NodeService nodeService;
|
|
protected PublicServiceAccessService publicServiceAccessService;
|
|
protected NamespaceService namespaceService;
|
|
protected FileFolderService fileFolderService;
|
|
protected LockService lockService;
|
|
protected ContentService contentService;
|
|
protected PermissionService permissionService;
|
|
protected MimetypeService mimetypeService;
|
|
|
|
|
|
/**
|
|
* @param nodeService node service
|
|
*/
|
|
public void setNodeService(NodeService nodeService)
|
|
{
|
|
this.nodeService = nodeService;
|
|
}
|
|
|
|
/**
|
|
* @param publicServiceAccessService public service access service
|
|
*/
|
|
public void setPublicServiceAccessService(PublicServiceAccessService publicServiceAccessService)
|
|
{
|
|
this.publicServiceAccessService = publicServiceAccessService;
|
|
}
|
|
|
|
/**
|
|
* @param namespaceService namespace service
|
|
*/
|
|
public void setNamespaceService(NamespaceService namespaceService)
|
|
{
|
|
this.namespaceService = namespaceService;
|
|
}
|
|
|
|
/**
|
|
* @param fileFolderService file folder service
|
|
*/
|
|
public void setFileFolderService(FileFolderService fileFolderService)
|
|
{
|
|
this.fileFolderService = fileFolderService;
|
|
}
|
|
|
|
/**
|
|
* @param lockService lock service
|
|
*/
|
|
public void setLockService(LockService lockService)
|
|
{
|
|
this.lockService = lockService;
|
|
}
|
|
|
|
/**
|
|
* @param permissionService permission service
|
|
*/
|
|
public void setPermissionService(PermissionService permissionService)
|
|
{
|
|
this.permissionService = permissionService;
|
|
}
|
|
|
|
/**
|
|
* @param userPermissions user permissions
|
|
*/
|
|
public void setUserPermissions(String[] userPermissions)
|
|
{
|
|
this.userPermissions = userPermissions;
|
|
}
|
|
|
|
/**
|
|
* @param contentService content service
|
|
*/
|
|
public void setContentService(ContentService contentService)
|
|
{
|
|
this.contentService = contentService;
|
|
}
|
|
|
|
/**
|
|
* @param mimetypeService mimetype service
|
|
*/
|
|
public void setMimetypeService(MimetypeService mimetypeService)
|
|
{
|
|
this.mimetypeService = mimetypeService;
|
|
}
|
|
|
|
/**
|
|
* Register a property decorator;
|
|
*
|
|
* @param propertyDecorator
|
|
*/
|
|
public void registerPropertyDecorator(PropertyDecorator propertyDecorator)
|
|
{
|
|
for (QName propertyName : propertyDecorator.getPropertyNames())
|
|
{
|
|
propertyDecorators.put(propertyName, propertyDecorator);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convert a node reference to a JSON string. Selects the correct converter based on selection
|
|
* implementation.
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public String toJSON(final NodeRef nodeRef, final boolean useShortQNames)
|
|
{
|
|
final JSONObject json = new JSONObject();
|
|
|
|
if (this.nodeService.exists(nodeRef))
|
|
{
|
|
if (publicServiceAccessService.hasAccess(ServiceRegistry.NODE_SERVICE.getLocalName(), "getProperties", nodeRef) == AccessStatus.ALLOWED)
|
|
{
|
|
// init namespace prefix cache
|
|
namespacePrefixCache.get().clear();
|
|
|
|
// Get node info
|
|
FileInfo nodeInfo = this.fileFolderService.getFileInfo(nodeRef);
|
|
|
|
// Set root values
|
|
setRootValues(nodeInfo, json, useShortQNames);
|
|
|
|
// add permissions
|
|
json.put("permissions", permissionsToJSON(nodeRef));
|
|
|
|
// add properties
|
|
json.put("properties", propertiesToJSON(nodeRef, nodeInfo.getProperties(), useShortQNames));
|
|
|
|
// add aspects
|
|
json.put("aspects", apsectsToJSON(nodeRef, useShortQNames));
|
|
}
|
|
}
|
|
|
|
return json.toJSONString();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param nodeInfo
|
|
* @param rootJSONObject
|
|
* @param useShortQNames
|
|
* @throws JSONException
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
protected void setRootValues(final FileInfo nodeInfo, final JSONObject rootJSONObject, final boolean useShortQNames)
|
|
{
|
|
final NodeRef nodeRef = nodeInfo.getNodeRef();
|
|
|
|
rootJSONObject.put("nodeRef", nodeInfo.getNodeRef().toString());
|
|
rootJSONObject.put("type", nameToString(nodeInfo.getType(), useShortQNames));
|
|
rootJSONObject.put("isContainer", nodeInfo.isFolder()); //node.getIsContainer() || node.getIsLinkToContainer());
|
|
rootJSONObject.put("isLocked", isLocked(nodeInfo.getNodeRef()));
|
|
|
|
rootJSONObject.put("isLink", nodeInfo.isLink());
|
|
if (nodeInfo.isLink())
|
|
{
|
|
NodeRef targetNodeRef = nodeInfo.getLinkNodeRef();
|
|
if (targetNodeRef != null)
|
|
{
|
|
rootJSONObject.put("linkedNode", toJSON(targetNodeRef, useShortQNames));
|
|
}
|
|
}
|
|
|
|
// TODO should this be moved to the property output since we may have more than one content property
|
|
// or a non-standard content property
|
|
|
|
if (nodeInfo.isFolder() == false)
|
|
{
|
|
final ContentData cdata = nodeInfo.getContentData();
|
|
if (cdata != null)
|
|
{
|
|
String contentURL = MessageFormat.format(
|
|
CONTENT_DOWNLOAD_API_URL, new Object[]{
|
|
nodeRef.getStoreRef().getProtocol(),
|
|
nodeRef.getStoreRef().getIdentifier(),
|
|
nodeRef.getId(),
|
|
URLEncoder.encode(nodeInfo.getName())});
|
|
|
|
rootJSONObject.put("contentURL", contentURL);
|
|
rootJSONObject.put("mimetype", cdata.getMimetype());
|
|
Map<String, String> mimetypeDescriptions;
|
|
mimetypeDescriptions = mimetypeService.getDisplaysByMimetype();
|
|
|
|
if (mimetypeDescriptions.containsKey(cdata.getMimetype()))
|
|
{
|
|
rootJSONObject.put("mimetypeDisplayName", mimetypeDescriptions.get(cdata.getMimetype()));
|
|
}
|
|
rootJSONObject.put("encoding", cdata.getEncoding());
|
|
rootJSONObject.put("size", cdata.getSize());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handles the work of converting node permissions to JSON.
|
|
*
|
|
* @param nodeRef
|
|
* @return
|
|
* @throws JSONException
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
protected JSONObject permissionsToJSON(final NodeRef nodeRef)
|
|
{
|
|
final JSONObject permissionsJSON = new JSONObject();
|
|
if (AccessStatus.ALLOWED.equals(permissionService.hasPermission(nodeRef, PermissionService.READ_PERMISSIONS)) == true)
|
|
{
|
|
permissionsJSON.put("inherited", permissionService.getInheritParentPermissions(nodeRef));
|
|
permissionsJSON.put("roles", allSetPermissionsToJSON(nodeRef));
|
|
permissionsJSON.put("user", userPermissionsToJSON(nodeRef));
|
|
}
|
|
return permissionsJSON;
|
|
}
|
|
|
|
/**
|
|
* Handles the work of converting user permissions to JSON.
|
|
*
|
|
* @param nodeRef
|
|
* @return
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
protected JSONObject userPermissionsToJSON(final NodeRef nodeRef)
|
|
{
|
|
final JSONObject userPermissionJSON = new JSONObject();
|
|
for (String userPermission : this.userPermissions)
|
|
{
|
|
boolean hasPermission = AccessStatus.ALLOWED.equals(permissionService.hasPermission(nodeRef, userPermission));
|
|
userPermissionJSON.put(userPermission, hasPermission);
|
|
}
|
|
return userPermissionJSON;
|
|
}
|
|
|
|
/**
|
|
* Handles the work of converting values to JSON.
|
|
*
|
|
* @param nodeRef
|
|
* @param propertyName
|
|
* @param key
|
|
* @param value
|
|
* @return the JSON value
|
|
*/
|
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
protected Object propertyToJSON(final NodeRef nodeRef, final QName propertyName, final String key, final Serializable value)
|
|
{
|
|
if (value != null)
|
|
{
|
|
// Has a decorator has been registered for this property?
|
|
if (propertyDecorators.containsKey(propertyName))
|
|
{
|
|
JSONAware jsonAware = propertyDecorators.get(propertyName).decorate(propertyName, nodeRef, value);
|
|
if (jsonAware != null)
|
|
{
|
|
return jsonAware;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Built-in data type processing
|
|
if (value instanceof Date)
|
|
{
|
|
JSONObject dateObj = new JSONObject();
|
|
dateObj.put("value", JSONObject.escape(value.toString()));
|
|
dateObj.put("iso8601", JSONObject.escape(ISO8601DateFormat.format((Date)value)));
|
|
return dateObj;
|
|
}
|
|
else if (value instanceof List)
|
|
{
|
|
// Convert the List to a JSON list by recursively calling propertyToJSON
|
|
List<Object> jsonList = new ArrayList<Object>(((List<Serializable>) value).size());
|
|
for (Serializable listItem : (List<Serializable>) value)
|
|
{
|
|
jsonList.add(propertyToJSON(nodeRef, propertyName, key, listItem));
|
|
}
|
|
return jsonList;
|
|
}
|
|
else if (value instanceof Double)
|
|
{
|
|
return (Double.isInfinite((Double)value) || Double.isNaN((Double)value) ? null : value.toString());
|
|
}
|
|
else if (value instanceof Float)
|
|
{
|
|
return (Float.isInfinite((Float)value) || Float.isNaN((Float)value) ? null : value.toString());
|
|
}
|
|
else
|
|
{
|
|
return value.toString();
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param nodeRef
|
|
* @param map
|
|
* @param useShortQNames
|
|
* @return
|
|
* @throws JSONException
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
protected JSONObject propertiesToJSON(NodeRef nodeRef, Map<QName, Serializable> properties, boolean useShortQNames)
|
|
{
|
|
JSONObject propertiesJSON = new JSONObject();
|
|
|
|
for (QName propertyName : properties.keySet())
|
|
{
|
|
try
|
|
{
|
|
String key = nameToString(propertyName, useShortQNames);
|
|
Serializable value = properties.get(propertyName);
|
|
|
|
propertiesJSON.put(key, propertyToJSON(nodeRef, propertyName, key, value));
|
|
}
|
|
catch (NamespaceException ne)
|
|
{
|
|
// ignore properties that do not have a registered namespace
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("Ignoring property '" + propertyName + "' as its namespace is not registered");
|
|
}
|
|
}
|
|
|
|
return propertiesJSON;
|
|
}
|
|
|
|
/**
|
|
* Handles the work of converting aspects to JSON.
|
|
*
|
|
* @param nodeRef
|
|
* @param useShortQNames
|
|
* @return
|
|
* @throws JSONException
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
protected JSONArray apsectsToJSON(NodeRef nodeRef, boolean useShortQNames)
|
|
{
|
|
JSONArray aspectsJSON = new JSONArray();
|
|
|
|
Set<QName> aspects = this.nodeService.getAspects(nodeRef);
|
|
for (QName aspect : aspects)
|
|
{
|
|
aspectsJSON.add(nameToString(aspect, useShortQNames));
|
|
}
|
|
|
|
return aspectsJSON;
|
|
}
|
|
|
|
/**
|
|
* Handles the work of converting all set permissions to JSON.
|
|
*
|
|
* @param nodeRef
|
|
* @return
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
protected JSONArray allSetPermissionsToJSON(NodeRef nodeRef)
|
|
{
|
|
Set<AccessPermission> acls = permissionService.getAllSetPermissions(nodeRef);
|
|
JSONArray permissions = new JSONArray();
|
|
for (AccessPermission permission : acls)
|
|
{
|
|
StringBuilder buf = new StringBuilder(64);
|
|
buf.append(permission.getAccessStatus())
|
|
.append(';')
|
|
.append(permission.getAuthority())
|
|
.append(';')
|
|
.append(permission.getPermission())
|
|
.append(';').append(permission.isSetDirectly() ? "DIRECT" : "INHERITED");
|
|
permissions.add(buf.toString());
|
|
}
|
|
return permissions;
|
|
}
|
|
|
|
/**
|
|
* Convert a qname to a string - either full or short prefixed named.
|
|
*
|
|
* @param qname
|
|
* @param isShortName
|
|
* @return qname string.
|
|
*/
|
|
private String nameToString(final QName qname, final boolean isShortName)
|
|
{
|
|
String result;
|
|
if (isShortName)
|
|
{
|
|
final Map<String, String> cache = namespacePrefixCache.get();
|
|
String prefix = cache.get(qname.getNamespaceURI());
|
|
if (prefix == null)
|
|
{
|
|
// first request for this namespace prefix, get and cache result
|
|
Collection<String> prefixes = this.namespaceService.getPrefixes(qname.getNamespaceURI());
|
|
prefix = prefixes.size() != 0 ? prefixes.iterator().next() : "";
|
|
cache.put(qname.getNamespaceURI(), prefix);
|
|
}
|
|
result = prefix + QName.NAMESPACE_PREFIX + qname.getLocalName();
|
|
}
|
|
else
|
|
{
|
|
result = qname.toString();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Return true if the node is locked.
|
|
*
|
|
* @param nodeRef
|
|
* @return
|
|
*/
|
|
private boolean isLocked(final NodeRef nodeRef)
|
|
{
|
|
boolean locked = false;
|
|
|
|
if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE) == true)
|
|
{
|
|
LockStatus lockStatus = lockService.getLockStatus(nodeRef);
|
|
if (lockStatus == LockStatus.LOCKED || lockStatus == LockStatus.LOCK_OWNER)
|
|
{
|
|
locked = true;
|
|
}
|
|
}
|
|
|
|
return locked;
|
|
}
|
|
}
|