Import scripts architecture


It has been some time since last post about import scripts from external sources to alfresco repository, I was busy with debugging and threading, but now I have some little time to write some notes on that topic again. I’d like to introduce „architecture“ of my solution, at least a first part of it, so lets start with an image.

Calling ImportAction
Calling ImportAction

MainImportingThread is Runnable implementation, which is initiated on init. Main thread sleeps some time and searches for config files in repository, while not sleep. If found some, ImportActionTask instance is created for each config in separate thread. ImportActionTask checks, if is it possible to run script described by config. If so, run script method on ImportAction is executed. That’s in few words functionality of the first part. Now in more details.

First version used quartz jobs triggered by org.alfresco.util.CronTriggerBean every 10 seconds, but that was temporarily solution, too heavy in my eyes. In second version I tried to use BatchProcessor, but spent few days without got it worked as I want :-(. Finally I used ThreadPoolTaskExecutor with combination of java.lang.Runnable in main thread and it worked like a charm! As I wrote a while ago, MainImportingThread has its own separate thread, which cyclically looks for configuration files in repository. It looks like following snippet:

[code lang=“java“]
public void init() {
taskExecutor.execute(new Runnable() {
@Override
public void run() {
while(keepAlive) {
Thread.sleep(threadSleepMs);

for(ResultSetRow row : resultSet) {
Object oTarget = pool.makeObject();

if(oTarget instanceof ImportActionTask) {
ImportActionTask importActionTask = (ImportActionTask) oTarget;
importActionTask.setScriptRef(row.getNodeRef());
taskExecutor.execute(importActionTask);
}
pool.destroyObject(oTarget);
}
}
taskExecutor.shutdown();
pool.destroy();
}
});
}
[/code]

For every row in result set PoolableObjectFactory creates a new instance of ImportActionTask and pass it to ThreadPoolTaskExecutor to execute. After all that – object is destroyed (destroyObject method is there just for sure – in time this method is called action still runs).

ImportActionTask is Runnable implementation, so every action runs its own thread. After execution isTimeToRun() method is called and action runs only when it’s its time and action is enabled, as it defined in data model illustrated on following diagram.

Config model
Config model

isTimeToRun() method uses fields importCron, importLastAction and isImportActive for its work. Its body looks similar to following simplified code snippet:

[code lang=“java“]
private boolean isTimeToRun() {
if(!model.isImportActive())
return false;

String cronString = model.getImportCron();
Date lastAction = model.getLastAction();

CronExpression cronExpression = new CronExpression(cronString);
if(cronExpression.getNextValidTimeAfter(lastAction).getTime() > System.currentTimeMillis())
return false;

return true;
}
[/code]

Previous snippet checks cron expression against time of last successfully executed action using org.quartz.CronExpression and in case of success (ie lastAction+cron < current time) importAction itself may be triggered. But more on this next time, right now just another snippet from ImportActionTask, which calls importAction (received from ProxyFactoryBean):

[code lang=“java“]
public void run() {
if(isTimeToRun) {
try {
importAction.invocateImportScript();
} finally {
importAction.clean();
}
}
}
[/code]


Jeden komentář: “Import scripts architecture”

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *