mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged V4.0-BUG-FIX to HEAD
33836: Fix for ALF-10651 Fix patches that trigger reindexing and ALF-10656 SOLR: Patches execute search during bootstrap causing deadlock 33842: Fixes ALF-12797: i18n strings in activiti-admin login-screen escaped properly 33844: Fix for ALF-10651 Fix patches that trigger reindexing and ALF-10656 SOLR: Patches execute search during bootstrap causing deadlock - batch touch to limit the in clause size generated 33845: Manually added extra core Share extensions needed for the V4.0 Records Management module from the development branch. - Refactored JSON property decorators for the Document Library data webscripts - Document List banners (e.g. working copy) moved into metadata template config - Ability to override default document/folder title within Document Library (<title> element in metadata template - unused in core code) - Additional extension point in surf-doclist to override remote data URL - Better handling for missing content property 33852: ALF-12725: Merged V3.4-BUG-FIX (3.4.9) to V4.0-BUG-FIX (4.0.1) 33849: Merged V3 (3.4.8) to V3.4-BUG-FIX (3.4.9) 33848: ALF-10976 (relates to ALF-10412) Fixed bug to do with preview being stuck as always being 'Content cannot be previewed. Do you wish to download?' or a 'blank preview after a transformer is not found' for all content with the same mimetype. Cache in ThumbnailRegistory.getThumbnailDefinitions() now understands that transformers may have an upper content size limit. The choice between the two options was based on the size of the first file previewed of each mimetype. Needed to add getMaxSourceSizeBytes() to support this (see below). - refactored (previous refactor was incomplete) ContentTransformer so that the two halfs of isTransformable is now split into sub methods isTransformableMimetypes and isTransformableSize. This is why there are so many files changed. - Moved getMaxSourceSizeBytes() from AbstractContentTransformerLimits to ContentTransformer as there were becomming too many places in the code that needed needed to check if the ContentTransformer was an instanceof AbstractContentTransformerLimits before calling this method. - TransformerDebug now uses KB MB GB values in output to make it simpler to read. - TransformerDebug now uses thousand separaters in millisecond values to make it simpler to read. - TransformerDebug now reports the 'parent' transformer name rather than the sub-transformer name when an unavailable transformer is found. Makes it simpler to tie up with the 'available transformer' list with the new pushIsTransformableSize() calls. - TransformerDebug now uses trace logging for calls from ThumbnailRegistory.isThumbnailDefinitionAvailable() as it is normally followed by a ContentService.transform() which is logged at debug level anyway. - TransformerDebug now turns logging level to trace if the file size is 0 bytes. Request from Jan. Not sure how one uploads such a file! - Modified ComplexContentTransformer.isTransformable() so that it checks the mimetypes before the sizes so that TransformerDebug does not report 'unavailable transformers' that don't support the mimetype conversion. - Modified ComplexContentTransformer.getLimits and ComplexContentTransformer.isPageLimitSupported() to include the limits from the first sub transformer. Was not an issue until ContentTransformer.getMaxSourceSizeBytes() was introduced. - Added logger to RhinoScriptProcessor to debug requests run javascript on the server. - Dropped the sourceUrl parameter from ThumbnailRegistry.getThumbnailDefinitions() which was introduced with limits as it is logicall not needed. 33853: DiskInterface.renameFile() can now throw PermissionDeniedException to return a different status to the client. Part of ALF-12717. 33856: Merged V3.4-BUG-FIX to V4.0-BUG-FIX 33835: ALF-12546: Remove references to retired RegPaths.exe from installed apply_amps.bat script 33843: Fix for ALF-12775 33855: Merged V3.4 to V3.4-BUG-FIX 33851: ALF-12588: Documents Intermittently Do Not Appear in Share - Fix by Alex Busel for regression I accidentally caused in 3.4.6 - Simple typo in mergeDeletions() caused path deletions to sometimes not get applied or get processed twice - Yikes! git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@33857 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1,298 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 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;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.jscript.app.PropertyDecorator;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.namespace.NamespaceException;
|
||||
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.JSONObject;
|
||||
import org.springframework.extensions.surf.util.URLEncoder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Utility functions specifically for external application use.
|
||||
*
|
||||
* @author Mike Hatfield
|
||||
*/
|
||||
|
||||
public final class ApplicationScriptUtils extends BaseScopableProcessorExtension
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(ApplicationScriptUtils.class);
|
||||
|
||||
/** Repository Service Registry */
|
||||
private ServiceRegistry services;
|
||||
private NodeService nodeService = null;
|
||||
private Map<String, Object> decoratedProperties;
|
||||
private String[] userPermissions;
|
||||
|
||||
private final static String CONTENT_DOWNLOAD_API_URL = "/api/node/content/{0}/{1}/{2}/{3}";
|
||||
|
||||
/**
|
||||
* Set the service registry
|
||||
*
|
||||
* @param serviceRegistry the service registry
|
||||
*/
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.services = serviceRegistry;
|
||||
this.nodeService = services.getNodeService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the properties that require decorator beans
|
||||
*
|
||||
* @param decoratedProperties
|
||||
*/
|
||||
public void setDecoratedProperties(Map<String, Object> decoratedProperties)
|
||||
{
|
||||
this.decoratedProperties = decoratedProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the list of user permissions to return in the JSON body
|
||||
*
|
||||
* @param userPermissions
|
||||
*/
|
||||
public void setUserPermissions(String[] userPermissions)
|
||||
{
|
||||
this.userPermissions = userPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JSON representation of a node. Long-form QNames are used in the
|
||||
* result.
|
||||
*
|
||||
* @param node the node to convert to JSON representation.
|
||||
* @return The JSON representation of this node
|
||||
*/
|
||||
public String toJSON(ScriptNode node)
|
||||
{
|
||||
return this.toJSON(node, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JSON representation of this node.
|
||||
*
|
||||
* @param node the node to convert to JSON representation.
|
||||
* @param useShortQNames if true short-form qnames will be returned, else long-form.
|
||||
* @return The JSON representation of this node
|
||||
*/
|
||||
public String toJSON(ScriptNode node, boolean useShortQNames)
|
||||
{
|
||||
return this.toJSONObj(node, useShortQNames).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON object representing the node.
|
||||
*
|
||||
* @param node the node to convert to JSON representation.
|
||||
* @param useShortQNames if true short-form qnames will be returned, else long-form.
|
||||
* @return The JSON representation of this node
|
||||
*/
|
||||
protected Object toJSONObj(ScriptNode node, boolean useShortQNames)
|
||||
{
|
||||
NodeRef nodeRef = node.getNodeRef();
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
if (this.nodeService.exists(nodeRef))
|
||||
{
|
||||
if (this.services.getPublicServiceAccessService().hasAccess(ServiceRegistry.NODE_SERVICE.getLocalName(), "getProperties", nodeRef) == AccessStatus.ALLOWED)
|
||||
{
|
||||
try
|
||||
{
|
||||
String typeString = useShortQNames ? this.getShortQName(node.getQNameType()) : node.getType();
|
||||
boolean isLink = node.getIsLinkToContainer() || node.getIsLinkToDocument();
|
||||
|
||||
json.put("nodeRef", nodeRef.toString());
|
||||
json.put("type", typeString);
|
||||
json.put("isContainer", node.getIsContainer() || node.getIsLinkToContainer());
|
||||
json.put("isLink", isLink);
|
||||
json.put("isLocked", node.getIsLocked());
|
||||
|
||||
if (node.getIsDocument())
|
||||
{
|
||||
json.put("contentURL", this.getDownloadAPIUrl(node));
|
||||
json.put("mimetype", node.getMimetype());
|
||||
json.put("size", node.getSize());
|
||||
}
|
||||
|
||||
// permissions
|
||||
Map<String, Serializable> permissionsJSON = new LinkedHashMap<String, Serializable>(3);
|
||||
if (node.hasPermission("ReadPermissions"))
|
||||
{
|
||||
permissionsJSON.put("roles", node.retrieveAllSetPermissions(false, true));
|
||||
}
|
||||
permissionsJSON.put("inherited", node.inheritsPermissions());
|
||||
Map<String, Serializable> userPermissionJSON = new LinkedHashMap<String, Serializable>(this.userPermissions.length);
|
||||
for (String userPermission : this.userPermissions)
|
||||
{
|
||||
userPermissionJSON.put(userPermission, node.hasPermission(userPermission));
|
||||
}
|
||||
permissionsJSON.put("user", (Serializable) userPermissionJSON);
|
||||
json.put("permissions", permissionsJSON);
|
||||
|
||||
// add properties
|
||||
Map<QName, Serializable> nodeProperties = this.nodeService.getProperties(nodeRef);
|
||||
json.put("properties", this.parseToJSON(nodeRef, nodeProperties, useShortQNames));
|
||||
|
||||
// add aspects as an array
|
||||
Set<QName> nodeAspects = this.nodeService.getAspects(nodeRef);
|
||||
if (useShortQNames)
|
||||
{
|
||||
Set<String> nodeAspectsShortQNames = new LinkedHashSet<String>(nodeAspects.size());
|
||||
for (QName nextLongQName : nodeAspects)
|
||||
{
|
||||
String nextShortQName = this.getShortQName(nextLongQName);
|
||||
nodeAspectsShortQNames.add(nextShortQName);
|
||||
}
|
||||
json.put("aspects", nodeAspectsShortQNames);
|
||||
}
|
||||
else
|
||||
{
|
||||
json.put("aspects", nodeAspects);
|
||||
}
|
||||
|
||||
// link to document or folder?
|
||||
if (isLink)
|
||||
{
|
||||
NodeRef targetNodeRef = (NodeRef) nodeProperties.get(ContentModel.PROP_LINK_DESTINATION);
|
||||
if (targetNodeRef != null)
|
||||
{
|
||||
json.put("linkedNode", this.toJSONObj(new ScriptNode(targetNodeRef, this.services, node.scope), useShortQNames));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONException error)
|
||||
{
|
||||
error.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a long-form QName, this method uses the namespace service to create a
|
||||
* short-form QName string.
|
||||
*
|
||||
* @param longQName
|
||||
* @return the short form of the QName string, e.g. "cm:content"
|
||||
*/
|
||||
protected String getShortQName(QName longQName)
|
||||
{
|
||||
return longQName.toPrefixString(this.services.getNamespaceService());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a map of node properties to a format suitable for JSON output
|
||||
*
|
||||
* @param nodeRef
|
||||
* @param properties
|
||||
* @param useShortQNames
|
||||
* @return a decorated map of properties suitable for JSON output
|
||||
*/
|
||||
protected Map<String, Serializable> parseToJSON(NodeRef nodeRef, Map<QName, Serializable> properties, boolean useShortQNames)
|
||||
{
|
||||
Map<String, Serializable> json = new LinkedHashMap<String, Serializable>(properties.size());
|
||||
|
||||
for (QName nextLongQName : properties.keySet())
|
||||
{
|
||||
try
|
||||
{
|
||||
String shortQName = this.getShortQName(nextLongQName);
|
||||
String key = useShortQNames ? shortQName : nextLongQName.toString();
|
||||
Serializable value = properties.get(nextLongQName);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
// Has a decorator has been registered for this property?
|
||||
if (this.decoratedProperties.containsKey(shortQName))
|
||||
{
|
||||
json.put(key, ((PropertyDecorator) this.decoratedProperties.get(shortQName)).decorate(nodeRef, shortQName, value));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Built-in data type processing
|
||||
if (value instanceof Date)
|
||||
{
|
||||
Map<String, Serializable> dateObj = new LinkedHashMap<String, Serializable>(1);
|
||||
dateObj.put("value", value);
|
||||
dateObj.put("iso8601", ISO8601DateFormat.format((Date)value));
|
||||
json.put(key, (Serializable)dateObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
json.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
json.put(key, null);
|
||||
}
|
||||
}
|
||||
catch (NamespaceException ne)
|
||||
{
|
||||
// ignore properties that do not have a registered namespace
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Ignoring property '" + nextLongQName + "' as its namespace is not registered");
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node the node to construct the download URL for
|
||||
* @return For a content document, this method returns the URL to the /api/node/content
|
||||
* API for the default content property
|
||||
* <p>
|
||||
* For a container node, this method returns an empty string
|
||||
* </p>
|
||||
*/
|
||||
public String getDownloadAPIUrl(ScriptNode node)
|
||||
{
|
||||
if (node.getIsDocument())
|
||||
{
|
||||
return MessageFormat.format(CONTENT_DOWNLOAD_API_URL, new Object[]{
|
||||
node.nodeRef.getStoreRef().getProtocol(),
|
||||
node.nodeRef.getStoreRef().getIdentifier(),
|
||||
node.nodeRef.getId(),
|
||||
URLEncoder.encode(node.getName())});
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2005-2011 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;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import org.alfresco.repo.jscript.app.JSONConversionComponent;
|
||||
import org.springframework.extensions.surf.util.URLEncoder;
|
||||
|
||||
/**
|
||||
* Utility functions specifically for external application use.
|
||||
*
|
||||
* @author Mike Hatfield
|
||||
*/
|
||||
|
||||
public final class ApplicationScriptUtils extends BaseScopableProcessorExtension
|
||||
{
|
||||
/** Content download API URL */
|
||||
private final static String CONTENT_DOWNLOAD_API_URL = "/api/node/content/{0}/{1}/{2}/{3}";
|
||||
|
||||
/** JSON conversion component */
|
||||
private JSONConversionComponent jsonConversionComponent;
|
||||
|
||||
/**
|
||||
* @param jsonConversionComponent JSON conversion component
|
||||
*/
|
||||
public void setJsonConversionComponent(JSONConversionComponent jsonConversionComponent)
|
||||
{
|
||||
this.jsonConversionComponent = jsonConversionComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JSON representation of a node. Long-form QNames are used in the
|
||||
* result.
|
||||
*
|
||||
* @param node the node to convert to JSON representation.
|
||||
* @return The JSON representation of this node
|
||||
*/
|
||||
public String toJSON(ScriptNode node)
|
||||
{
|
||||
return this.toJSON(node, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JSON representation of this node.
|
||||
*
|
||||
* @param node the node to convert to JSON representation.
|
||||
* @param useShortQNames if true short-form qnames will be returned, else long-form.
|
||||
* @return The JSON representation of this node
|
||||
*/
|
||||
public String toJSON(ScriptNode node, boolean useShortQNames)
|
||||
{
|
||||
return jsonConversionComponent.toJSON(node.getNodeRef(), useShortQNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node the node to construct the download URL for
|
||||
* @return For a content document, this method returns the URL to the /api/node/content
|
||||
* API for the default content property
|
||||
* <p>
|
||||
* For a container node, this method returns an empty string
|
||||
* </p>
|
||||
*/
|
||||
public String getDownloadAPIUrl(ScriptNode node)
|
||||
{
|
||||
if (node.getIsDocument())
|
||||
{
|
||||
return MessageFormat.format(CONTENT_DOWNLOAD_API_URL, new Object[]{
|
||||
node.nodeRef.getStoreRef().getProtocol(),
|
||||
node.nodeRef.getStoreRef().getIdentifier(),
|
||||
node.nodeRef.getId(),
|
||||
URLEncoder.encode(node.getName())});
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user