Renommer Utilisateur Documentum
Il est assez courant de devoir renommer un utilisateur déclaré dans Documentum, suite à une erreur de saisie ou le traditionnel changement de nom suite à un mariage. Bon nombre d'administrateurs se contenteront d'aller sur le premier DA venu et de lancer l'action "Renommer" sur l'utilisateur concerné.
Mais qu'en est il vraiment au niveau du serveur. Cet article présente l'ensemble des impacts sur la docbase, et comment se passer facilement de DA, voir même des DFCs.
Sommaire
Votre avis
Nobody voted on this yet
|
|
Analyse DA version 6.7 SP1
Définition action
Le composant userrename
est défini dans le fichier webcomponent/config/admin/user/userrename_component.xml
avec la configuration suivante:
<component id="userrename">
<params>
<param name="objectname" required="true"></param>
<param name="objectId" required="true"></param>
</params>
<!-- Component Layout -->
<pages>
<start>/webcomponent/admin/user/userrename.jsp</start>
</pages>
<!-- Component Behavior -->
<class>com.documentum.webcomponent.admin.user.UserRename</class>
<nlsbundle>com.documentum.webcomponent.admin.user.UserRenameNlsProp</nlsbundle>
<!-- Component specific Configuration -->
<helpcontextid>userrename</helpcontextid>
</component>
Ceci permet d'identifier la classe a étudier.
Classe instance
Comme pour tout composant, la méthode onCommitChanges
est exécutée lors de l'enregistrement des modifications faites sur l'interface.
public boolean onCommitChanges()
{
boolean fSuccess = false;
validate();
boolean reportOnly = ((Radio)getControl("onlyreport")).getValue();
if (getIsValid())
{
try
{
String usersNewName = ((Text)getControl("userrenametextbox")).getValue();
boolean isJobRunNow = ((Radio)getControl("renamenow")).getValue();
boolean unlockObjects = ((Radio)getControl("checkedoutobjectsunlock")).getValue();
IDfUser userObj = getDfSession().getUser(this.m_userName);
userObj.renameUser(usersNewName, isJobRunNow, unlockObjects, reportOnly);
fSuccess = true;
}
catch (DfException exp)
{
ErrorMessageService.getService().setNonFatalError(this, "MSG_ERROR_USER_RENAME", exp);
}
}
if ((fSuccess) && (!reportOnly))
{
MessageService.addMessage(this, "MSG_REASSIGN_USER_SUCCESS");
}
return fSuccess;
}
Nous pouvons donc constater que le changement de nom est directement disponible dans les DFCs. L'interface est utilisée uniquement pour spécifier les paramètres d'exécution.
Analyse DFC version 6.7 SP1
L'analyse du DA montre en évidence l'utilisation de la méthode renameUser
sur l'instance de IDfUser
lié à l'utilisateur traité. Il existe une seule implémentation de cette interface, à savoir la classe DfUser
dans le package com.documentum.fc.client
.
Classe DfUser
Méthode renameUser
Très concrètement, cette méthode n'effectue rien de particulier. C'est juste une exposition de la méthode doRenameUser
public void renameUser(String userName, boolean immediate, boolean unlockObjects, boolean reportOnly)
throws DfException
{
org.aspectj.lang.JoinPoint joinpoint;
String s;
boolean flag;
boolean flag1;
boolean flag2;
s = userName;
flag = immediate;
flag1 = unlockObjects;
flag2 = reportOnly;
joinpoint = null;
if(BaseTracingAspect.ajc$if_0())
{
if(joinpoint == null)
{
Object aobj[] = new Object[4];
aobj[0] = s;
aobj[1] = Conversions.booleanObject(flag);
aobj[2] = Conversions.booleanObject(flag1);
aobj[3] = Conversions.booleanObject(flag2);
joinpoint = Factory.makeJP(ajc$tjp_98, this, this, aobj);
}
TracingAspect.aspectOf().ajc$before$com_documentum_fc_tracing_impl_aspects_TracingAspect$3$cbec3e36(joinpoint);
}
doRenameUser(userName, immediate, unlockObjects, reportOnly, NO_ARGS);
Object obj = null;
if(BaseTracingAspect.ajc$if_0())
{
if(joinpoint == null)
{
Object aobj1[] = new Object[4];
aobj1[0] = s;
aobj1[1] = Conversions.booleanObject(flag);
aobj1[2] = Conversions.booleanObject(flag1);
aobj1[3] = Conversions.booleanObject(flag2);
joinpoint = Factory.makeJP(ajc$tjp_98, this, this, aobj1);
}
TracingAspect.aspectOf().ajc$afterReturning$com_documentum_fc_tracing_impl_aspects_TracingAspect$9$b2797f1(obj, joinpoint);
}
return;
Throwable throwable;
throwable;
if(BaseTracingAspect.ajc$if_0())
{
if(joinpoint == null)
{
Object aobj2[] = new Object[4];
aobj2[0] = s;
aobj2[1] = Conversions.booleanObject(flag);
aobj2[2] = Conversions.booleanObject(flag1);
aobj2[3] = Conversions.booleanObject(flag2);
joinpoint = Factory.makeJP(ajc$tjp_98, this, this, aobj2);
}
TracingAspect.aspectOf().ajc$afterThrowing$com_documentum_fc_tracing_impl_aspects_TracingAspect$12$cbec3e36(throwable, joinpoint);
}
throw throwable;
}
Méthode doRenameUser
Avec cette méthode, nous commençons à enfin toucher le coeur de l'exécution.
protected void doRenameUser(String userName, boolean immediate, boolean unlockObjects, boolean reportOnly, Object extendedArgs[])
throws DfException
{
org.aspectj.lang.JoinPoint joinpoint;
String s;
boolean flag;
boolean flag1;
boolean flag2;
Object aobj[];
s = userName;
flag = immediate;
flag1 = unlockObjects;
flag2 = reportOnly;
aobj = extendedArgs;
joinpoint = null;
if(BaseTracingAspect.ajc$if_0())
{
if(joinpoint == null)
{
Object aobj1[] = new Object[5];
aobj1[0] = s;
aobj1[1] = Conversions.booleanObject(flag);
aobj1[2] = Conversions.booleanObject(flag1);
aobj1[3] = Conversions.booleanObject(flag2);
aobj1[4] = ((Object) (aobj));
joinpoint = Factory.makeJP(ajc$tjp_99, this, this, aobj1);
}
TracingAspect.aspectOf().ajc$before$com_documentum_fc_tracing_impl_aspects_TracingAspect$3$cbec3e36(joinpoint);
}
String oldUserName = getUserName();
if(StringUtil.isEmptyOrNull(userName) || !userName.equals(oldUserName))
{
if(isNew())
{
setUserName(userName);
} else
{
IDfJRRenameUser command = (IDfJRRenameUser)DfAdminCommand.getCommand(0);
command.setOldUserName(oldUserName);
command.setNewUserName(userName);
command.setReportOnly(reportOnly);
command.setUnlockObjects(unlockObjects);
command.setImmediate(immediate);
command.execute(getSession());
boolean writeFederationLog = isGloballyManaged() && DfAdminUtils.isDocbaseGoverning(getObjectSession());
if(writeFederationLog)
{
StringBuffer stringBuffer = new StringBuffer(512);
stringBuffer.append("dm_job_request where job_name='UserRename' and request_completed = false and any arguments_values='");
stringBuffer.append(oldUserName);
stringBuffer.append("' and any arguments_values='");
stringBuffer.append(userName);
stringBuffer.append("' order by r_object_id desc");
IDfId jobRequestId = getObjectSession().getIdByQualification(stringBuffer.toString());
if(jobRequestId != null && !jobRequestId.isNull())
DfAdminUtils.writeFederationLog(getObjectSession(), "UserRename", "dm_user", jobRequestId.getId());
}
if(!reportOnly)
setStringInternal("user_name", userName);
}
}
Object obj = null;
if(BaseTracingAspect.ajc$if_0())
{
if(joinpoint == null)
{
Object aobj2[] = new Object[5];
aobj2[0] = s;
aobj2[1] = Conversions.booleanObject(flag);
aobj2[2] = Conversions.booleanObject(flag1);
aobj2[3] = Conversions.booleanObject(flag2);
aobj2[4] = ((Object) (aobj));
joinpoint = Factory.makeJP(ajc$tjp_99, this, this, aobj2);
}
TracingAspect.aspectOf().ajc$afterReturning$com_documentum_fc_tracing_impl_aspects_TracingAspect$9$b2797f1(obj, joinpoint);
}
return;
Throwable throwable;
throwable;
if(BaseTracingAspect.ajc$if_0())
{
if(joinpoint == null)
{
Object aobj3[] = new Object[5];
aobj3[0] = s;
aobj3[1] = Conversions.booleanObject(flag);
aobj3[2] = Conversions.booleanObject(flag1);
aobj3[3] = Conversions.booleanObject(flag2);
aobj3[4] = ((Object) (aobj));
joinpoint = Factory.makeJP(ajc$tjp_99, this, this, aobj3);
}
TracingAspect.aspectOf().ajc$afterThrowing$com_documentum_fc_tracing_impl_aspects_TracingAspect$12$cbec3e36(throwable, joinpoint);
}
throw throwable;
}
Trois actions sont réalisées:
- Exécution d'une commande. Et oui, il va falloir étudier une nouvelle classe.
- En cas d'utilisation de Federation, mise à jour d'une log pour entraîner la réplication.
- Mise à jour de l'instance en cours.
Très concrètement, la première action est la plus courante. L'utilisation de Federation étant un peu moins courante, cela ne concernera que peu de monde.
Enfin la dernière action, mise à jour de l'attribut user_name
paraît "inutile". En effet, la méthode save
n'étant pas appelé, la modification ne sera pas prise en compte par la docbase. nous pouvons imaginé que c'est uniquement pour mettre à jour le cache de la session courante, mais bon cela n'a peu d'intérêt.
Exécution commande
Le gros du travail est donc réalisée à partir d'une instance de l'interface IDfJRRenameUser
.
IDfJRRenameUser command = (IDfJRRenameUser)DfAdminCommand.getCommand(0);
command.setOldUserName(oldUserName);
command.setNewUserName(userName);
command.setReportOnly(reportOnly);
command.setUnlockObjects(unlockObjects);
command.setImmediate(immediate);
command.execute(getSession());
Heureusement, il n'y a qu'une implémentation de cette interface, ce qui va éviter de comprendre l'exécution de (IDfJRRenameUser)DfAdminCommand.getCommand(0)
. La classe étudiée est donc DfJobRequestCommand
du package com.documentum.fc.commands.admin
.
public IDfCollection execute(IDfSession session)
throws DfException
{
org.aspectj.lang.JoinPoint joinpoint;
IDfSession idfsession;
idfsession = session;
joinpoint = null;
if(BaseTracingAspect.ajc$if_0())
{
if(joinpoint == null)
joinpoint = Factory.makeJP(ajc$tjp_20, this, this, idfsession);
TracingAspect.aspectOf().ajc$before$com_documentum_fc_tracing_impl_aspects_TracingAspect$3$cbec3e36(joinpoint);
}
if(validate()) goto _L2; else goto _L1
_L1:
IDfCollection idfcollection = null;
goto _L3
_L2:
int priority = 0;
if(isImmediate())
priority = 1;
String jobObjectName = null;
String jobName = null;
String methodName = null;
Vector argumentKeys = new Vector();
if(m_commandType == 0)
{
jobObjectName = "UserRename";
jobName = "dm_UserRename";
methodName = "dm_UserRename";
argumentKeys.addElement("OldUserName");
argumentKeys.addElement("NewUserName");
argumentKeys.addElement("report_only");
argumentKeys.addElement("unlock_locked_obj");
} else
if(m_commandType == 2)
{
jobObjectName = "GroupRename";
jobName = "dm_GroupRename";
methodName = "dm_GroupRename";
argumentKeys.addElement("OldGroupName");
argumentKeys.addElement("NewGroupName");
argumentKeys.addElement("report_only");
argumentKeys.addElement("unlock_locked_obj");
if(getNewGroupDisplayName() != null)
argumentKeys.addElement("NewGroupDisplayName");
} else
if(m_commandType == 1)
{
jobObjectName = "UserChgHomeDb";
jobName = "dm_UserChgHomeDb";
methodName = "dm_UserChgHomeDb";
argumentKeys.addElement("UserName");
argumentKeys.addElement("NewHomeDocbase");
}
IDfId folderId = getJobRequestFolder(session, jobObjectName);
IDfSysObject jobRequest = (IDfSysObject)session.newObject("dm_job_request");
jobRequest.setObjectName(jobObjectName);
jobRequest.setString("job_name", jobName);
jobRequest.setString("method_name", methodName);
jobRequest.setBoolean("request_completed", false);
jobRequest.setInt("priority", priority);
int count = argumentKeys.size();
for(int i = 0; i < count; i++)
{
jobRequest.setRepeatingString("arguments_keys", i, (String)argumentKeys.elementAt(i));
jobRequest.setRepeatingString("arguments_values", i, (String)m_argumentValues.elementAt(i));
}
StringBuffer stringBuffer = new StringBuffer(512);
stringBuffer.append("/System/Sysadmin");
stringBuffer.append("/");
stringBuffer.append(jobObjectName);
jobRequest.link(stringBuffer.toString());
jobRequest.save();
stringBuffer = new StringBuffer(512);
stringBuffer.append("dm_job where object_name='");
stringBuffer.append(DfUtil.escapeQuotedString(jobName));
stringBuffer.append("'");
IDfSysObject job = (IDfSysObject)session.getObjectByQualification(stringBuffer.toString());
if(job != null)
{
job.setBoolean("run_now", isImmediate());
IDfQuery query = new DfQuery((new StringBuilder()).append("select method_type from dm_method where object_name='").append(methodName).append("'").toString());
IDfCollection result = query.execute(session, 0);
String methodType;
for(methodType = null; result != null && result.next(); methodType = result.getString("method_type"));
if(methodType != null && methodType.equalsIgnoreCase("java"))
job.setRepeatingString("method_arguments", 0, (new StringBuilder()).append("-priority ").append(DfUtil.toString(priority)).toString());
else
job.setRepeatingString("method_arguments", 0, DfUtil.toString(priority));
job.save();
} else
{
throw new DfAdminException(6409, jobName, null, null);
}
idfcollection = null;
_L3:
JVM INSTR dup ;
Object obj;
obj;
if(BaseTracingAspect.ajc$if_0())
{
if(joinpoint == null)
joinpoint = Factory.makeJP(ajc$tjp_20, this, this, idfsession);
TracingAspect.aspectOf().ajc$afterReturning$com_documentum_fc_tracing_impl_aspects_TracingAspect$9$b2797f1(obj, joinpoint);
}
return idfcollection;
Throwable throwable;
throwable;
if(BaseTracingAspect.ajc$if_0())
{
if(joinpoint == null)
joinpoint = Factory.makeJP(ajc$tjp_20, this, this, idfsession);
TracingAspect.aspectOf().ajc$afterThrowing$com_documentum_fc_tracing_impl_aspects_TracingAspect$12$cbec3e36(throwable, joinpoint);
}
throw throwable;
}
Comme nous pouvons le constater, la même méthode est utilisé pour renommer un utilisateur, un groupe ou changer la "Home Docbase" d'un utilisateur. Mais restons sur le changement de nom.
Quelques variables sont initialisées, ainsi qu'un Vector. Heureusement que nous n'avons pas la main sur ces données, car l'ordre des valeurs dans le Vector est très important. Le plus important concerne la création de l'objet dm_job_request
. Celui ci est initialisé avec les valeurs suivantes:
Attribut | Valeur |
---|---|
object_name | UserRename
Valeur dans la variable jobObjectName |
job_name | dm_UserRename
Valeur dans la variable jobName |
method_name | dm_UserRename
Valeur dans la variable methodName |
request_completed | false |
priority | Valeur passé en argument |
arguments_keys |
|
arguments_values | Les différentes valeurs du Vector m_argumentValues
mises en place par les différents setter. La position des valeurs dans cet attribut multi valué est en lien avec les valeurs dans arguments_keys. Pour report_only, il est possible de mettre T, un rapport sera effectué uniquement, ou F, le changement sera effectif. Pour unlock_locked_obj, il est possible de mettre T, les verrous sur les objets seront enlevés, ou F, les objets avec un verrou ne seront pas modifiés. |
Emplacement | Le chemin est construit pour donner /System/Sysadmin/UserRename
Les personnes avisées remarqueront que ce répertoire est recherché, récupération de son identifiant, mais pour rien en faire... Dommage de faire une requête pour rien. Attention à ne pas le supprimer |
Une fois l'instance dm_job_request
enregistrée, le job dm_UserRename
est recherché pour mettre à jour deux attributs:
Attribut | Valeur |
---|---|
run_now | T ou F
En fonction du choix d'exécution. Si il doit être lancé tout de suite ou via la planification. |
method_arguments | -priority X si la méthode dm_UserRename est déclarée en java
X si la méthode dm_UserRename n'est pas déclarée en java X étant la priorité envoyé en argument, et positionné sur l'attribut |
Donc si nous avons demandé une exécution immédiate, le job dm_UserRename
sera exécuté, car la valeur 1 sera positionnée sur l'attribut run_now
Préparation via API
Après l'analyse du code de DA, nous avons toutes les cartes en main pour effectuer une demande de changement de nom sur un utilisateur. Il suffit de créer un objet dm_job_request
avec les bonne valeur d'attribut. Prenons l'exemple d'un utilisateur déclaré sous le nom Etiene Jouvin
à renommer en Etienne Jouvin
.
Objet dm_job_request
Les attributs seront donc les suivants:
Attribut | Valeur |
---|---|
object_name | UserRename |
job_name | dm_UserRename |
method_name | dm_UserRename |
request_completed | false |
priority | 0 |
arguments_keys |
|
arguments_values |
|
Emplacement | /System/Sysadmin/UserRename |
Dans ce cas, nous demandons que la modification soit effective et que les verrous des objets soient enlevés.
Le script API est alors le suivant:
create,c,dm_job_request set,c,l,object_name UserRename set,c,l,job_name dm_UserRename set,c,l,method_name dm_UserRename set,c,l,request_completed F set,c,l,priority 0 append,c,l,arguments_keys OldUserName append,c,l,arguments_values Etiene Jouvin append,c,l,arguments_keys NewUserName append,c,l,arguments_values Etienne Jouvin append,c,l,arguments_keys report_only append,c,l,arguments_values F append,c,l,arguments_keys unlock_locked_obj append,c,l,arguments_values T link,c,l,/System/Sysadmin/UserRename save,c,l
L'exécution du job s'effectuera ensuite en modifiant le job dm_UserRename
. Si nous suivons scrupuleusement le code de DA, il faut mettre à jour la propriété method_arguments
. Par défaut, la valeur de method_type
pour l'objet dm_method
avec le nom dm_UserRename
est dmbasic
.
La valeur a positionné est donc 0, nous avons positionné 0
sur l'attribut priority
de l'objet dm_job_request
.
Préparation via API
cet article ne présente pas le mode de fonctionnement du changement de nom. Mais deux points méritent une attention paritculière.
Répertoire /System/Sysadmin/UserRename
Pour ceux qui voudrait continuer d'utiliser DA, nous avons pu voir qu'il n'y a aucun contrôle de son existence. Il est supposé qu'il est présent. L'utilisateur, en train de changer le nom, doit avoir un accès sur celui-ci pour ajouter l'objet dm_job_request
.
Attribut priority et method_arguments
Au niveau de la méthode serveur, la première valeur de l'attribut method_arguments
est récupérée. Celle-ci est utilisée pour filtrer les instances dm_job_request
à traiter. Le filtre s'effectue sur la valeur de priority
qui doit être supérieur ou égal à la valeur de method_arguments
.