mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged V3.4-BUG-FIX to HEAD
28650: Merged DEV/TEMPORARY to V3.4-BUG-FIX 28637: ALF-5601: WCM Reviewer should be able to modify 'Launch Date' of the review item. Set "wcmwf:launchDate" to read-only on "submitpendingTask". 28697: Fix for ALF-2711 - Fix to handle incorrect (negative size!) content length headers sent by Adobe Flash when uploading files over 2GB. 28702: Merged DEV to V3.4-BUG-FIX 28693: ALF-9314: Unable to add to multi-valued properties via AVM Console The node property value of Collection type must be set within square braces as a comma separated values without spaces. E.g. [aaa,bbb,ccc] 28718: Merged PATCHES/V3.4.2 to V3.4-BUG-FIX 28569: ALF-9253 / ALF-9166: 'A valid SecureContext was not provided in the RequestContext' exception on startup following upgrade to 3.4.1 28618: ALF-8385 / ALF-9364: Merged DEV/TEMPORARY to PATCHES/V3.4.2 28565: ALF-5887 Addition of RenameUser command line toolContext - PersonServiceImpl should not disable normal behaviour when handling duplicate Person NodeRefs as the userAuthorityCache does not get updated correctly - Tool (base class for Import, Export and RenameUser command line tools) should not automatically login if setLogin(false) has been called. 28719: Merged V3.4 to V3.4-BUG-FIX 28648: ALF-9103: Remove obsolete (and mis-spelled) use-old-dm-alcs-context.xml.sample 28701: Corrected library for - Fix for ALF-7860 - Regression: Close button doesn't work in Node Browser git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@28721 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
561
source/java/org/alfresco/tools/RenameUser.java
Normal file
561
source/java/org/alfresco/tools/RenameUser.java
Normal file
@@ -0,0 +1,561 @@
|
||||
/*
|
||||
* 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.tools;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.IllegalCharsetNameException;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.batch.BatchProcessWorkProvider;
|
||||
import org.alfresco.repo.batch.BatchProcessor;
|
||||
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker;
|
||||
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorkerAdaptor;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.security.person.PersonServiceImpl;
|
||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.NoSuchPersonException;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.VmShutdownListener;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Rename user tool. This tool provides minimal support for renaming users.
|
||||
* See {@link displayHelp} message for restrictions.
|
||||
* <pre>
|
||||
* Usage: renameUser -user username [options] oldUsername newUsername");
|
||||
* renameUser -user username [options] -file filename");
|
||||
* </pre>
|
||||
* The csv file has a simple comma separated list, with
|
||||
* a pair of usernames on each line. Comments and blank
|
||||
* lines may also be included. For example:
|
||||
* <pre>
|
||||
* # List of usernames to change
|
||||
*
|
||||
* # oldUsername,newUsername
|
||||
* johnp,ceo # President and CEO
|
||||
* johnn,cto # CTO and Chairman
|
||||
* </pre>
|
||||
*
|
||||
* @author Alan Davis
|
||||
*/
|
||||
public class RenameUser extends Tool
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(RenameUser.class);
|
||||
|
||||
/** User Rename Tool Context */
|
||||
protected RenameUserToolContext context;
|
||||
private boolean login = true;
|
||||
|
||||
PersonService personService;
|
||||
NodeService nodeService;
|
||||
|
||||
private PersonService getPersonService()
|
||||
{
|
||||
if (personService == null)
|
||||
{
|
||||
personService = getServiceRegistry().getPersonService();
|
||||
}
|
||||
return personService;
|
||||
}
|
||||
|
||||
private NodeService getNodeService()
|
||||
{
|
||||
if (nodeService == null)
|
||||
{
|
||||
nodeService = getServiceRegistry().getNodeService();
|
||||
}
|
||||
return nodeService;
|
||||
}
|
||||
|
||||
public void setLogin(boolean login)
|
||||
{
|
||||
this.login = login;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry Point
|
||||
*
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args)
|
||||
{
|
||||
Tool tool = new RenameUser();
|
||||
tool.start(args);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.tools.Tool#processArgs(java.lang.String[])
|
||||
*/
|
||||
@Override
|
||||
protected ToolContext processArgs(String[] args)
|
||||
throws ToolArgumentException
|
||||
{
|
||||
context = new RenameUserToolContext();
|
||||
context.setLogin(login);
|
||||
|
||||
int i = 0;
|
||||
while (i < args.length)
|
||||
{
|
||||
if (args[i].equals("-h") || args[i].equals("-help"))
|
||||
{
|
||||
context.setHelp(true);
|
||||
break;
|
||||
}
|
||||
else if (args[i].equals("-user"))
|
||||
{
|
||||
i++;
|
||||
if (i == args.length || args[i].length() == 0)
|
||||
{
|
||||
throw new ToolArgumentException("The value <user> for the option -user must be specified");
|
||||
}
|
||||
context.setUsername(args[i]);
|
||||
}
|
||||
else if (args[i].equals("-pwd"))
|
||||
{
|
||||
i++;
|
||||
if (i == args.length || args[i].length() == 0)
|
||||
{
|
||||
throw new ToolArgumentException("The value <password> for the option -pwd must be specified");
|
||||
}
|
||||
context.setPassword(args[i]);
|
||||
}
|
||||
else if (args[i].equals("-encoding"))
|
||||
{
|
||||
i++;
|
||||
if (i == args.length || args[i].length() == 0)
|
||||
{
|
||||
throw new ToolArgumentException("The value <encoding> for the option -encoding must be specified");
|
||||
}
|
||||
try
|
||||
{
|
||||
context.encoding = Charset.forName(args[i]);
|
||||
}
|
||||
catch (IllegalCharsetNameException e)
|
||||
{
|
||||
throw new ToolArgumentException("The value <encoding> is not recognised");
|
||||
}
|
||||
catch (UnsupportedCharsetException e)
|
||||
{
|
||||
throw new ToolArgumentException("The value <encoding> is unsupported");
|
||||
}
|
||||
}
|
||||
else if (args[i].equals("-quiet"))
|
||||
{
|
||||
context.setQuiet(true);
|
||||
}
|
||||
else if (args[i].equals("-verbose"))
|
||||
{
|
||||
context.setVerbose(true);
|
||||
}
|
||||
else if (args[i].equals("-f") || args[i].equals("-file"))
|
||||
{
|
||||
i++;
|
||||
if (i == args.length || args[i].length() == 0)
|
||||
{
|
||||
throw new ToolArgumentException("The value <filename> for the option -file must be specified");
|
||||
}
|
||||
context.setFilename(args[i]);
|
||||
}
|
||||
else if (!args[i].startsWith("-"))
|
||||
{
|
||||
i++;
|
||||
if (i == args.length || args[i-1].trim().length() == 0 || args[i].trim().length() == 0)
|
||||
{
|
||||
throw new ToolArgumentException("Both <oldUsername> <newUsername> must be specified");
|
||||
}
|
||||
if (context.userCount() > 0)
|
||||
{
|
||||
throw new ToolArgumentException("Only one <oldUsername> <newUsername> pair may be " +
|
||||
"specified on the command line. See the -file option");
|
||||
}
|
||||
String oldUsername = args[i-1].trim();
|
||||
String newUsername = args[i].trim();
|
||||
String error = context.add(-1, null, oldUsername, newUsername);
|
||||
if (error != null)
|
||||
{
|
||||
throw new ToolArgumentException(error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ToolArgumentException("Unknown option " + args[i]);
|
||||
}
|
||||
|
||||
// next argument
|
||||
i++;
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.tools.Tool#displayHelp()
|
||||
*/
|
||||
protected @Override
|
||||
/*package*/ void displayHelp()
|
||||
{
|
||||
logError("This tool provides minimal support for renaming users. It fixes");
|
||||
logError("authorities, group memberships and current zone (older versions");
|
||||
logError("still require a property change).");
|
||||
logError("");
|
||||
logError("WARNING: It does NOT change properties that store the username such");
|
||||
logError(" as (creator, modifier, lock owner or owner). Of these owner");
|
||||
logError(" and lock affect user rights. The username is also used");
|
||||
logError(" directly in workflow, for RM caveats, for Share invites and");
|
||||
logError(" auditing");
|
||||
logError("");
|
||||
logError("Usage: renameUser -user username [options] oldUsername newUsername");
|
||||
logError(" renameUser -user username [options] -file filename");
|
||||
logError("");
|
||||
logError(" username: username for login");
|
||||
logError("oldUsername: current username ");
|
||||
logError("newUsername: replacement username ");
|
||||
logError("");
|
||||
logError("Options:");
|
||||
logError(" -h[elp] display this help");
|
||||
logError(" -pwd password for login");
|
||||
logError(" -f[ile] csv file of old and new usernames");
|
||||
logError(" -encoding for source file (default: " + Charset.defaultCharset() + ")");
|
||||
logError(" -quiet do not display any messages during rename");
|
||||
logError(" -verbose report rename progress");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.tools.Tool#getToolName()
|
||||
*/
|
||||
@Override
|
||||
protected String getToolName()
|
||||
{
|
||||
return "Alfresco Rename User";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.tools.Tool#execute()
|
||||
*/
|
||||
@Override
|
||||
protected int execute() throws ToolException
|
||||
{
|
||||
// Used for ability to be final and have a set
|
||||
final AtomicInteger status = new AtomicInteger(0);
|
||||
|
||||
BatchProcessWorker<User> worker = new BatchProcessWorkerAdaptor<User>()
|
||||
{
|
||||
public void process(final User user) throws Throwable
|
||||
{
|
||||
RunAsWork<Void> runAsWork = new RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
renameUser(user.getOldUsername(), user.getNewUsername());
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
status.set(handleError(t));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
AuthenticationUtil.runAs(runAsWork, context.getUsername());
|
||||
}
|
||||
};
|
||||
|
||||
// Use 2 threads, 20 User objects per transaction. Log every 100 entries.
|
||||
BatchProcessor<User> processor = new BatchProcessor<User>(
|
||||
"HomeFolderProviderSynchronizer",
|
||||
getServiceRegistry().getTransactionService().getRetryingTransactionHelper(),
|
||||
new WorkProvider(context),
|
||||
2, 20,
|
||||
null,
|
||||
logger, 100);
|
||||
processor.process(worker, true);
|
||||
|
||||
return status.get();
|
||||
}
|
||||
|
||||
private void renameUser(String oldUsername, String newUsername)
|
||||
{
|
||||
logInfo("\""+oldUsername+"\" --> \""+newUsername+"\"");
|
||||
try
|
||||
{
|
||||
NodeRef person = getPersonService().getPerson(oldUsername, false);
|
||||
|
||||
// Allow us to update the username just like the LDAP process
|
||||
AlfrescoTransactionSupport.bindResource(PersonServiceImpl.KEY_ALLOW_UID_UPDATE, Boolean.TRUE);
|
||||
|
||||
// Update the username property which will result in a PersonServiceImpl.onUpdateProperties call
|
||||
// on commit.
|
||||
getNodeService().setProperty(person, ContentModel.PROP_USERNAME, newUsername);
|
||||
}
|
||||
catch (NoSuchPersonException e)
|
||||
{
|
||||
logError("User does not exist: "+oldUsername);
|
||||
}
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
private final String oldUsername;
|
||||
private final String newUsername;
|
||||
|
||||
public User(String oldUsername, String newUsername)
|
||||
{
|
||||
this.oldUsername = oldUsername;
|
||||
this.newUsername = newUsername;
|
||||
}
|
||||
|
||||
public String getOldUsername()
|
||||
{
|
||||
return oldUsername;
|
||||
}
|
||||
|
||||
public String getNewUsername()
|
||||
{
|
||||
return newUsername;
|
||||
}
|
||||
}
|
||||
|
||||
public class RenameUserToolContext extends ToolContext
|
||||
{
|
||||
/**
|
||||
* Old and new usernames to change.
|
||||
*/
|
||||
private List<User> usernames = new ArrayList<User>();
|
||||
|
||||
// Internal - used check the name has not been used before.
|
||||
private Set<String> uniqueNames = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* Source filename of usernames.
|
||||
*/
|
||||
private String filename;
|
||||
|
||||
/**
|
||||
* Encoding of filename of usernames.
|
||||
*/
|
||||
private Charset encoding = Charset.defaultCharset();
|
||||
|
||||
public void setFilename(String filename)
|
||||
{
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public String add(int lineNumber, String line, String oldUsername, String newUsername)
|
||||
{
|
||||
String error = null;
|
||||
if (oldUsername.equals(newUsername))
|
||||
{
|
||||
error = "Old and new usernames are the same";
|
||||
if (line != null)
|
||||
error = "Error on line " + lineNumber + " ("+error+"): " + line;
|
||||
}
|
||||
else if (uniqueNames.contains(oldUsername))
|
||||
{
|
||||
error = "Old username already specified";
|
||||
if (line != null)
|
||||
error = "Error on line " + lineNumber + " ("+error+"): " + line;
|
||||
}
|
||||
else if (uniqueNames.contains(newUsername))
|
||||
{
|
||||
error = "New username already specified";
|
||||
if (line != null)
|
||||
error = "Error on line " + lineNumber + " ("+error+"): " + line;
|
||||
}
|
||||
else
|
||||
{
|
||||
add(new User(oldUsername, newUsername));
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
private void add(User user)
|
||||
{
|
||||
usernames.add(user);
|
||||
uniqueNames.add(user.getOldUsername());
|
||||
uniqueNames.add(user.getNewUsername());
|
||||
}
|
||||
|
||||
public int userCount()
|
||||
{
|
||||
return usernames.size();
|
||||
}
|
||||
|
||||
public Iterator<User> iterator()
|
||||
{
|
||||
return usernames.iterator();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.tools.ToolContext#validate()
|
||||
*/
|
||||
@Override
|
||||
/*package*/ void validate()
|
||||
{
|
||||
super.validate();
|
||||
|
||||
if (filename != null)
|
||||
{
|
||||
if (userCount() > 0)
|
||||
{
|
||||
throw new ToolArgumentException("<filename> should not have been specified if " +
|
||||
"<oldUsername> <newUsername> has been specified on the command line.");
|
||||
}
|
||||
File file = new File(filename);
|
||||
if (!file.exists())
|
||||
{
|
||||
throw new ToolArgumentException("File " + filename + " does not exist.");
|
||||
}
|
||||
if (!readFile(file))
|
||||
{
|
||||
throw new ToolArgumentException("File " + filename + " contained errors.");
|
||||
}
|
||||
}
|
||||
|
||||
if (userCount() == 0)
|
||||
{
|
||||
throw new ToolArgumentException("No old and new usernames have been specified.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the user names out of the file.
|
||||
* @param file to be read
|
||||
* @return {@code true} if there were no problems found with the file contents.
|
||||
*/
|
||||
private boolean readFile(File file)
|
||||
{
|
||||
BufferedReader in = null;
|
||||
boolean noErrors = true;
|
||||
try
|
||||
{
|
||||
in = new BufferedReader(new InputStreamReader(new FileInputStream(file), encoding.name()));
|
||||
int lineNumber = 1;
|
||||
for (String line = in.readLine(); line != null; line = in.readLine(), lineNumber++)
|
||||
{
|
||||
int i = line.indexOf('#');
|
||||
if (i != -1)
|
||||
{
|
||||
line = line.substring(0, i);
|
||||
}
|
||||
if (line.trim().length() != 0)
|
||||
{
|
||||
String[] names = line.split(",");
|
||||
String oldUsername = names[0].trim();
|
||||
String newUsername = names[1].trim();
|
||||
if (names.length != 2 || oldUsername.length() == 0 || newUsername.length() == 0)
|
||||
{
|
||||
RenameUser.this.logError("Error on line " + lineNumber + ": " + line);
|
||||
noErrors = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
String error = context.add(lineNumber, line, oldUsername, newUsername);
|
||||
if (error != null)
|
||||
{
|
||||
RenameUser.this.logError(error);
|
||||
noErrors = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new ToolArgumentException("Failed to read <filename>.", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (in != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
in.close();
|
||||
} catch (IOException e)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
return noErrors;
|
||||
}
|
||||
}
|
||||
|
||||
// BatchProcessWorkProvider returns batches of 100 User objects.
|
||||
private class WorkProvider implements BatchProcessWorkProvider<User>
|
||||
{
|
||||
private static final int BATCH_SIZE = 100;
|
||||
|
||||
private final VmShutdownListener vmShutdownLister = new VmShutdownListener("getRenameUserWorkProvider");
|
||||
private final Iterator<User> iterator;
|
||||
private final int size;
|
||||
|
||||
public WorkProvider(RenameUserToolContext context)
|
||||
{
|
||||
iterator = context.iterator();
|
||||
size = context.userCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getTotalEstimatedWorkSize()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Collection<User> getNextWork()
|
||||
{
|
||||
if (vmShutdownLister.isVmShuttingDown())
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Collection<User> results = new ArrayList<User>(BATCH_SIZE);
|
||||
while (results.size() < BATCH_SIZE && iterator.hasNext())
|
||||
{
|
||||
results.add(iterator.next());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user