Saturday, June 22, 2013

JUnit TemporaryFolder Rule


If you need a temporary directory or file for testing and you are using jUnit, @Rule together with TemporaryFolder solves your problem. 
The TemporaryFolder Rule allows creation of files and folders that are guaranteed to be deleted when the test method finishes (whether it passes or fails) 
@Rule

public TemporaryFolder tempFolder = new TemporaryFolder();
...

@Test
public void testFileCreation (){
        File myFolder = tempFolder.newFile("test.);
        fileGenerator.createFiles(2, myFolder);
        myFolder.listFiles().length == 2;
}
The files that were generated will be deleted once the test finishes executing.

Wednesday, May 15, 2013

Using Groovy Closures To Simplify Working With Alfresco Transactions

If you are familiar with Alfresco transactions than you will be familiar with the following:
  
Boolean result = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Boolean>() {
            public Boolean execute() throws Throwable {
                //Your code
                return true;
            }
}, false, true);
This is quite a bit of code and gets ugly if you start embedding a bunch of code inside this block. It is also not very testable with out some crazy mocking.


Groovy Closures to the rescue. http://groovy.codehaus.org/Closures
I created a simple TransactionHelper Groovy class with a method that takes a closure and wraps the closure inside of the above code required for a transaction and wired it as a Spring Bean.

import org.alfresco.repo.transaction.RetryingTransactionHelper
import org.alfresco.service.transaction.TransactionService
class TransactionHelper {
    private TransactionService transactionService
    def executeInSperarateTransaction(closure) {
        Boolean result = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Boolean>() {
            public Boolean execute() throws Throwable {
                closure()
                return true
            }
        }, false, true)
    }
    void setTransactionService(TransactionService transactionService) {
        this.transactionService = transactionService
    }
}

Now if I need to execute a transaction I can simply do the following.
transactionHelper.executeInSperarateTransaction({ nodeService.addAspect(nodeRef, MyModel.THUMBNAIL_ASPECT, new HashMap<QName, Serializable>())})


You can simply pass a closure statement like above or pass in a closure like the following.

def closure() {
  def localVariable = new java.util.Date()
  return { println localVariable }
}
transactionHelper.executeInSeperateTransaction(closure)
 
For more information on Groovy and Closures see http://groovy.codehaus.org/Closures 

Wednesday, April 10, 2013

Bootstraping Users with Alfresco



Bootstrapping data is a very common thing to do when deploying new modules.   You may be expecting a certain taxonomy, certain set of rules, certain categories, certain users, certain metadata , etc. to be available to your new module.  http://wiki.alfresco.com/wiki/Bootstrap_Data shows you how to bootstrap files, spaces, and categories. But I wanted to bootstrap a user that was going to be used to for a third-party system to interact with Alfresco.  After some searching I came across http://forums.alfresco.com/forum/developer-discussions/repository-services/howto-bootstrap-users-09182008-1214 which  described most of what I needed to do.
In order to bootstrap users you need to:

Create an xml file containing the person information (people.xml)

<?xml version="1.0" encoding="UTF-8"?>
<view:view xmlns:view="http://www.alfresco.org/view/repository/1.0" xmlns:alf="http://www.alfresco.org" xmlns:d="http://www.alfresco.org/model/dictionary/1.0" xmlns:sys="http://www.alfresco.org/model/system/1.0" xmlns:act="http://www.alfresco.org/model/action/1.0" xmlns:rule="http://www.alfresco.org/model/rule/1.0" xmlns:fm="http://www.alfresco.org/model/forum/1.0" xmlns:app="http://www.alfresco.org/model/application/1.0" xmlns:usr="http://www.alfresco.org/model/user/1.0" xmlns:ver="http://www.alfresco.org/model/versionstore/1.0" xmlns:cm="http://www.alfresco.org/model/content/1.0" xmlns="">
    <cm:person view:childName="cm:0001">
        <view:acl>
            <view:ace view:access="ALLOWED">
                <view:authority>jbarrett</view:authority>
                <view:permission>All</view:permission>
            </view:ace>
        </view:acl>
        <view:properties>
            <cm:firstName>Josh</cm:firstName>
            <cm:lastName>Barrett</cm:lastName>
            <cm:email>jbarrett2k3@gmail.com</cm:email>
            <cm:userName>jbarrett</cm:userName>
            <cm:homeFolder>workspace://SpacesStore/MY_USERS_HOME</cm:homeFolder>
            <cm:organizationId></cm:organizationId>
            <cm:sizeQuota>-1</cm:sizeQuota>
            <cm:sizeCurrent>0</cm:sizeCurrent>
        </view:properties>
    </cm:person>
