mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-30 18:15:39 +00:00
19546: (RECORD ONLY) Merged V3.2 to PATCHES/V3.2.r 19432: Merged V3.1 to V3.2 19427: Merged V3.0 to V3.1 19423: Merged V2.2 to V3.0 19391: Fix for ALF-2076: AUTO does not work if a document has been added and deleted since the index backup 19419: V2.2 Build Fix 19421: Fix for ALF-2076: AUTO does not work if a document has been added and deleted since the index backup 19463: Merged V3.1 to V3.2 19459: Merged V3.0 to V3.1 19457: Merged V2.2 to V3.0 19449: Addition Fix for ALF-2076: AUTO does not work if a document has been added and deleted since the index backup 19493 Merged V3.1 to V3.2 19471: Build fix after changes for ALF-2076 were merged forward. Index checker correctly understands INDETERMINATE state of indexed transactions 19547: (RECORD ONLY) Incremented version label 19555: (RECORD ONLY) Merged V3.2 to PATCHES/V3.2.r 19552: Merged V3.1 to V3.2 19551: Further fix after changes for ALF-2076 were merged forward. Final fix to check for InIndex.No 19566: (RECORD ONLY) Merged V3.2 to PATCHES/V3.2.r 19539: Merged HEAD to V3.2 19538: ALF-2076: Build fix - fix build speed 19802: (RECORD ONLY) ALF-2382, ALF-2383: Merged V3.2 to PATCHES/V3.2.r 19647: ALF-2231: Merged DEV/BELARUS/V2.2-2009_12_01 to V3.2 17704: ENH-681: alfresco webdav does not respect webdav locks 19624: ALF-2231: Merged DEV/BELARUS/V2.2-2009_12_01 to V3.2 17704: ENH-681: alfresco webdav does not respect webdav locks 19623: ALF-1890: Correction to previous checkin to allow defaulting of request body charset 19617: ALF-1890: Improvements to make ALL WebDAV methods retryable - Solution from PutMethod promoted to request wrapper that will handle ALL calls to getInputStream and getReader 19614: ALF-1890: Merged V2.2 to V3.2 17709: Merged DEV_TEMPORARY to V2.2 17700: ETWOTWO-1393: concurrent writes to webdav lead to data loss (0kb resulting file) 19613: Merged DEV/BELARUS/V2.2-2010_02_03 to V2.2 19157: ALF-1890: concurrent writes to webdav lead to data loss (0kb resulting file) 19803: ALF-558: File servers (CIFS / FTP / NFS) can now handle concurrent write operations on Alfresco repository - ContentDiskDriver / AVMDiskDriver now use retrying transactions for write operations - Disable EagerContentStoreCleaner on ContentDiskDriver / AVMDiskDriver closeFile() operations so that they may be retried after rollback (Sony zero byte problem) - Allow manual association of AVM ContentData with nodes so that closeFile() may be retried - Propagation of new argument through AVM interfaces 19804: (RECORD ONLY) Merged PATCHES/V3.2.0 to PATCHES/V3.2.r Merged HEAD to V3.2.0 19786: Refactor of previous test fix. I have pushed down the OOo-specific parts of the change from AbstractContentTransformerTest to OpenOfficeContentTransformerTest leaving an extension point in the base class should other transformations need to be excluded in the future. 19785: Fix for failing test OpenOfficeContentTransformerTest.testAllConversions. Various OOo-related transformations are returned as available but fail on our test server with OOo on it. Pending further work on these failings, I am disabling those transformations in test code whilst leaving them available in the product code. This is because in the wild a different OOo version may succeed with these transformations. I had previously explicitly disabled 3 transformations in the product and I am moving that restriction from product to test code for the same reason. 19707: Return value from isTransformationBlocked was inverted. Fixed now. 19705: Refinement of previous check-in re OOo transformations. I have pulled up the code that handles blocked transformations into a superclass so that the JodConverter-based transformer worker can inherit the same list of blocked transformations. To reiterate, blocked transformations are those that the OOo integration code believes should work but which are broken in practice. These are blocked by the transformers and will always be unavailable regardless of the OOo connection state. 19702: Fix for HEAD builds running on panda build server. OOo was recently installed on panda which has activated various OOo-related transformations/extractions in the test code. It appears that OOo does not support some transformations from Office 97 to Office 2007. Specifically doc to docx and xls to xlsx. These transformations have now been marked as unavailable. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@20004 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
479 lines
14 KiB
Java
479 lines
14 KiB
Java
/*
|
|
* Copyright (C) 2005-2010 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.filesys.repo.desk;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.File;
|
|
import java.io.FileReader;
|
|
import java.io.IOException;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.StringTokenizer;
|
|
import java.util.concurrent.Callable;
|
|
|
|
import org.springframework.extensions.config.ConfigElement;
|
|
import org.alfresco.filesys.alfresco.AlfrescoContext;
|
|
import org.alfresco.filesys.alfresco.AlfrescoDiskDriver;
|
|
import org.alfresco.filesys.alfresco.DesktopAction;
|
|
import org.alfresco.filesys.alfresco.DesktopActionException;
|
|
import org.alfresco.filesys.alfresco.DesktopParams;
|
|
import org.alfresco.filesys.alfresco.DesktopResponse;
|
|
import org.alfresco.jlan.server.filesys.DiskSharedDevice;
|
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
|
import org.alfresco.scripts.ScriptException;
|
|
import org.alfresco.service.cmr.repository.ScriptService;
|
|
import org.alfresco.util.ResourceFinder;
|
|
import org.springframework.core.io.Resource;
|
|
|
|
/**
|
|
* Javascript Desktop Action Class
|
|
*
|
|
* <p>Run a server-side script against the target node(s).
|
|
*
|
|
* @author gkspencer
|
|
*/
|
|
public class JavaScriptDesktopAction extends DesktopAction {
|
|
|
|
// Script name
|
|
|
|
private String m_scriptName;
|
|
|
|
// Script file details
|
|
|
|
private String m_scriptPath;
|
|
private long m_lastModified;
|
|
|
|
// Script string
|
|
|
|
private String m_script;
|
|
|
|
/**
|
|
* Class constructor
|
|
*/
|
|
public JavaScriptDesktopAction()
|
|
{
|
|
super( 0, 0);
|
|
}
|
|
|
|
/**
|
|
* Return the confirmation string to be displayed by the client
|
|
*
|
|
* @return String
|
|
*/
|
|
@Override
|
|
public String getConfirmationString()
|
|
{
|
|
return "Run Javascript action";
|
|
}
|
|
|
|
/**
|
|
* Perform standard desktop action initialization
|
|
*
|
|
* @param global ConfigElement
|
|
* @param config ConfigElement
|
|
* @param fileSys DiskSharedDevice
|
|
* @exception DesktopActionException
|
|
*/
|
|
@Override
|
|
public void standardInitialize(ConfigElement global, ConfigElement config, DiskSharedDevice fileSys)
|
|
throws DesktopActionException
|
|
{
|
|
// Perform standard initialization
|
|
super.standardInitialize(global, config, fileSys);
|
|
|
|
// Get the script file name and check that it exists
|
|
|
|
ConfigElement elem = config.getChild("script");
|
|
if ( elem != null && elem.getValue().length() > 0)
|
|
{
|
|
// Set the script name
|
|
setScriptName(elem.getValue());
|
|
}
|
|
else
|
|
throw new DesktopActionException("Script name not specified");
|
|
|
|
// check if the desktop action attributes have been specified
|
|
|
|
elem = config.getChild("attributes");
|
|
if ( elem != null)
|
|
{
|
|
// Check if the attribute string is empty
|
|
|
|
if ( elem.getValue().length() == 0)
|
|
throw new DesktopActionException("Empty desktop action attributes");
|
|
|
|
// Parse the attribute string
|
|
setAttributeList(elem.getValue());
|
|
}
|
|
|
|
// Check if the desktop action pre-processing options have been specified
|
|
|
|
elem = config.getChild("preprocess");
|
|
if ( elem != null)
|
|
{
|
|
setPreprocess(elem.getValue());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void initializeAction(AlfrescoDiskDriver filesysDriver, AlfrescoContext filesysContext)
|
|
throws DesktopActionException
|
|
{
|
|
// Perform standard initialization
|
|
|
|
super.initializeAction(filesysDriver, filesysContext);
|
|
|
|
// Get the script file name and check that it exists
|
|
|
|
if ( m_scriptName == null || m_scriptName.length() == 0)
|
|
{
|
|
throw new DesktopActionException("Script name not specified");
|
|
}
|
|
|
|
// Check if the script exists on the classpath
|
|
Resource resource = new ResourceFinder().getResource(m_scriptName);
|
|
if (!resource.exists())
|
|
{
|
|
throw new DesktopActionException("Failed to find script on classpath, " + getScriptName());
|
|
}
|
|
|
|
|
|
// Check that the script file exists
|
|
File scriptFile;
|
|
try
|
|
{
|
|
scriptFile = resource.getFile();
|
|
if (scriptFile.exists() == false)
|
|
throw new DesktopActionException("Script file not found, " + m_scriptName);
|
|
}
|
|
catch (IOException e)
|
|
{
|
|
throw new DesktopActionException("Unable to resolve script as a file, " + resource.getDescription());
|
|
}
|
|
|
|
m_scriptPath = scriptFile.getAbsolutePath();
|
|
m_lastModified =scriptFile.lastModified();
|
|
|
|
// Load the script
|
|
|
|
try
|
|
{
|
|
loadScript( scriptFile);
|
|
}
|
|
catch ( IOException ex)
|
|
{
|
|
throw new DesktopActionException( "Failed to load script, " + ex.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Run the desktop action
|
|
*
|
|
* @param params DesktopParams
|
|
* @return DesktopResponse
|
|
*/
|
|
@Override
|
|
public DesktopResponse runAction(DesktopParams params)
|
|
throws DesktopActionException
|
|
{
|
|
File scriptFile = new File(m_scriptPath);
|
|
|
|
synchronized (this)
|
|
{
|
|
if (scriptFile.lastModified() != m_lastModified)
|
|
{
|
|
// Reload the script
|
|
|
|
m_lastModified = scriptFile.lastModified();
|
|
|
|
try
|
|
{
|
|
loadScript(scriptFile);
|
|
}
|
|
catch (IOException ex)
|
|
{
|
|
// Check if the script file has been changed
|
|
return new DesktopResponse(StsError, "Failed to reload script file, " + getScriptName());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Access the script service
|
|
final ScriptService scriptService = getServiceRegistry().getScriptService();
|
|
|
|
if ( scriptService != null)
|
|
{
|
|
// Create the objects to be passed to the script
|
|
|
|
final Map<String, Object> model = new HashMap<String, Object>();
|
|
model.put("deskParams", params);
|
|
model.put("out", System.out);
|
|
|
|
// Add the webapp URL, if valid
|
|
|
|
if ( hasWebappURL())
|
|
model.put("webURL", getWebappURL());
|
|
|
|
// Compute the response in a retryable write transaction
|
|
return params.getDriver().doInWriteTransaction(params.getSession(), new Callable<DesktopResponse>()
|
|
{
|
|
|
|
public DesktopResponse call() throws Exception
|
|
{
|
|
DesktopResponse response = new DesktopResponse(StsSuccess);
|
|
|
|
// Run the script
|
|
|
|
Object result = null;
|
|
|
|
try
|
|
{
|
|
// Run the script
|
|
|
|
result = scriptService.executeScriptString(getScript(), model);
|
|
|
|
// Check the result
|
|
|
|
if (result != null)
|
|
{
|
|
// Check for a full response object
|
|
|
|
if (result instanceof DesktopResponse)
|
|
{
|
|
response = (DesktopResponse) result;
|
|
}
|
|
|
|
// Status code only response
|
|
|
|
else if (result instanceof Double)
|
|
{
|
|
Double jsSts = (Double) result;
|
|
response.setStatus(jsSts.intValue(), "");
|
|
}
|
|
|
|
// Encoded response in the format '<stsCode>,<stsMessage>'
|
|
|
|
else if (result instanceof String)
|
|
{
|
|
String responseMsg = (String) result;
|
|
|
|
// Parse the status message
|
|
|
|
StringTokenizer token = new StringTokenizer(responseMsg, ",");
|
|
String stsToken = token.nextToken();
|
|
String msgToken = token.nextToken();
|
|
|
|
int sts = -1;
|
|
try
|
|
{
|
|
sts = Integer.parseInt(stsToken);
|
|
}
|
|
catch (NumberFormatException ex)
|
|
{
|
|
response.setStatus(StsError, "Bad response from script");
|
|
}
|
|
|
|
// Set the response
|
|
|
|
response.setStatus(sts, msgToken != null ? msgToken : "");
|
|
}
|
|
}
|
|
}
|
|
catch (ScriptException ex)
|
|
{
|
|
if (RetryingTransactionHelper.extractRetryCause(ex) != null)
|
|
{
|
|
throw ex;
|
|
}
|
|
|
|
// Set the error response for the client
|
|
response.setStatus(StsError, ex.getMessage());
|
|
}
|
|
|
|
// Return the response
|
|
|
|
return response;
|
|
}
|
|
});
|
|
}
|
|
else
|
|
{
|
|
// Return an error response, script service not available
|
|
|
|
return new DesktopResponse(StsError, "Script service not available");
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Get the script name
|
|
*
|
|
* @return String
|
|
*/
|
|
public final String getScriptName()
|
|
{
|
|
return m_scriptName;
|
|
}
|
|
|
|
/**
|
|
* Return the script data
|
|
*
|
|
* @return String
|
|
*/
|
|
public final String getScript()
|
|
{
|
|
return m_script;
|
|
}
|
|
|
|
/**
|
|
* Set the script name
|
|
*
|
|
* @param name String
|
|
*/
|
|
public final void setScriptName(String name)
|
|
{
|
|
m_scriptName = name;
|
|
}
|
|
|
|
/**
|
|
* Set the action attributes
|
|
*
|
|
* @param attributes String
|
|
* @throws DesktopActionException
|
|
*/
|
|
public void setAttributeList(String attributes) throws DesktopActionException
|
|
{
|
|
// Check if the attribute string is empty
|
|
if ( attributes == null || attributes.length() == 0)
|
|
{
|
|
return;
|
|
}
|
|
// Parse the attribute string
|
|
|
|
int attr = 0;
|
|
StringTokenizer tokens = new StringTokenizer( attributes, ",");
|
|
|
|
while ( tokens.hasMoreTokens())
|
|
{
|
|
// Get the current attribute token and validate
|
|
|
|
String token = tokens.nextToken().trim();
|
|
|
|
if ( token.equalsIgnoreCase( "targetFiles"))
|
|
attr |= AttrTargetFiles;
|
|
else if ( token.equalsIgnoreCase( "targetFolders"))
|
|
attr |= AttrTargetFolders;
|
|
else if ( token.equalsIgnoreCase( "clientFiles"))
|
|
attr |= AttrClientFiles;
|
|
else if ( token.equalsIgnoreCase( "clientFolders"))
|
|
attr |= AttrClientFolders;
|
|
else if ( token.equalsIgnoreCase( "alfrescoFiles"))
|
|
attr |= AttrAlfrescoFiles;
|
|
else if ( token.equalsIgnoreCase( "alfrescoFolders"))
|
|
attr |= AttrAlfrescoFolders;
|
|
else if ( token.equalsIgnoreCase( "multiplePaths"))
|
|
attr |= AttrMultiplePaths;
|
|
else if ( token.equalsIgnoreCase( "allowNoParams"))
|
|
attr |= AttrAllowNoParams;
|
|
else if ( token.equalsIgnoreCase( "anyFiles"))
|
|
attr |= AttrAnyFiles;
|
|
else if ( token.equalsIgnoreCase( "anyFolders"))
|
|
attr |= AttrAnyFolders;
|
|
else if ( token.equalsIgnoreCase( "anyFilesFolders"))
|
|
attr |= AttrAnyFilesFolders;
|
|
else
|
|
throw new DesktopActionException("Unknown attribute, " + token);
|
|
}
|
|
setAttributes(attr);
|
|
}
|
|
|
|
/**
|
|
* Set the client side pre-processing actions
|
|
*
|
|
* @param preProcessActions String
|
|
* @throws DesktopActionException
|
|
*/
|
|
public void setPreprocess(String preProcessActions) throws DesktopActionException
|
|
{
|
|
// Check if the pre-process string is empty
|
|
|
|
if ( preProcessActions == null || preProcessActions.length() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int pre = 0;
|
|
|
|
// Parse the pre-process string
|
|
|
|
StringTokenizer tokens = new StringTokenizer( preProcessActions, ",");
|
|
|
|
while ( tokens.hasMoreTokens())
|
|
{
|
|
// Get the current pre-process token and validate
|
|
|
|
String token = tokens.nextToken().trim();
|
|
|
|
if ( token.equalsIgnoreCase( "copyToTarget"))
|
|
pre |= PreCopyToTarget;
|
|
else if ( token.equalsIgnoreCase( "confirm"))
|
|
pre |= PreConfirmAction;
|
|
else if ( token.equalsIgnoreCase( "localToWorkingCopy"))
|
|
pre |= PreLocalToWorkingCopy;
|
|
else
|
|
throw new DesktopActionException("Unknown pre-processing flag, " + token);
|
|
}
|
|
|
|
// Set the action pre-processing flags
|
|
|
|
setPreProcessActions( pre);
|
|
}
|
|
|
|
/**
|
|
* Load, or reload, the script
|
|
*
|
|
* @param scriptFile File
|
|
*/
|
|
private final void loadScript(File scriptFile)
|
|
throws IOException
|
|
{
|
|
// Open the script file
|
|
|
|
BufferedReader scriptIn = new BufferedReader(new FileReader( scriptFile));
|
|
StringBuilder scriptStr = new StringBuilder((int) scriptFile.length() + 256);
|
|
|
|
String inRec = scriptIn.readLine();
|
|
|
|
while ( inRec != null)
|
|
{
|
|
scriptStr.append( inRec);
|
|
scriptStr.append( "\n");
|
|
inRec = scriptIn.readLine();
|
|
}
|
|
|
|
// Close the script file
|
|
|
|
scriptIn.close();
|
|
|
|
// Update the script string
|
|
|
|
m_script = scriptStr.toString();
|
|
}
|
|
}
|