Posts tagged howto

Deleting workflows in Alfresco

7

I tried to find out how to delete completed workflows in Alfresco, but I find no way to do that. I’m talking about HUGE number of completed workflows – a thousands. There are many questions on that topic, but no solution. I tried to play with Workflow console, also tried Alfresco Workflow Purge webscript by Rothbury software and also tried to write own deleters based on Workflow service (more on this next time), but no success at all. In better cases process dies with „out of memory“, or completely locks Alfresco in worst cases. So I choose hardcore solution – to delete database tables. And it works :-).

I’m talking about 10 tables, which are bind with foreign keys. So to remove ALL workflows follow those steps (note I’m not responsible for data loses, you’re on your own, so backup carefully!):

  1. Stop Alfresco and stop mysql
  2. Do backups – at least alf_data and /var/lib/mysql
  3. Start mysql and open mysql client
  4. Turn off foreign key checking: SET FOREIGN_KEY_CHECKS=0;
  5. Truncate following tables:
    • JBPM_TOKEN
    • JBPM_TOKENVARIABLEMAP
    • JBPM_TASKINSTANCE
    • JBPM_SWIMLANEINSTANCE
    • JBPM_PROCESSINSTANCE
    • JBPM_MODULEINSTANCE
    • JBPM_LOG
    • JBPM_BYTEBLOCK
    • JBPM_BYTEARRAY
    • JBPM_VARIABLEINSTANCE
  6. Maybe it’s good idea to set index.recovery.mode to FULL
  7. Start Alfresco and hope everything is well
  8. Turn off reindexing set in step 6

Simple yet effective. Please, let me know, if it works on your Alfresco too. I tested it od Community versions 3.4.e, 3.4.d and 4.1.0 (built from svn).

Creating rules programaticaly

0

Nowadays I’ve been working on policies and triggering a behavior  based on user action, so I wanted to write about it, but I found more interesting stuff I did with it than triggering itself (which is by the way well described by Jeff Potts). I wanted a routine, which runs on every node created and adds a rule, if that node is a folder.

At first I did some research on rules. How are rules bound to nodes? We’re working on repository, so it should be a node. When you open a node browser and look on node with rule bound, you’ll see ‚ruleFolder‘ child of that node of ruleFolder type. Children of this node are rules itself – one child, one rule. Inside each are actions defined with conditions and actions with their parameters, like on following structure:

RuleFolder structure

RuleFolder structure

Conditions may be structured too – if condition is not „no-condition“ – there may be much complicated structure: either condition itself (actioncondition node type) with parameters as children, or composite-condition (compositeactioncondition node type) with conditions nested inside. Each condition has „invert“ boolean variable, which inverts condition meaning. Properties of simpliest condition (no-condition) are on following image:

Condition properties

Condition properties

Parameters are another types of node – actionparameter. Each has two important properties: parameterName and parameterValue and those values depends on action (or condition) on which is this parameter bind to. Example of parameter for copy-to-webproject action is on following image:

Parameter properties

Parameter properties

And of course third node type – action. With or without parameters. In both cases with properties like definitionName, executeAsynchronously, etc. see following image:

Action properties

Action properties

Examples on how to set rule on node are in nodeRef cookbook. I worked with CopyToWebProject action, which can be with parameters defined like this:

Action myAction = actionService.createAction(CopyToWebProjectActionExecuter.NAME);
Map<String, Serializable> actionProps = myAction.getParameterValues();
actionProps.put(CopyToWebProjectActionExecuter.PARAM_DESTINATION_FOLDER, avmRef);
myAction.setParameterValues(actionProps);

Note static variables with parameter names (prefix PARAM_). Executers are in org.alfresco.repo.action.executer package, or it’s possible to use own action executer (extending ActionExecuterAbstractBase).

Next step is to add a condition, in my case HasAspectEvaluator like this:

ActionCondition condition = actionService.createActionCondition(HasAspectEvaluator.NAME);
Map<String, Serializable> conditionProps = new HashMap<String, Serializable>();
conditionProps.put(HasAspectEvaluator.PARAM_ASPECT, ContentModel.ASPECT_WORKING_COPY);
condition.setParameterValues(conditionProps);
condition.setInvertCondition(true);

Evaluators (package org.alfresco.repo.action.evaluator) also have parameter names defined with prefix PARAM_. Previous code creates condition testing aspect is NOT set on node (note setInvertCondition() method) – this condition is for testing copied content is not working copy.

Created condition and action should be placed in CompositeAction:

CompositeAction compositeAction = actionService.createCompositeAction();
compositeAction.addActionCondition(condition);
compositeAction.addAction(myAction);

And the final step is to add this whole composition inside created rule and use ruleService to bind created rule to node – through its nodeRef:

rule.setAction(compositeAction);
ruleService.saveRule(sourceRef, rule);