</view:view>

Create an xml file containing the authority information (authorities.xml)

<?xml version="1.0" encoding="UTF-8"?>

<view:view xmlns:view="http://www.alfresco.org/view/repository/1.0" xmlns:alf="http://www.alfresco.org" xmlns:d="http://www.alfresco.org/model/dictionary/1.0" xmlns:sys="http://www.alfresco.org/model/system/1.0" xmlns:act="http://www.alfresco.org/model/action/1.0" xmlns:rule="http://www.alfresco.org/model/rule/1.0" xmlns:fm="http://www.alfresco.org/model/forum/1.0" xmlns:app="http://www.alfresco.org/model/application/1.0" xmlns:usr="http://www.alfresco.org/model/user/1.0" xmlns:ver="http://www.alfresco.org/model/versionstore/1.0" xmlns:cm="http://www.alfresco.org/model/content/1.0" xmlns="">

    <usr:user view:childName="usr:jbarrett"><!-- the value of usr must be the username -->

        <view:properties>

            <usr:username>jbarrett</usr:username>

            <usr:password>b02e3a7432ac716fdc2bb8df46ec5ab8</usr:password> <!—MD4 Hash which can be generated following the instructions http://wiki.alfresco.com/wiki/Security_and_Authentication#How_to_generate_the_correct_MD4_hash. -->

            <usr:accountExpires>false</usr:accountExpires>

            <usr:credentialsExpire>false</usr:credentialsExpire>

            <usr:accountLocked>false</usr:accountLocked>

            <usr:enabled>true</usr:enabled>

        </view:properties>

    </usr:user>

</view:view>

Bootstrap the xml files via a spring context file (mymodulebootstrap-context.xml)

<?xml version='1.0' encoding='UTF-8'?>

<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>

<beans>

    <bean id="myModlue_bootstrapSpaces" class="org.alfresco.repo.module.ImporterModuleComponent" parent="module.baseComponent">

        <property name="moduleId" value="myModule" />

        <property name="name" value="myModule.bootstrapSpaces" />

        <property name="description" value="Initial data requirements" />

        <property name="sinceVersion" value="0.0.1" />

        <property name="appliesFromVersion" value="0.0.1" />

        <property name="executeOnceOnly" value="true" />



        <property name="importer" ref="spacesBootstrap"/>

        <property name="bootstrapViews">

            <list>

                <props>

                    <prop key="path">/${system.system_container.childname}/${system.people_container.childname}</prop>

                    <prop key="location">alfresco/module/myModule/bootstrap/people.xml</prop>

                </props>

            </list>

        </property>

    </bean>



    <bean id="myModule_bootstrapUserGroups" class="org.alfresco.repo.module.ImporterModuleComponent" parent="module.baseComponent">

        <property name="moduleId" value="myModule" />

        <property name="name" value="myModule.bootstrapGroups" />

        <property name="description" value="Initial data requirements" />

        <property name="sinceVersion" value="0.0.1" />

        <property name="appliesFromVersion" value="0.0.1" />

        <property name="executeOnceOnly" value="false" />

        <property name="importer" ref="userBootstrap"/>

        <property name="bootstrapViews">

            <list>

                <props>



                    <prop key="path">/${alfresco_user_store.system_container.childname}/${alfresco_user_store.user_container.childname}</prop>

                    <prop key="location">alfresco/module/mymodule/bootstrap/authorities.xml</prop>

                </props>

            </list>

        </property>

    </bean>
</beans>

That is all that is needed to bootstrap a user.


Tuesday, January 22, 2013

Cool Online Agile Board

http://leankit.com/

I stumbled across this tool today and it looks pretty neat. 

The free account allows for 25 users and 10 boards.