Explication IDfQueryProcessor DFC
Dans différentes applications Documentum, comme Webtop cf Explication Exécution Recherche Webtop, les requêtes sont exécutées à l'aide d'une instance de l'interface com.documentum.fc.client.search.IDfQueryProcessor
. Ceci permet de récupérer les résultats de façon asynchrone en utilisant un mécanisme de listener.
Cependant cette implémentation est particulièrement difficile à appréhender à première vue, car beaucoup de classe sont utilisées.
Cet article va décrire différents points importants important pour comprendre cette fonctionnalité.
Sommaire
Votre avis
Nobody voted on this yet
|
|
Version 5.3 SP2
Rappel d'utilisation depuis Webtop
Cette article a été écrit suite à l'analyse faite sur l'exécution d'une recherche dans Webtop.
Au niveau de Webtop, les requêtes sont construites et exécutées à partir d'une instance com.documentum.fc.client.search.IDfSearchService
construite à l'aide de l'instruction suivante:
IDfSearchService searchService = getSearchInfo().getSearchService();
La code de la fonction getSearchService()
est:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: SearchInfo.java
public IDfSearchService getSearchService()
{
if(m_idfSearchService == null)
try
{
DfClientX clientx = new DfClientX();
IDfClient client = clientx.getLocalClient();
m_idfSearchService = client.newSearchService(SessionManagerHttpBinding.getSessionManager(), SessionManagerHttpBinding.getCurrentDocbase());
}
catch(DfException e)
{
throw new WrapperRuntimeException(e);
}
return m_idfSearchService;
}
Ensuite, le code suivant est utilisé afin d'exécuter une requête définie par une instance de com.documentum.fc.client.search.IDfQueryDefinition
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: SearchEx.java
IDfSearchService searchService = getSearchInfo().getSearchService();
IDfQueryDefinition idfQuertdef = getSearchInfo().getSmartListDefinition().getQueryDefinition();
IDfQueryProcessor idfQueryProcessor = searchService.newQueryProcessor(idfQuertdef, true);
getSearchInfo().setQueryProcessor(idfQueryProcessor);
com.documentum.fc.client.search.IDfResultsManipulator idfResultsManipulator = searchService.newResultsManipulator(idfQuertdef);
getSearchInfo().setResultsManipulator(idfResultsManipulator);
idfQueryProcessor.addListener(this);
idfQueryProcessor.search();
Construction de IDfClient
Plusieurs implémentations sont disponibles pour cette interface. Après plusieurs expérience, il est facile de savoir quelle est la classe utilisée. Mais il est important de comprendre comment celle ci est construite. L'implémentation est donc retournée par la méthode getLocalClient()
d'une instance de com.documentum.com.DfClientX
.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: DfClientX.java
public IDfClient getLocalClient()
throws DfException
{
IDfClient __TRACER_RETURN_VALUE__ = null;
Throwable __TRACER_EXCEPTION__ = null;
com.documentum.tracing.core.FieldAccessors __TRACE_FIELD_ACCESS__[] = null;
try
{
IDfClient idfclient;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[0];
DfTracer.traceMethodEntrance("getLocalClient", 1, __TRACER_PARAMETERS__, getClass(), this, "IDfClient");
}
__TRACER_RETURN_VALUE__ = DfClient.getLocalClient();
idfclient = __TRACER_RETURN_VALUE__;
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof DfException)
throw (DfException)__exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
return idfclient;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit("getLocalClient", 1, getClass(), this, __TRACER_EXCEPTION__, __TRACER_RETURN_VALUE__);
}
}
La construction de l'instance de DfClient
s'effectue donc depuis la fonction statique getLocalClient
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: DfClient.java
public static synchronized IDfClient getLocalClient()
throws DfException
{
IDfClient __TRACER_RETURN_VALUE__ = null;
Throwable __TRACER_EXCEPTION__ = null;
com.documentum.tracing.core.FieldAccessors __TRACE_FIELD_ACCESS__[] = null;
try
{
IDfClient idfclient;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[0];
DfTracer.traceMethodEntrance("getLocalClient", 25, __TRACER_PARAMETERS__, com.documentum.fc.client.DfClient.class, null, "IDfClient");
}
__TRACER_RETURN_VALUE__ = getLocalClientEx();
idfclient = __TRACER_RETURN_VALUE__;
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof DfException)
throw (DfException)__exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
return idfclient;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit("getLocalClient", 25, com.documentum.fc.client.DfClient.class, null, __TRACER_EXCEPTION__, __TRACER_RETURN_VALUE__);
}
}
Celle ci fait appel à la fonction statique getLocalClientEx()
au sein de la même classe qui va permettre d'obtenir enfin l'instance souhaitée:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: DfClient.java
public static synchronized IDfClient getLocalClientEx()
{
IDfClient __TRACER_RETURN_VALUE__ = null;
Throwable __TRACER_EXCEPTION__ = null;
com.documentum.tracing.core.FieldAccessors __TRACE_FIELD_ACCESS__[] = null;
try
{
IDfClient idfclient;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[0];
DfTracer.traceMethodEntrance("getLocalClientEx", 25, __TRACER_PARAMETERS__, com.documentum.fc.client.DfClient.class, null, "IDfClient");
}
if(s_client == null)
try
{
s_client = new DfClient();
}
catch(DfException e)
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.exceptionInfo(25, com.documentum.fc.client.DfClient.class, null, e, "getLocalClientEx");
}
__TRACER_RETURN_VALUE__ = s_client;
idfclient = __TRACER_RETURN_VALUE__;
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
return idfclient;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit("getLocalClientEx", 25, com.documentum.fc.client.DfClient.class, null, __TRACER_EXCEPTION__, __TRACER_RETURN_VALUE__);
}
}
En conclusion, la variable retournée par la fonction getLocalClient
, de DfClientX
, est une instance de com.documentum.fc.client.DfClient
.
Construction du service de recherche
Après avoir récupérer une instance de IDfClient
, la fonction newSearchService(IDfSessionManager idfsessionmanager, String s)
est exécutée afin de récupérer le service de recherche. C'est pourquoi il était important de connaître précisément la classe utilisée. L'étude de cette fonction permet d'identifier la classe exacte du service.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: DfClientSupport.java
public IDfSearchService newSearchService(IDfSessionManager sessionManager, String defaultMetadataDocbase)
{
IDfSearchService __TRACER_RETURN_VALUE__ = null;
Throwable __TRACER_EXCEPTION__ = null;
com.documentum.tracing.core.FieldAccessors __TRACE_FIELD_ACCESS__[] = null;
try
{
IDfSearchService idfsearchservice;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[2];
__TRACER_PARAMETERS__[0] = new Parameter(sessionManager, "sessionManager", "IDfSessionManager");
__TRACER_PARAMETERS__[1] = new Parameter(defaultMetadataDocbase, "defaultMetadataDocbase", "String");
DfTracer.traceMethodEntrance("newSearchService", 1, __TRACER_PARAMETERS__, getClass(), this, "IDfSearchService");
}
if(sessionManager == null)
throw new IllegalArgumentException(DfSearchMessages.getString("NULL_ARGUMENT", (com.documentum.fc.client.IDfSessionManager.class).getName()));
__TRACER_RETURN_VALUE__ = new DfSearchService(sessionManager, defaultMetadataDocbase);
idfsearchservice = __TRACER_RETURN_VALUE__;
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
return idfsearchservice;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit("newSearchService", 1, getClass(), this, __TRACER_EXCEPTION__, __TRACER_RETURN_VALUE__);
}
}
Encore une fois, cette analyse n'est pas forcément nécessaire car il y a uniquement deux implémentations de l'interface IDfSearchService
:
- com.documentum.fc.client.search.impl.mockups.DfSearchService
- com.documentum.fc.client.search.impl.DfSearchService
D'après le package de la première implémentation, il était fort peu probable qu'elle soit utilisée. L'analyse a pu confirmer cette intuition.
Construction du IDfQueryProcessor
C'est cette instance qui est utilisée pour exécuter une définition de recherche. Elle est construite à partir de service de recherche par la fonction newQueryProcessor(IDfQueryDefinition query, boolean removeDuplicate)
.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: DfSearchService.java
public IDfQueryProcessor newQueryProcessor(IDfQueryDefinition query, boolean removeDuplicate)
{
IDfQueryProcessor __TRACER_RETURN_VALUE__ = null;
Throwable __TRACER_EXCEPTION__ = null;
com.documentum.tracing.core.FieldAccessors __TRACE_FIELD_ACCESS__[] = null;
try
{
IDfQueryProcessor idfqueryprocessor;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[2];
__TRACER_PARAMETERS__[0] = new Parameter(query, "query", "IDfQueryDefinition");
__TRACER_PARAMETERS__[1] = new Parameter(removeDuplicate, "removeDuplicate", "boolean");
DfTracer.traceMethodEntrance("newQueryProcessor", 1, __TRACER_PARAMETERS__, getClass(), this, "IDfQueryProcessor");
}
if(query == null)
throw new IllegalArgumentException(DfSearchMessages.getString("NULL_ARGUMENT", (com.documentum.fc.client.search.IDfQueryDefinition.class).getName()));
__TRACER_RETURN_VALUE__ = new DfQueryProcessor((DfQueryDefinition)query, m_sessionMgr, getBrokerAssembly(), removeDuplicate, getSourceMap());
idfqueryprocessor = __TRACER_RETURN_VALUE__;
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
return idfqueryprocessor;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit("newQueryProcessor", 1, getClass(), this, __TRACER_EXCEPTION__, __TRACER_RETURN_VALUE__);
}
}
La variable retournée est donc une instance de la classe com.documentum.fc.client.search.impl.execution.DfQueryProcessor
. Encore une fois, la lecture de ce code n'était pas forcément nécessaire car il n'existe qu'une seule implémentation de l'interface IDfQueryProcessor
.
Mais il est important de noter le paramètre d'appel au constructeur construit à l'aide de la fonction getBrokerAssembly()
, qui sera utilisée plus tard.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: DfSearchService.java
private static synchronized BrokerAssembly getBrokerAssembly()
{
BrokerAssembly __TRACER_RETURN_VALUE__ = null;
Throwable __TRACER_EXCEPTION__ = null;
com.documentum.tracing.core.FieldAccessors __TRACE_FIELD_ACCESS__[] = null;
try
{
BrokerAssembly brokerassembly;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[0];
DfTracer.traceMethodEntrance("getBrokerAssembly", 26, __TRACER_PARAMETERS__, com.documentum.fc.client.search.impl.DfSearchService.class, null, "BrokerAssembly");
}
if(s_brokerAssembly == null)
s_brokerAssembly = new BrokerAssembly();
__TRACER_RETURN_VALUE__ = s_brokerAssembly;
brokerassembly = __TRACER_RETURN_VALUE__;
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
return brokerassembly;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit("getBrokerAssembly", 26, com.documentum.fc.client.search.impl.DfSearchService.class, null, __TRACER_EXCEPTION__, __TRACER_RETURN_VALUE__);
}
}
Dans le constructeur de la classe DfQueryProcessor
, la fonction getQueryBroker()
de l'instance BrokerAssembly
est exécutée afin de peupler la variable m_receiver
.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: DfQueryProcessor.java
public DfQueryProcessor(DfQueryDefinition def, IDfSessionManager sessionMgr, BrokerAssembly assembly, boolean removeDuplicate, IDfSearchSourceMap sourceMap)
{
m_listeners = null;
m_sequenceNumber = 0;
Throwable __TRACER_EXCEPTION__ = null;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[5];
__TRACER_PARAMETERS__[0] = new Parameter(def, "def", "DfQueryDefinition");
__TRACER_PARAMETERS__[1] = new Parameter(sessionMgr, "sessionMgr", "IDfSessionManager");
__TRACER_PARAMETERS__[2] = new Parameter(assembly, "assembly", "BrokerAssembly");
__TRACER_PARAMETERS__[3] = new Parameter(removeDuplicate, "removeDuplicate", "boolean");
__TRACER_PARAMETERS__[4] = new Parameter(sourceMap, "sourceMap", "IDfSearchSourceMap");
DfTracer.traceMethodEntrance("<init>", 65, __TRACER_PARAMETERS__, com.documentum.fc.client.search.impl.execution.DfQueryProcessor.class, this, null);
}
if(!$assertionsDisabled && def == null)
throw new AssertionError("Definition should not be null at this point");
if(!$assertionsDisabled && sessionMgr == null)
throw new AssertionError("IDfSessionManager should not be null at this point");
if(!$assertionsDisabled && assembly == null)
throw new AssertionError("BrokerAssembly should not be null at this point");
m_receiver = assembly.getQueryBroker();
int maxResults = computeMaxResults(def);
m_query = new ServerQuery(def, maxResults, sessionMgr);
m_listeners = Collections.synchronizedList(new ArrayList(1));
if(removeDuplicate)
m_results = new DfDuplicateRemover(sourceMap);
else
m_results = new DfResultsSet();
m_status = new DfQueryStatus(def.getMetadataMgr().getSelectedSources());
m_completed = false;
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit(getClass().getName(), 65, getClass(), this, __TRACER_EXCEPTION__);
}
}
La variable m_receiver
est donc peuplée à l'aide de la fonction getQueryBroker()
de l'argument assembly
.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: BrokerAssembly.java
public QueryReceiver getQueryBroker()
{
QueryReceiver __TRACER_RETURN_VALUE__ = null;
Throwable __TRACER_EXCEPTION__ = null;
com.documentum.tracing.core.FieldAccessors __TRACE_FIELD_ACCESS__[] = null;
try
{
QueryReceiver queryreceiver;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[0];
DfTracer.traceMethodEntrance("getQueryBroker", 1, __TRACER_PARAMETERS__, getClass(), this, "QueryReceiver");
}
__TRACER_RETURN_VALUE__ = m_queryBroker;
queryreceiver = __TRACER_RETURN_VALUE__;
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
return queryreceiver;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit("getQueryBroker", 1, getClass(), this, __TRACER_EXCEPTION__, __TRACER_RETURN_VALUE__);
}
}
Celle ci retourne la variable interne m_queryBroker
construite dans le constructeur de la classe.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: BrokerAssembly.java
public BrokerAssembly()
{
Throwable __TRACER_EXCEPTION__ = null;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[0];
DfTracer.traceMethodEntrance("<init>", 65, __TRACER_PARAMETERS__, com.documentum.fc.client.search.impl.query.BrokerAssembly.class, this, null);
}
m_queryBroker = new QueryBroker(null);
m_scheduler = new Scheduler();
m_queryBroker.connectToSubsystems(m_scheduler);
m_scheduler.connectToQueryMgt(m_queryBroker);
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit(getClass().getName(), 65, getClass(), this, __TRACER_EXCEPTION__);
}
}
Tout cela est un peu fastidieux, mais nécessaire pour comprendre la suite.
Exécution de la recherche
La recherche est construite et exécutée depuis la méthode search()
de l'instance DfQueryProcessor
.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: DfQueryProcessor.java
public void search()
{
Throwable __TRACER_EXCEPTION__ = null;
com.documentum.tracing.core.FieldAccessors __TRACE_FIELD_ACCESS__[] = null;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[0];
DfTracer.traceMethodEntrance("search", 1, __TRACER_PARAMETERS__, getClass(), this, "void");
}
synchronized(this)
{
m_status.started();
}
m_receiver.search(this, m_query);
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit("search", 1, getClass(), this, __TRACER_EXCEPTION__);
}
}
A ce niveau, on peut constater l'utilité de connaître la classe d'instance de m_receiver
, pour mémoire QueryBroker
, à laquelle a été affectée une instance de com.documentum.fc.client.search.impl.broker.Scheduler
dans la variable m_scheduler
lors du constructeur de BrokerAssembly
. La fonction search(Surrogate sg, ServerQuery query)
est la suivante.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: QueryBroker.java
public void search(Surrogate sg, ServerQuery query)
{
Throwable __TRACER_EXCEPTION__ = null;
com.documentum.tracing.core.FieldAccessors __TRACE_FIELD_ACCESS__[] = null;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[2];
__TRACER_PARAMETERS__[0] = new Parameter(sg, "sg", "Surrogate");
__TRACER_PARAMETERS__[1] = new Parameter(query, "query", "ServerQuery");
DfTracer.traceMethodEntrance("search", 1, __TRACER_PARAMETERS__, getClass(), this, "void");
}
m_clients.put(query, sg);
m_scheduler.search(query, 5, false);
if(m_serverMonitor != null)
m_serverMonitor.search(sg, query);
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit("search", 1, getClass(), this, __TRACER_EXCEPTION__);
}
}
Exécution différée de la recherche, classe Scheduler
Jusqu'à présent la requête n'est toujours pas construite ni exécutée. Mais comme le nom de la classe Scheduler l'indique, celle ci va être responsable de l'exécution différée/plannifiée de la requête.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: Scheduler.java
public void search(ServerQuery query, int priority, boolean forceUpdate)
{
Throwable __TRACER_EXCEPTION__ = null;
com.documentum.tracing.core.FieldAccessors __TRACE_FIELD_ACCESS__[] = null;
DfQueryDefinition queryDef;
Vector unprocessedActions;
IDfEnumeration sourceNamesEnum;
ArrayList extSources;
IDfSearchSource source;
Action createdAction;
String sourceName;
int i;
Action createdAction;
Action action;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[3];
__TRACER_PARAMETERS__[0] = new Parameter(query, "query", "ServerQuery");
__TRACER_PARAMETERS__[1] = new Parameter(priority, "priority", "int");
__TRACER_PARAMETERS__[2] = new Parameter(forceUpdate, "forceUpdate", "boolean");
DfTracer.traceMethodEntrance("search", 1, __TRACER_PARAMETERS__, getClass(), this, "void");
}
if(m_hasShutdown)
return;
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit("search", 1, getClass(), this, __TRACER_EXCEPTION__);
}
if(m_actionMapping.containsKey(query) || query == null)
return;
queryDef = query.getQuery();
unprocessedActions = new Vector(queryDef.getSelectedSourceCount());
sourceNamesEnum = queryDef.getSelectedSources();
extSources = new ArrayList(queryDef.getSelectedSourceCount());
do
{
if(!sourceNamesEnum.hasMoreElements())
break;
source = (IDfSearchSource)sourceNamesEnum.nextElement();
sourceName = source.getName();
if(source.getType() == 1)
{
createdAction = new Action(query, sourceName, priority);
unprocessedActions.addElement(createdAction);
if(DfLogger.isDebugEnabled(this))
DfLogger.debug(this, "Create action " + createdAction, null, null);
} else
if(source.getType() == 100)
extSources.add(sourceName);
else
m_queryMgr.status(query, sourceName, new DfQueryEvent(7, 77, sourceName, "Source is not available"));
} while(true);
if(extSources.size() > 0)
{
createdAction = new Action(query, extSources, priority);
unprocessedActions.addElement(createdAction);
if(DfLogger.isDebugEnabled(this))
DfLogger.debug(this, "Create action " + createdAction, null, null);
}
if(unprocessedActions.size() == 0)
{
m_queryMgr.done(query);
} else
{
m_actionMapping.put(query, unprocessedActions);
synchronized(query)
{
for(i = 0; i < unprocessedActions.size(); i++)
{
action = (Action)unprocessedActions.elementAt(i);
if(action.isDocbase())
m_docBasePendings.put(action);
else
m_ecisPendings.put(action);
}
if(DfLogger.isDebugEnabled(this))
{
DfLogger.debug(this, "ECIS busy level = " + m_ecisPendings.size() + "/" + m_docbaseBrokersNb, null, null);
DfLogger.debug(this, "Docbases busy level = " + m_docBasePendings.size() + "/" + m_ecisBrokersNb, null, null);
}
}
}
}
Dans un premier temps, des instances (en fonction du nombre de source) de com.documentum.fc.client.search.impl.broker.Action
sont construites et placées dans le vecteur unprocessedActions
. Dans un second temps, les actions sont placées dans les variables m_docBasePendings
ou m_ecisPendings
. Ces variables sont des instances de com.documentum.fc.client.search.impl.broker.ActionQueue
, construite dans le constructeur du Scheduler.
Dans ce constructeur, des threads sont démarrés, ceux intéressants dans le cas des l'étude sont les instances de DocbaseBroker.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: Scheduler.java
public Scheduler()
{
m_hasShutdown = false;
Throwable __TRACER_EXCEPTION__ = null;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[0];
DfTracer.traceMethodEntrance("<init>", 65, __TRACER_PARAMETERS__, com.documentum.fc.client.search.impl.broker.Scheduler.class, this, null);
}
m_ecisPendings = new ActionQueue();
m_docBasePendings = new ActionQueue();
m_actionMapping = new Hashtable();
m_docbaseBrokersNb = SearchConfigFactory.getConfig().getMaxDocbaseBrokers();
m_ecisBrokersNb = SearchConfigFactory.getConfig().getMaxEcisBrokers();
m_brokerGrp = new ThreadGroup(Thread.currentThread().getThreadGroup(), "Brokers");
m_brokerGrp.setMaxPriority(1);
for(int i = 0; i < m_docbaseBrokersNb; i++)
{
DocbaseBroker broker = new DocbaseBroker(this, m_brokerGrp, "DocbaseBroker (" + String.valueOf(i + 1) + ")", m_docBasePendings);
broker.setPriority(3);
broker.start();
}
for(int i = 0; i < m_ecisBrokersNb; i++)
{
ECISBroker broker = new ECISBroker(this, m_brokerGrp, "ECISBroker (" + String.valueOf(i + 1) + ")", m_ecisPendings);
broker.setPriority(3);
broker.start();
}
if(DfLogger.isDebugEnabled(this))
DfLogger.debug(this, "Spawned [" + m_ecisBrokersNb + "] ECIS brokers " + "and [" + m_docbaseBrokersNb + "] Docbase brokers", null, null);
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit(getClass().getName(), 65, getClass(), this, __TRACER_EXCEPTION__);
}
}
Définition des threads
Dans le constructeur de la classe Scheduler
, des threads sont construits (cf paragraphe précédent, en les associant à une instance de ActionQueue
. L'association s'effectue dans le constructeur de ces threads.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: DocbaseBroker.java
DocbaseBroker(Scheduler scheduler, ThreadGroup group, String name, ActionQueue pendings)
{
super(scheduler, group, name, pendings);
Throwable __TRACER_EXCEPTION__ = null;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[4];
__TRACER_PARAMETERS__[0] = new Parameter(scheduler, "scheduler", "Scheduler");
__TRACER_PARAMETERS__[1] = new Parameter(group, "group", "ThreadGroup");
__TRACER_PARAMETERS__[2] = new Parameter(name, "name", "String");
__TRACER_PARAMETERS__[3] = new Parameter(pendings, "pendings", "ActionQueue");
DfTracer.traceMethodEntrance("<init>", 192, __TRACER_PARAMETERS__, com.documentum.fc.client.search.impl.broker.DocbaseBroker.class, this, null);
}
m_shouldStop = false;
m_maxScore = 0.0D;
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit(getClass().getName(), 192, getClass(), this, __TRACER_EXCEPTION__);
}
}
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: BaseBroker.java
public BaseBroker(Scheduler scheduler, ThreadGroup group, String name, Queue pendings)
{
super(group, name);
m_scheduler = null;
m_pendings = null;
m_action = null;
m_brokerState = 0;
Throwable __TRACER_EXCEPTION__ = null;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[4];
__TRACER_PARAMETERS__[0] = new Parameter(scheduler, "scheduler", "Scheduler");
__TRACER_PARAMETERS__[1] = new Parameter(group, "group", "ThreadGroup");
__TRACER_PARAMETERS__[2] = new Parameter(name, "name", "String");
__TRACER_PARAMETERS__[3] = new Parameter(pendings, "pendings", "Queue");
DfTracer.traceMethodEntrance("<init>", 65, __TRACER_PARAMETERS__, com.documentum.fc.client.search.impl.broker.BaseBroker.class, this, null);
}
setDaemon(true);
m_scheduler = scheduler;
m_pendings = pendings;
m_idlename = name;
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit(getClass().getName(), 65, getClass(), this, __TRACER_EXCEPTION__);
}
}
Déclenchement de la requête
En reprenant la classe Scheduler
, les threads sont démarrés dès leur construction. L'analyse de la méthode run
permet d'en finir avec l'analyse.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: BaseBroker.java
public void run()
{
Throwable __TRACER_EXCEPTION__;
__TRACER_EXCEPTION__ = null;
com.documentum.tracing.core.FieldAccessors __TRACE_FIELD_ACCESS__[] = null;
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[0];
DfTracer.traceMethodEntrance("run", 1, __TRACER_PARAMETERS__, getClass(), this, "void");
}
setBrokerState(1);
_L3:
if(m_brokerState != 6)
try
{
switch(m_brokerState)
{
case 0: // '\0'
if(!$assertionsDisabled)
throw new AssertionError("Unexcepted state in broker run loop:0");
break;
case 1: // '\001'
m_action = (Action)m_pendings.get();
if(m_action != null)
setBrokerState(2);
break;
case 2: // '\002'
m_scheduler.processing(m_action, this);
handleProcessingState();
break;
case 3: // '\003'
synchronized(this)
{
try
{
wait();
}
catch(InterruptedException ie)
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.exceptionInfo(1, getClass(), this, ie, "run");
if(!$assertionsDisabled)
throw new AssertionError("broker should never get interrupted." + ie.toString());
}
}
break;
case 4: // '\004'
if(DfLogger.isDebugEnabled(this))
DfLogger.debug(this, "Action stopped " + m_action + getName(), null, null);
m_scheduler.stopped(m_action);
if(internalThrowLifeCycleEvent())
status(6, 61, m_action.getDocbaseSource(), "", null);
setBrokerState(5);
break;
case 5: // '\005'
internalClean();
clean();
setBrokerState(1);
break;
default:
if(!$assertionsDisabled)
throw new AssertionError("Unknown state in broker main loop: " + m_brokerState);
break;
case 6: // '\006'
break;
}
continue; /* Loop/switch isn't completed */
}
catch(Exception e)
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.exceptionInfo(1, getClass(), this, e, "run");
DfLogger.error(this, DfSearchMessages.getString("ERROR_IN_BROKER", getName()), null, e);
if(DfLogger.isDebugEnabled(this))
DfLogger.debug(this, "Broker in state:" + m_brokerState + " action in state:" + m_action.getState(), null, null);
if(m_action != null)
m_scheduler.unprocessable(m_action);
setBrokerState(1);
continue; /* Loop/switch isn't completed */
}
catch(Error e)
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.exceptionInfo(1, getClass(), this, e, "run");
DfLogger.fatal(this, DfSearchMessages.getString("ERROR_IN_BROKER", getName()), null, e);
if(m_action != null)
m_scheduler.unprocessable(m_action);
setBrokerState(1);
continue; /* Loop/switch isn't completed */
}
catch(Throwable t)
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.exceptionInfo(1, getClass(), this, t, "run");
DfLogger.error(this, DfSearchMessages.getString("ERROR_IN_BROKER", getName()), null, t);
}
if(DfLogger.isDebugEnabled(this))
DfLogger.debug(this, getName() + ": BaseBroker shutting down", null, null);
m_scheduler = null;
m_pendings = null;
m_action = null;
goto _L1
Throwable __exception__;
__exception__;
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
local;
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit("run", 1, getClass(), this, __TRACER_EXCEPTION__);
JVM INSTR ret 7;
_L1:
return;
if(true) goto _L3; else goto _L2
_L2:
}
Dans cette méthode run
, lorsque la valeur de la variable m_brokerState
, représentant son état, est égal à 2 (visiblement actif), la méthode handleProcessingState()
est exécutée.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: BaseBroker.java
private void handleProcessingState()
{
Throwable __TRACER_EXCEPTION__ = null;
com.documentum.tracing.core.FieldAccessors __TRACE_FIELD_ACCESS__[] = null;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[0];
DfTracer.traceMethodEntrance("handleProcessingState", 2, __TRACER_PARAMETERS__, getClass(), this, "void");
}
m_scheduler.processing(m_action, this);
brokerTrace("Process action ");
try
{
internalProcess();
if(m_brokerState == 2)
{
if(DfLogger.isDebugEnabled(this))
DfLogger.debug(this, "Action finished: " + m_action, null, null);
if(internalThrowLifeCycleEvent())
status(6, 60, m_action.getDocbaseSource(), "", null);
m_scheduler.done(m_action);
setBrokerState(5);
}
}
catch(Exception e)
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.exceptionInfo(2, getClass(), this, e, "handleProcessingState");
if(DfLogger.isDebugEnabled(this))
DfLogger.debug(this, getName() + ": unable to process query for action " + m_action + ", caught error\n" + e, null, e);
String source;
for(Iterator sources = m_action.getSources().iterator(); sources.hasNext(); status(7, 74, source, "", null))
source = (String)sources.next();
failure();
}
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit("handleProcessingState", 2, getClass(), this, __TRACER_EXCEPTION__);
}
}
Cette méthode va ensuite appelée la méthode internalProcess
, abstraite dans la classe BaseBroker
. Dans le cadre de cette explication, l'implémentation dans la classe DocbaseBroker
est intéressante.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: DocbaseBroker.java
protected void internalProcess()
{
Throwable __TRACER_EXCEPTION__ = null;
com.documentum.tracing.core.FieldAccessors __TRACE_FIELD_ACCESS__[] = null;
ServerQuery query;
IDfSessionManager manager;
String sourceName;
com.documentum.fc.client.IDfSession session;
IDfCollection collection;
DfQueryDefinition queryDef;
DfException e;
IDfSearchMetadataManager metadataManager;
IDfSearchSource searchSource;
boolean srcFTDQLCompatible;
String dqlStatement;
IDfQuery dfQuery;
int maxResults;
int batchSize;
DfSearchSource source;
List results;
int index;
boolean collectionNext;
IDfResultEntry entry;
DfException e;
try
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
{
Parameter __TRACER_PARAMETERS__[] = new Parameter[0];
DfTracer.traceMethodEntrance("internalProcess", 4, __TRACER_PARAMETERS__, getClass(), this, "void");
}
if(DfLogger.isDebugEnabled(this))
DfLogger.debug(this, "InternalProcess, action = " + getAction(), null, null);
m_shouldStop = false;
Action action = getAction();
query = action.getServerQuery();
manager = query.getAccount();
sourceName = action.getDocbaseSource();
session = null;
try
{
session = manager.getSession(sourceName);
}
catch(DfServiceException e)
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.exceptionInfo(4, getClass(), this, e, "internalProcess");
status(7, 73, sourceName, e.getMessage(), e);
setFailed();
return;
}
}
catch(Throwable __exception__)
{
__TRACER_EXCEPTION__ = __exception__;
if(__exception__ instanceof Error)
throw (Error)__exception__;
else
throw (RuntimeException)__exception__;
}
finally
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.traceMethodExit("internalProcess", 4, getClass(), this, __TRACER_EXCEPTION__);
}
collection = null;
queryDef = query.getQuery();
metadataManager = queryDef.getMetadataMgr();
searchSource = metadataManager.getSourceMap().getSource(sourceName);
srcFTDQLCompatible = searchSource != null ? searchSource.hasCapability("ftdql_support") : false;
dqlStatement = queryDef.getDocbaseQuery(sourceName);
if(DfLogger.isDebugEnabled(this))
DfLogger.debug(this, "InternalProcess dql=" + dqlStatement, null, null);
dfQuery = new DfQuery();
dfQuery.setDQL(dqlStatement);
maxResults = getAction().getServerQuery().getMaxResultsPerSource();
batchSize = getBatchSize();
dfQuery.setBatchSize(batchSize);
status(3, 0, sourceName, "", null);
collection = dfQuery.execute(session, 4);
if(m_shouldStop)
return;
source = (DfSearchSource)metadataManager.getSourceMap().getSource(sourceName);
results = new ArrayList(batchSize);
index = 0;
collectionNext = collection.next();
do
{
if(!collectionNext || index >= maxResults)
break;
for(; collectionNext && results.size() < batchSize && index < maxResults; index++)
{
entry = getEntry(collection, index, source, srcFTDQLCompatible, query);
results.add(entry);
collectionNext = collection.next();
}
if(results.size() > 0)
{
found(sourceName, results);
results.clear();
}
} while(true);
if(index == 0 && queryDef.isQueryBuilder() && isUnreachableScope((IDfQueryBuilder)queryDef))
status(7, 78, sourceName, "At least one query location scope is unreachable", null);
if(collection.next())
status(11, 0, sourceName, "Additional results have been skipped", null);
goto _L1
e;
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.exceptionInfo(4, getClass(), this, e, "internalProcess");
status(7, 74, sourceName, e.getMessage() + " message= " + e.getMessage(), e);
setFailed();
return;
local;
if(collection != null)
try
{
collection.close();
}
// Misplaced declaration of an exception variable
catch(DfException e)
{
if(DfTracer.s_globalTraceEnabled && DfTracer.isEnabled())
DfTracer.exceptionInfo(4, getClass(), this, e, "internalProcess");
}
if(session != null)
manager.release(session);
JVM INSTR ret 23;
_L1:
}
L'analyse de l'exécution de la recherche est ainsi terminée. Le nombre de classes mises en jeu est assez impressionnant, ce qui explique la difficulté à comprendre le fonctionnement. Toutefois, cela permet également d'identifier un moyen simple de logger les requêtes exécutées.