This is enough and it should work. What am I using it for? I need CopyToWebProject rule to foolow tree structure in DM, not just copy everything in subdirs to given folder. So I have my own implementation of OnCreateNodePolicy, which binds this rule to every created folder (under some conditions of course).

Controller for views in root

0

Yesterday while developping ukazbobra I realized, that I don’t know how to map controller for my index view in root of Spring MVC project. I searched and experimented a bit and here is a solution. Please note I’m using Spring Roo and annotation driven setup.

First thing is to create controller, for example simple one like this:

@RequestMapping("/")
@Controller
public class RootController {

	@RequestMapping(method = RequestMethod.GET)
	public String index(Model model) {
		model.addAttribute("foo", "bar");
		return "index";
	}
. . .

Now you have to turn off thing named ParameterizableViewController, which staticaly selects a view for for rendering. So open up webmvc-config.xml and remove line with mapping for index view:

<mvc:view-controller path="/" view-name="index"/>

That is all, nothing more, nothing less – you have working controller for your index page in root and also for other views.

Problemy s chromiem na Ubuntu LucidLynx

0

Po jistem update systemu pred nekolika mesici mi zacalo kolabovat Chromium, ale mira kolapsu byla jeste tolerovatelna – cca 2x za den jsem provadel killall a myslel jsem, ze je to nejakym pluginem ci chybou v konfiguraci. Od vcerejska to zacalo kolabovat nepretrzite a stalo se temer nepouzitelnym, tak jsem se rozhodl s tim zacit neco delat a co s tim delam budu psat prubezne sem, protoze jsem se stale nedobral reseni.

Stale jsem mel za to, ze je chyba v konfiguraci meho pocitace, protoze na jinem mi vsechno fungovalo bez problemu (totozna distribuce, verze…), pak jsem ale udelal update virtualu a stalo se mi to stejne, takze jsem si uvedomil, ze na onom jinem stroji mam novejsi verzi Ubuntu a tento problem tudiz postihuje verzi 10.04, takze jsem mel prvotni keywords pro reseni situace. Jeste predtim jsem pro jistotu odinstaloval flash. Napadu a rad jsem potom postupne vyzkousel nekolik:

  • Smazat ~/.config/chromium a ~/.cache/chromium a po nastartovani nepovolovat synchronizaci s google uctem. Provedl jsem a skoncil s vysledkem, ktery ilustruje nasledujici obrazek (a aspon me to docela rozesmalo). V kazdem pripade mazani techto adresaru jsem provadel v kazdem mezikroku, kdyby nahodou neco… Nejzajimavejsi na tomto celem je, ze i kdyz jsem smazal veskere konfiguracni soubory a nepovoloval synchronizaci, presto obcas se mi stalo, ze byly predvyplneny formulare!!! Tento jev si nedokazu nijak vysvetlit.
Zdechly chrome

Zdechly chrome

  • V dalsim kroku jsem si vzal k ruce seznam prepinacu pro spousteni chromia a pokusil jsem se ho spustit v debug rezimu s vypnutymi vsemi pluginy, javascriptem, javou… a mam z toho dojem, ze za vsechny ty problemy muze javascript. Ale web byl totalne nepouzitelny – nemluvim o tom, ze zmizelo pohodli, ale obrovske mnozstvi sajt bylo naprosto neovladatelnych, takze taky tudy cesta nevede.
chromium-browser --log-level=0 --enable-logging=stderr --disable-3d-apis --disable-accelerated-plugins --disable-webgl --disable-java --disable-extensions --disable-plugins --disable-javascript
  • Jako mezikrok jsem zauvazoval o debugovani, ale proboha – copak mam jako uzivatel mit cas instalovat gdb a vrtat se v tom? Z toho uz jsem vyrostl, kdyz jsem dal do haje Gentoo!
  • Jedeme dal – na ubuntu foru to par lidi resilo, vyzkousel jsem vsechny jejich tipy: purge, alternativni repozitar (ne doporucovany beta, ale daily builds, takze jsem vyzkousel i verzi 17.0.926.0) a nakonec jsem zkusil stahnout i primo chrome od Googlu.
  • Na jinem foru lidi zkouseli dalsi alternativni repozitar pro updaty Xek, takze jsem taky zkusil updatovat Xorg a ovladace, odstranit nepouzivane… A vysledek? Haha!
  • Dalsi mezikrok bylo zkusit to zbuildovat, ale ty prerequisities a predevsim naroky hardwarove (10G na disku, 4G pameti, 8G swapfile) a casove (uz ted s tim zabijim vice nez dost casu) – takze strucne receno: „srsly, wtf?“
  • Ve vyse uvedenem foru byl zminovan i upgrade jadra, na coz me privedla i jina diskuze, takze jsem stahnul nejprve 2.6.35-30 a ono (pro zmenu) nic. Dalsim jadrem na zkousku je 2.6.34…a nic. Mam dojem, ze uz delam zoufale kroky, ktere s tim nemaji nic spolecneho.

Vzhledem k tomu, ze na to nemam nekonecne mnozstvi casu, tak asi udelam upgrade systemu na nejakou vyssi verzi, coz jsem nechtel, protoze 10.04 ma byt LTS. Jak vidno, tak zrejme neni a rozumneho reseni se nemuzu dogooglit. Otazka je – je to ostuda pro me, nebo pro Ubuntu?

Adding columns to custom browse.jsp

0

Last week I had to change browse.jsp view in alfresco and I need to add custom columns – attributes from my own data model. It’s pretty simple and I’ll explain that in this blogpost.

I tried to do is as much simple as possible, so I removed all other view types but details and in this view I added some boolean properties, which have own action handler – so are clickable and after click change their state. Result of this changes is on following screenshot.

How does it look like

How does it look like

You can see I added two boolean properties (in Czech – Ano = true, Ne = false) among others (Type). To do that I needed to override BrowseBean and create own NodePropertyResolver. Now from the begining:

