Thursday, October 30, 2014

Reindex in SOLR4 in Alfresco

In Alfresco 5.0.b har been introduced which has a different (better!) SOLR folder layout. It is slightly different, so to reindex a SOLR4 instance in Alfresco 5.0.b. You should delete or move alf_data/solr4/*. This takes care of cached content nodes, models, and index.

SOLR data/indexes
<ALF_DATA>/solr4 or normally <ALFRESCO_HOME>/alf_data/solr4


BTW SOLR4 configuration is now in alfresco root <ALFRESCO_HOME>/solr4

Wednesday, October 22, 2014

Faceted forms - form based on node state (metadata)

A nice thing about Alfresco Share is that, you get a lot of functionality for free and it is very adaptable. But often you want more client-side adaptability and the first think that comes into mind is client-side Javascript. To avoid client-side javascript customization on Share I made a special form evaluator, which gives you the power to have different forms for the same node type, depending on the state/metadata values.

Normally you define a node type form for view and edit of existing nodes:

 <config evaluator="node-type" condition="my:nodeType"> ...

This is one time solution for alle nodes of this type and lifecycle. To use a facetted approach, you could now add form configuration depending on a metadata property, like:

  <config evaluator="facet-node-type" condition="my:nodeType,my:state=open">

and another

  <config evaluator="facet-node-type" condition="my:nodeType,my:state=closed">

This means (given this facet-node-type exists and works :) you should have a resulting form configuration of the 'node-type' and one 'facet-node-type' given your node either have state 'open' or 'closed'

This evaluation is done Share-server-side, so the state (my:state) should preferable be read-only in the resulting forms.

In my example we could have a text field for an 'open' node and none for a 'closed' on.

To make this work we need to define the 'facet-node-type' in the form-config xml

<alfresco-config>
  <plug-ins>
    <evaluators>
      <evaluator id="facet-node-type" class="com.redpill-linpro.alfresco.web.config.forms.FacetNodeTypeEvaluator" />
       </evaluators>
  </plug-ins>

...

and mainly the java code Source FacetNodeTypeEvaluator.java

Finally lets show the full 'condition' definition available:

General format

condition="<node-type>,<property-evals>"

Where <node-type> is the prefix-nodetype  like in the standard node-type evaluator ...

Where <property-evals> is of the format:

 <property-eval>[,<property-eval>]*

And <property-eval> is of the format

<property-name>=<property-value>[|<property-value>]*


So I could write the following to select only 'my:node-type' nodes with 'my:state' 'open' or 'closed' and 'my:color' set to 'blue'

condition="my:nodeType,my:state=open|closed,my:color=blue"

This can be used to have a form definition where one-large common form (section) is defined and various small modifications of this is in facet-node-type sections depending on the metadata of the node.








Friday, September 19, 2014

Maven problems in 4.2.e-f and 4.20

I you need access to some java classes in a Alfresco Maven project it might give you problems with an artifact which did not get properly inserted into the maven.alfresco.com repository. The issue is also described in various issues, among others: https://issues.alfresco.com/jira/browse/MNT-10118

I solved access to alfresco-repository, alfresco-web-framework-commons, alfresco-remote-api & alfresco-web-client 

Using these dependencies in my Alfresco repo maven pom, where the parent pom used the alfresco platform.

    <dependencies>
        <dependency>
            <groupId>${alfresco.groupId}</groupId>
            <artifactId>alfresco</artifactId>
            <type>war</type>
        </dependency>
        <dependency>
            <groupId>${alfresco.groupId}</groupId>
            <artifactId>alfresco-repository</artifactId>
            <scope>provided</scope>
             <exclusions>
                <exclusion>
                    <groupId>org.alfresco</groupId>
                    <artifactId>alfresco-web-framework-commons</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
         <dependency>
            <groupId>${alfresco.groupId}</groupId>
            <artifactId>alfresco-web-framework-commons</artifactId>
            <scope>provided</scope>
            <version>${alfresco.version}</version>
        </dependency>
       
        <dependency>
            <groupId>${alfresco.groupId}</groupId>
            <artifactId>alfresco-remote-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>${alfresco.groupId}</groupId>
            <artifactId>alfresco-web-client</artifactId>
            <scope>provided</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.alfresco</groupId>
                    <artifactId>alfresco-web-framework-commons</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

Monday, September 8, 2014

Resolving jobs kept in 'Sync Pending' in Alfresco Cloud sync

In Alfresco you can sync your on-premise documents to Alfresco Cloud, given you have a sync-enabled Alfresco Enterprise license and a Alfresco Cloud login/network.

The Cloud sync (on premise) has a pull and a push job which pulls fron or pushes to the cloud. This works out of the box and in newer version 4.2.x. Cloud sync is only for one server ('PRODUCTION').

Example for cloud sync enabling settings:

system.serverMode=PRODUCTION
syncService.mode=ON_PREMISE
sync.pushJob.enabled=true
sync.pullJob.enabled=true

Troubleshooting the sync is described here: https://docs.alfresco.com/4.2/concepts/cloud_sync_troubleshooting.html

A detail which I discovered the hard-way is that the push job is dependent on the audit-system. It uses the audit messages to findout if anything has happen, since last sync (no audit -> do not run). Therefore, if you disable the audit trail, the push-job never runs. You will not see anything in the logs.

So remove any 'audit.enabled=false' if you have sync-jobs kept in pending state on your on-premise installation. Audit is enabled OOTB, but alternatively set the last line in your alfresco-global.properties to audit.enable=true

Tuesday, August 12, 2014

Using a bean instanciated TaskListener in an Activiti Workflow

In Alfresco (ONE ~ ECM) Activiti you can use a Java TaskListener, which has the following advantages:
 - Is Java, preference for some, is more powerful in Alfresco
 - Compared to inline Activiti JS script, it is easier to reuse
 - Can be changed on running workflows (bug fixes etc.)
 - Can be reloaded dynamically using spring-loaded or JRebel

First you must create your TaskListener (different types exist):

public class StartTaskCreate extends TaskCreateListener {
  @Override
  public void notify(DelegateTask task) {
     // ... I can walk!

     // you stuff goes here ...
   super.notify(task); 
 }
}

Then yoiu must create a bean definition (using bean parent to init super class):

 <bean id="my.StartTaskCreate"
        class="my.StartTaskCreate"
        parent="activitiCreateTaskListener"/>


 Then you must let Activiti know about it (put into activitiBeanRegistry map):

<bean id="my.activitiBeanRegistry"  class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" depends-on="activitiBeanRegistry">
    <property name="targetObject">
      <ref bean="activitiBeanRegistry" />
    </property>
    <property name="targetMethod" value="put" />
    <property name="arguments">

      <list>
        <value>StartTaskCreate</value>
        <ref bean="my.StartTaskCreate" />
       </list>
    </property>
  </bean>


I use method invoking via Spring to add to existing bean-map, this makes the solution deployable as AMP (not tomcat/shared/..) and in a solution with many extensions more robust. Also Alfresco can change the orginal definition somewhat without this breaking, robust across Alfresco versions!

Then use it!
<process ...
...
<startEvent id="alfrescoStartevent1" name="Start" activiti:formKey="...">
  <extensionElements>
    <activiti:taskListener event="create" delegateExpression="${StartTaskCreate}"/>

...

Observe the key in activitiBeanRegistry is the word to use in the workflow delegate expression ~ delegateExpression="${StartTaskCreate}"

Monday, August 4, 2014

Override Alfresco Share action order

To override the action order in documentlibrary extensions, your can do so by defining the action group with new index for action.

EX:

<actionGroups> 
  <actionGroup id="document-browse">
    <action index="XYZ" id="document-move-to" />
...


An important rule is use three digits, always three digits! So to move an action up in the top (lower than index 100), so it will become visible document browsing use prefixes of zero (0) ~I think it probably does a string compare somewhere, would explain the behaviour.

EX:

<actionGroups>
  <actionGroup id="document-browse">
    <action index="099" id="document-move-to" />

...

Wednesday, June 25, 2014

Alfresco JS webscripts - no comments before

Errors like:
Caused by: org.mozilla.javascript.EvaluatorException: syntax error (file:/opt/alfresco/tomcat-share/webapps/share/WEB-INF/classes/alfresco/web-extension/site-webscripts/dk/redpill-linpro/alfresco/share/header/share-header.get.js#5)
    at org.mozilla.javascript.DefaultErrorReporter.runtimeError(DefaultErrorReporter.java:109)


Can be caused by comments in js-controller file before <import> statements, EX:
-------------generating error--------
//overridden
<import resource="classpath:/alfresco/web-extension/site-webscripts/dk/redpill-linpro/alfresco/share/imports/share-header.lib.js">
...
-------------no error --------
<import resource="classpath:/alfresco/web-extension/site-webscripts/dk/redpill-linpro/alfresco/share/imports/share-header.lib.js">
//overridden
...


Silly but true

Monday, June 16, 2014

... renaming users

Trying to find out how to get the activities feed and activities dashlets working for AD sync'ed mixed-case usernames ... I found some help in the property: user.name.caseSensitive

Setting it to true works for activity feeds, if you set it form the beginning, but not if on a running system ...

After playing with the alfresco-global.properties, i found AD sync'ed some users were 'moved'. EX: from userName 'LULA' to 'LULA80cb1574-7b9b-4cfb-b82f-f0c72a5ea346'. All authoritive containers were changed.

This happened because Alfresco was set with the properties:

user.name.caseSensitive=false

I changed it back, but damage was done! 

And when the user with AD-username in uppercase, EX: 'LULA', alfresco wanted to reuse it for the new username (in a different case) and renamed it.

The user was not deleted because of property:

synchronization.allowDeletions=false


 Using AE 4.1.1.3 i decided to try and recover the users changed (only ones that tryed logging in). I found out the users with changed usernames still had the correct zones (synchronization subsystem).

Lets try to rename the user. First observation was javascript console cannot change the userName (permission denied), probably need to be system user, so I found the rename User tool.

- stop Alfresco

- comment out vti module contexts: 

tomcat/webapps/alfresco/WEB-INF/classes/alfresco/module/org.alfresco.module.vti/module-context.xml file:

EX:
<beans>
<!-- <import resource="classpath:alfresco/module/org.alfresco.module.vti/context/*-context.xml"/> -->
</beans>


- go into 'tomcat/webapps/alfresco/WEB-INF'

- run RenameTool:
java -XX:MaxPermSize=512m -classpath ../../../lib/*:../../../endorsed/*:lib/*:classes:classes/alfresco/module:classes/alfresco/module/org.alfresco.module.vti:../../../shared/classes org.alfresco.tools.RenameUser -user admin -pwd admin LULA80cb1574-7b9b-4cfb-b82f-f0c72a5ea346 LULA -verbose

- Reenable VTI

- start Alfresco

- Change in Javascript console (installed?) cm_owner on user:
var person = people.getPerson("LULA");
person.properties.owner="LULA";
person.save();


- site membership should be restored :)

- Now find out which AD groups was removed :(

Friday, June 13, 2014

No customize dashboard after applying custom presets

In Alfresco Share 4.2.x menu has changed and some of this is implemented share-header.get.js and share-header.lib.js.

 When making a custom preset for a site 'type', normally you would give it a custom title and titleId. This causes the customize Dashboard option to disappear, there fore you need to modify line 1531 (form 4.2.2) to include your custom dashboard title id:

share-header.lib.js:
...
 // If on the dashboard then add the customize dashboard option...
 if (page.titleId == "page.siteDashboard.title" || page.titleId == "page.meeting_workspace.title")
            {


...

Tuesday, April 1, 2014

Upgrading postgresql database from Alfresco installer

I had the pleasure to battle a little with postgresql installed by Alfresco installers. What I found out is that Alfresco tends to change the software; mainly the location of files, scripts and used libraries ... they probably have good reasons to do this, to ensure consistency across installations, but this makes it hard to follow standard software procedures ...

For the postgresql installation, what you need to know is that the original postgresql binary are renamed/postfixed with '.bin', EX: pg_ctl -> pg_ctl.bin ... and a new script file has been added called pg_ctl, which calles the original and ensures its environment.

After using some time on that, I found two ways to tackle that:
 - pg_upgrade, which needs clean version, so compile clean versions corresponding to the new and old postgresqls following this guide, using http://www.openscg.com/2013/04/how-to-compile-postgresql-9-2-x-from-source-on-ubuntu-12-x/ - however setting different prefixes in configure, EX: --prefix /usr/local/postgresql-9.2.4

 - use the guide here https://www.fossoffice.com/blog/2012/12/13/alfresco-community-4-0-e-to-4-2-c-upgrade-procedure/ - I skipped the lucene part switch

I ended up doing the latter, because i ran into the xlog problems with a seemingly dirty db, like: http://www.brentmc79.com/posts/psql-could-not-connect-oh-fuck-you


Wednesday, February 26, 2014

Monkey patching Alfresco Repo JS webscript

While Alfresco Share is now has many methods of overloading, overriding, changing, adding, removing functionality. Alfresco Repository have few, and a common pattern for larger solution is to replace existing files fully overriding functionality. While this works it is hard to maintain.

1) Replace file by overriding, hard to maintain, 'cannot' be undone
2) Override URL, by making your own Webscript and specifying the same URL, this is better, but require files, and it does not work for *.lib.js files
 - for *.lib.js (imported files), you can override all the webscripts that use that lib-file, and in the overload import your own, thus no file is overridden ... but for some lib-files this means too much work for the gain

3) Change Share/Frontend code to use a different Repo-webscript (your own), then provide you own webscript. This can in many cases be done with share-configuration.


Future will probably improve this:
http://blogs.alfresco.com/wp/developer/2012/05/23/webscript-extensibility-on-the-alfresco-repository/

With approach 2 & 3 you will still have the original JS code in the Alfresco webapp, and this fact can be used to monkey-path the file, minimizing the amount of code to-be-written, increase reuse and maintainability.

Example, standard Repo webscript pattern:

A.get.js

<#import ../B.lib.js >

function C() { ... };

function main() { ... };

main();


Monkey- patch file:

D.get.js

<#import /full-path-to-A/A.lib.js >

function C() { .... monkey-patch-with-your-code... };


Now D.get.js will have the same functionality as A.get.js, but with your change ...


BUT the resulting file will have two C-functions! Yes, but javascript only runs the last declared ... so it works.

In the Javascrip debugger:



D.get.js - @runtime


<#import ../B.lib.js >

function C() { ... };

function main() { ... };

main();

function C() { .... monkey-patch-with-your-code... };


See this discussion: http://stackoverflow.com/questions/15810249/which-and-how-javascript-function-will-be-called-if-we-have-2-function-declarati

Friday, January 10, 2014

Alfresco Share project - Maven setup with Java code

If you need a Alfresco Share - Maven pom with support for java code (ex. BaseEvaluators) ... You need this workaround for Alfresco Enterprise 4.2.0 in your <dependencies>:
 
<dependencies>
       <dependency>
            <groupId>${alfresco.groupId}</groupId>
             <artifactId>alfresco-share</artifactId>
            <version>${alfresco.version}</version>
            <scope>provided</scope>
            <exclusions>
               <exclusion>
                  <groupId>${alfresco.groupId}</groupId>
                  <artifactId>alfresco-web-framework-commons</artifactId>
              </exclusion>
           </exclusions>
        </dependency>
        <dependency>
        <!-- work around for error in POM, should be fixed in 4.2.1
        https://issues.alfresco.com/jira/browse/MNT-10118 -->
            <groupId>${alfresco.groupId}</groupId>
            <artifactId>alfresco-web-framework-commons</artifactId>
            <version>${alfresco.version}</version>
            <scope>system</scope>
            <systemPath>${tomcat.home}/webapps/share/WEB-INF/lib/alfresco-web-framework-commons-${alfresco.version}.jar</systemPath>
        </dependency>

...
  </dependencies>


and now you can start coding!