  • I created custom document model,
  • wrote custom browse.jsp (just copied and edited original one),
  • overrode outcomes to new view,
  • overwrote BrowseBean and wrote custom NodePropertyResolver.

Creating custom document model is well described everywhere else (at least in alfresco wiki), so I’m not going to describe it here, also overriding views. Lets start with altering browse.jsp.

Items in list are created by RichList component, in which we are interested in just some attributes: viewMode and value. ViewMode is a String value (details, icons, list) with default view mode. When I tried to change ViewMode value to details, it doesn’t work correctly, so I had to override getBrowseViewMode() to return „details“.

public class BrowseTeletextBean extends BrowseBean {
 . . .
private NodePropertyResolver pageExpiredResolver = new BooleanNodePropertyResolver(TxtModel.txtExpired, getNodeService());
 . . .
@Override
public String getBrowseViewMode(){
	return "details";
}

@Override
public List<Node> getContent() {
	List<Node> list = super.getContent();

	for(Node node : list){
		node.addPropertyResolver("pageExpired", pageExpiredResolver);
		 . . .
	}

	return list;
}
 . . .

Value should return list of Node type, in which I wanted to add custom fields, so I needed to override it too. I put there some propertyResolvers – I did my own BooleanPropertyResolver:

public class BooleanNodePropertyResolver implements NodePropertyResolver {
	private NodeService nodeService;
	private QName qName;

	public BooleanNodePropertyResolver(QName qName, NodeService nodeService){
		this.qName = qName;
		this.nodeService = nodeService;
	}

	@Override
	public Object get(Node node) {
		boolean expired = NodeUtils.getBoolProperty(node.getNodeRef(), qName, nodeService);
		return (expired ? "Ano" : "Ne");
	}
}

Now it’s possible to build a list in view like this:

<a:richList id="contentRichList" binding="#{BrowseTeletextBean.contentRichList}" viewMode="#{BrowseTeletextBean.browseViewMode}" pageSize="#{BrowseTeletextBean.pageSizeContent}" styleClass="recordSet" headerStyleClass="recordSetHeader" rowStyleClass="recordSetRow" altRowStyleClass="recordSetRowAlt" width="100%" value="#{BrowseTeletextBean.content}" refreshOnBind="true" var="r">
 . . .
  <a:column id="col14" style="text-align:left">
      <f:facet name="header">
          <a:sortLink id="col14-sort" label="Expired" value="expired" styleClass="header"/>
      </f:facet>
      <a:actionLink id="col14-act1" value="#{r.pageExpired}" actionListener="#{BrowseTeletextBean.clickPageExpired}">
          <f:param name="id" value="#{r.id}" id="param14-1" />
      </a:actionLink>
  </a:column>
 . . .

Here you can see actionLink with value defined by custom NodePropertyResolver (r.pageExpired), which renders either „Ano“ or „Ne“ based on value in TxtModel.txtExpired (QName) property in model.

public static final QName txtExpired = QName.createQName("http://www.alfresco.org/model/txt/1.0", "expired");

ActionLink has an action handler – actionListener parameter – this handler just change value of the expired property and is as simple as this:

public void clickPageExpired(ActionEvent event){
    NodeRef nodeRef = getNodeRefFromParams(event);
    if(nodeRef != null) {
        boolean status = NodeUtils.getBoolProperty(nodeRef, TxtModel.txtExpired, getNodeService());
        getNodeService().setProperty(nodeRef, qName, !status);
        UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
    }
}

Note that UIContext…notifyBeans() is needed to notify beans, that some change had been done and we need to refresh view. For this refresh also refreshOnBind parameter on richList is needed to be true.

It was easy to put it together, but like everything in Alfresco – badly documented. So I hope this post help someone. Feel free to ask questions, if something is not clear enough ;-).

Go to Top