Category: General

General thoughts that defy categorization.

Quick Hack: Creating default folder structures in Alfresco Share sites

Someone recently asked how to create Alfresco Share sites with a default folder structure. Currently, out-of-the-box, when you create an Alfresco Share site, the document library is empty. This person instead wanted to define a set of folders that would be created in the document library when a new Alfresco Share site is created.

Although this exact functionality is not available out-of-the-box, there is something similar. It’s called a “space template”. Space templates have been in the product since the early days but haven’t yet been exposed to Alfresco Share. In the old Alfrexsco Explorer client you could specify a space template when you created a new folder, and the resulting folder would have the same set of folders and documents that were present in the template.

With a little bit of work using the out-of-the-box extension points we can get Alfresco to use space templates when creating new sites in Share. I’ve created this as an add-on and the code lives on GitHub. I thought it might be instructive to review how it works here.

Approach

The first thing to realize is that a space template isn’t special. It’s just a folder that happens to live in Data Dictionary/Space Templates. In fact, there aren’t any API calls specific to space templates. If you go looking for a createFolderFromTemplate() method on a Folder object you’ll be disappointed. When the Alfresco Explorer client creates a folder from a template, it simply finds the template folder and copies its contents into the newly-created folder.

On the Alfresco Share side, a site isn’t that special either. It’s just a special type of folder. The document library that sits within a Share site is also just a folder, albeit a specially-named folder with an aspect. Normally, the document library folder does not get created until the first user actually opens the site and navigates to the document library.

So all we really need to do is write some code that gets called when a site is created, looks up the space template, and then creates the document library folder with the contents of the space template.

What’s the best way for the code to know which space template to use? One way would be to use a specially-named space template for all Share sites. But using a single space template for all Share sites seems limiting. Alfresco Share already has a mechanism for selecting the “type” of site to create–it’s called a preset. So a better approach is to use the preset’s ID to determine which space template to use.

Code

We need to run some code when a site is created. One way to do this is with a behavior. The behavior is Java code that will be bound to the onCreateNode policy for nodes that are instances of st:site. The init() method does that:

// Create behaviors
this.onCreateNode = new JavaBehaviour(this, "onCreateNode", NotificationFrequency.TRANSACTION_COMMIT);

// Bind behaviors to node policies
this.policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"), TYPE_SITE, this.onCreateNode);

So any time a node is create that is an instance of st:site, the onCreateNode() method in this class will get called.

The first thing the onCreateNode() method needs to do is find the space template. To keep things simple, I’m going to assume that the space template is named the same thing as the site preset ID, so all I need to do is grab that preset ID and do a Lucene search to find the template:

NodeRef siteFolder = childAssocRef.getChildRef();

if (!nodeService.exists(siteFolder)) {
logger.debug("Site folder doesn't exist yet");
return;
}

//grab the site preset value
String sitePreset = (String) nodeService.getProperty(siteFolder, PROP_SITE_PRESET);

//see if there is a folder in the Space Templates folder of the same name
String query = "+PATH:\"/app:company_home/app:dictionary/app:space_templates/*\" +@cm\\:name:\"" + sitePreset + "\"";
ResultSet rs = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_LUCENE, query);

If there aren’t any space templates the method can return, otherwise, the space template should be copied into the site folder as the new document library folder:

documentLibrary = fileFolderService.copy(spaceTemplate, siteFolder, "documentLibrary").getNodeRef();

//add the site container aspect, set the descriptions, set the component ID
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
props.put(ContentModel.PROP_DESCRIPTION, "Document Library");
props.put(PROP_SITE_COMPONENT_ID, "documentLibrary");
nodeService.addAspect(documentLibrary, ASPECT_SITE_CONTAINER, props);

I used the fileFolderService to perform the copy, then I set the properties and aspect on the new document library folder with the values that Alfresco Share expects a document library to have.

I’ve left out some insignificant code bits here and there–you can look at the source if you need to. The project was bootstrapped using the Alfresco Maven SDK and includes a unit test that makes sure the behavior works as expected.

Result

The project creates an AMP file. If you’ve checked out the source you can build the AMP using mvn install. Then you can install the AMP into the Alfresco WAR by placing the AMP in the amps directory and run apply_amps.sh. Alternatively, you can use mvn alfresco:install. After installing the AMP into the Alfresco WAR you can test it out.

Out-of-the-box Alfresco Share has a single site type called “Collaboration Site”. The preset ID for that type of site is “site-dashboard”. You might have additional site types configured in your installation. To set up the template for the default collaboration site, navigate to Data Dictionary/Space Templates and create a folder called “site-dashboard”. Then add whatever folders and documents you want to that folder. Now, anytime a “Collaboration Site” gets created in Alresco Share, the document library will automatically be created with the same folders and documents you’ve set up in your space template.

This was not a mind-blowing, deeply-technical extension to Alfresco. Hopefully, it shows you that, with even a few lines of code, you can easily add useful functionality to Alfresco.

Alfresco 4.2.d: The Public API & some CMIS changes you should be aware of

Well, Alfresco Community Edition 4.2.d has been out for a couple of weeks now and everyone I’ve talked to seems pretty excited about the new release. The new ribbon header in the Share user interface, the filmstrip view, and the table view for the document library seems to have gotten all of the attention (and it does look sharp) but my favorite new feature is actually behind-the-scenes: The Alfresco Public API has finally made its way from Alfresco in the cloud to on-premise.

What is the Alfresco Public API?

We’ve talked about it a lot over the last year, but it’s always been cloud-only, so you’re forgiven if you need a refresher. Basically, it means that we now have a documented, versioned, and backward compatible API that you can use to do things like:

  • Get a list of sites a user can see
  • Get some information about a site, including its members
  • Add, update, or remove someone from a site
  • Get information about a person, including their favorite sites and preferences
  • Get the tags for a node, including updating a tag on a node
  • Create, update, and delete comments on a node
  • Like/unlike a node
  • Do everything that CMIS can do

The Public API is comprised of CMIS for doing things like performing CRUD functions on documents and folders, querying for content, modifying ACLs, and creating relationships plus non-CMIS calls for things that CMIS doesn’t cover. When you run against Alfresco in the cloud you use OAuth2 for authentication. When you run against Alfresco on-premise, you use basic authentication.

Some Examples

I created some Java API examples for cloud a while ago. This week I spent some time on those examples to get them cleaned up a bit here and there and to have a really clear separation between what’s specific to running against Alfresco on-premise versus Alfresco in the cloud and what’s common to both. The result is a single set of code that runs against either one.

Here’s how the project is set up:

The remaining classes in com.alfresco.api.example are the actual examples. These would probably be better structured as unit tests but for now, they are just runnable Java classes. Currently there are only four:

  • GetSitesExample.java simply fetches the short names of up to 10 sites the current user has access to.
  • CmisRepositoryInfoExample.java is the simplest CMIS example you can write. It retrieves some basic information about the repository.
  • CmisCreateDocumentExample.java creates a folder, creates a document, likes the folder, and comments on the document. This is a mix of CMIS and non-CMIS calls.
  • CmisAspectExample.java imports some images, uses Apache Tika to extract some metadata from the binary image file, then uses the OpenCMIS Extension to store those metadata values in properties defined in aspects. The extension has to be used because CMIS 1.0 doesn’t support aspects.

Take a look at the readme.md file to see what changes you need to make to run these examples in your own environment.

New CMIS URLs in Alfresco Community Edition 4.2.d

One thing to notice is that starting with this release there are two new CMIS URLs. Which one you use depends on which version of CMIS you would like to leverage. If you want to use CMIS 1.0, the URL is:
http://localhost:8080/alfresco/api/-default-/public/cmis/versions/1.0/atom

If you would rather use CMIS 1.1, the URL is:
http://localhost:8080/alfresco/api/-default-/public/cmis/versions/1.1/atom

New with 4.2.d is the CMIS 1.1 browser binding. Currently Alfresco in the cloud only supports Atom Pub, but if you are only running against on-premise, you might decide that the browser binding, which uses JSON instead XML, is more performant. If you want to use the browser binding, the service URL is:

http://localhost:8080/alfresco/api/-default-/public/cmis/versions/1.1/browser

CMIS Repository ID and Object ID Changes

When using the new URLs, you’ll notice a couple of things right away. First, the repositoryId is coming back as “-default-” instead of the 32-byte string it used to return.

Second, the format of the object IDs has changed. The CMIS specification dictates that object IDs are supposed to be opaque. You shouldn’t build any logic on the content of a CMIS object ID. However, if you have built a client application that stores object IDs, you may want to pay particular attention to this when you test against the new version. The object IDs for the same object will be different than they were when using the old CMIS URLs.

You can see this in 4.2.d. If I use the old “/alfresco/cmisatom” URL, and I ask for the ID of the root folder, I’ll get:
workspace://SpacesStore/ae045ec3-5578-4c7b-b5a6-f893810e63dc

But if I use either the new CMIS 1.0 URL or the new CMIS 1.1 URL and ask for the ID of the same root folder, I’ll get:
ae045ec3-5578-4c7b-b5a6-f893810e63dc

In order to minimize the impact of this change, you can issue a getObject call using either the old ID or the new ID and you’ll get the same object back. And if you ask for the object’s ID you’ll get it back in the same format that was used to retrieve it, as shown in this Python example:

>>> repo.getObject('ae045ec3-5578-4c7b-b5a6-f893810e63dc').id
'ae045ec3-5578-4c7b-b5a6-f893810e63dc'
>>> repo.getObject('ae045ec3-5578-4c7b-b5a6-f893810e63dc').name
u'Company Home'
>>> repo.getObject('workspace://SpacesStore/ae045ec3-5578-4c7b-b5a6-f893810e63dc').id
'workspace://SpacesStore/ae045ec3-5578-4c7b-b5a6-f893810e63dc'
>>> repo.getObject('workspace://SpacesStore/ae045ec3-5578-4c7b-b5a6-f893810e63dc').name
u'Company Home'

Still Missing Some CMIS 1.1 Goodness

The browser binding is great but 4.2.d is still missing some of the CMIS 1.1 goodness. For example, CMIS 1.1 defines a new concept called “secondary types”. In Alfresco land we call those aspects. Unfortunately, 4.2.d does not yet appear to have full support for aspects. You can see what aspects a node has applied by inspecting the cmis:secondaryObjectTypeIds property, which is useful. But in my test, changing the value of that property did not affect the aspects on the object as I would expect if secondary type support was fully functional.

Summary

The Public API is new. There are still a lot of areas not covered by either CMIS or the rest of the Alfresco API. Hopefully those gaps will close over time. If you have an opinion on what should be the next area to be added to the Alfresco API, please comment here or mention it to your account rep.

Don’t get tripped up by MySQL/MariaDB skip-networking default in MacPorts

I recently decided to switch one of my MacBooks from MySQL installed with the binary package to MariaDB installed through MacPorts. I’ve used MacPorts for years and it has worked great for me, although I realize that isn’t the case for everyone.

After installing MariaDB, when I started Alfresco, it couldn’t talk to the database. I thought it might be a MariaDB problem, so I poked around a bit and then installed MySQL from MacPorts. Same problem.

I noticed that the problem was only with JDBC connections. Python didn’t have any trouble connecting nor did any of my non-JDBC database tools. A clue.

Then I noticed that “netstat -an|grep 3306” came back with nothing indicating that the database wasn’t listening on the port at all. I thought maybe it was a networking problem. Maybe permissions. Maybe a my.cnf issue. I tried tweaking all of that but wasn’t making any progress.

I decided there must be a .cnf file somewhere that was hosing me. It turns out that MacPorts installs a default .cnf file for both MySQL and MariaDB that has “skip-networking” turned on. That turns off all network-based connections to the server and that includes JDBC.

I have no idea why that is turned on by default but if you don’t know to look for it, you may chase your tail for a while. The fix is simply to edit the default .cnf file and comment out skip-networking. For MySQL, the file lives here:

/opt/local/etc/mysql55/macports-default.cnf

And for MariaDB the file lives here:

/opt/local/etc/mariadb/macports-default.cnf

Alfresco Roma Meetup Agenda

UPDATE: I’ve updated this post with links to the presentations from the meetup. We had a great turnout. Thanks for coming, everyone!

We did a half-day meetup in Rome on Friday, March 22. The agenda with links to what was presented is as follows:

15:00 to 15:15 Welcome (Jeff)

15:15 to 15:45 Introducing the Alfresco API (Jeff)

15:45 to 16:15 Customer Case Study (Fastweb)

16:15 to 16:45 Alfresco WebScript Connector for Apache ManifoldCF (Piergiorgio Lucidi, Sourcesense)

16:45 to 17:00 BREAK

17:00 to 17:30 Part 1: Alfresco & Semantics, Part 2: RedLink (Ainga Pillai, Zaizi)

17:30 to 18:00 The New Maven SDK (Gab Columbro, Alfresco)

18:00 to 18:15 Invitation to Join the Community (Jeff)

18:15 to 19:00 Pizza, Beer, & Networking

Parenting Hack: Even and Odd Days

I have a sister three years younger than I am. When we were kids we fought over everything. Who gets the front seat. Whose turn is it to take out the garbage. Or to feed the dog. Or to do the dishes. And on and on. As a parent of two kids I now know how crazy that must have made my parents.

Their solution to this was usually along the lines of “If you can’t work it out I’ll work it out for you,” followed by a forced compromise neither of us liked, delivered in exasperation, leaving each of us seething.

Luckily, with my two kids we’ve been using a solution that has worked great for many years, and one that came to us from my sister, ironically enough. We call it “even and odd days”. The way it works is that each child gets a day. When it is that child’s day, they have to do all of the chores, but they also get to reap whatever perks might occur that day. To keep track of whose day it is, one child takes even days and the other takes odd days. In our case, my son’s birthday falls on an odd day and my daughter’s on an even, so making the assignment (and remembering who has even and who has odd) was easy.

For example, the 24th is an even day so it is my daughter’s day. She’s got to feed the dog (both times), empty the dishwasher if it needs it, set the table, and rinse and load the dinner dishes into the dishwasher. But, if there’s a choice about what to have for dinner, she gets to pick. If we’re playing a game, she decides who goes first. So when it is your day you work hard, but you also reap the benefits.

The even and odd days approach takes the emotion and guesswork out of it. Who was the last person to clean the dog poop out of the back yard? Doesn’t matter–today’s an odd day, which means it is your turn, pal!

We started doing this when the kids were probably 5 and 8 and after sticking to it for six years I can say we’ve never had the kind of sibling strife over chores and perks like my sister and I experienced. Every now and then, when one kid’s schedule prevents them from doing a chore on their day and we ask the other one to do it, we’ll get a, “Sorry, not my day” response, particularly if that child has felt like the system hasn’t treated them fairly of late, but that can be dealt with. And when we first started out my son felt a little aggrieved because there are times when odd days occur twice in a row (31st, followed by 1st), but other than those blips, we’re happy with it.

The system even works for chores that are not daily tasks. For example, in our neighborhood, the trash and recycle bins have to be put out on the curb Sunday night. If a Sunday night falls on an even day, it’s my daughter’s task and when it falls on an odd it’s my son’s. Works like a charm.

Tips on Working with Google Fusion Tables

We had a need to see Alfresco forum users by geography. Google Fusion Tables provides the capability to see any geographic location stored in one or more columns on a map. We had successfully used this before for smaller batches of mostly static data, so I decided to see if it would work well for our forum data. This blog post is about what I did, including some useful tips for working with the Google Fusion Table API.

Determining the Location

First, I needed a city and country for each forum user. In our forums, users can declare their location, but not everyone does. So I wrote a little Python script that uses the MaxMind GeoLite database to determine a location for each user based on IP address. The script then compares the IP-determined location with the user’s declared location, and if they are different, it asks the person running the script to choose which one is likely to be more accurate. For example, the IP address based lookup might come back with “Suriname” but the user’s declared location is “Paramaribo, Suriname”, so you’d choose the latter. The script saves each decision so that it doesn’t have to ask again for the same comparison on this run or subsequent runs.

Loading the Data into Google Fusion Tables with Python

Once I had a city and country for each forum user I had to get those loaded into a Google Fusion Table. I found this Python-based Fusion Tables client and it worked quite nicely.

Here are a few tips that might save you some time when you are working with Google Fusion Tables, regardless of the client-side language…

Don’t Update–Drop, then Add

I started by trying to be smart about updating existing records rather than inserting new ones. But this meant that for each row, I had to do a query to test for the existence of a match and then do an update. This was incredibly slow, especially because you can’t do bulk updates (see next point).

So every time I run an update, the script first clears out the table. That means I load the entire dataset every time there is an update, but that is much faster than the update-if-present-otherwise-insert approach.

Batch Your Queries

The Google Fusion Tables API supports bulk operations. You can execute up to 500 at-a-time, if I recall correctly. This is a huge time-saver. My script just adds the insert statements to a list, and when it gets 500 (or runs out of inserts) it joins the list on “;” and then executes the batch with a single call to the Fusion Tables API.

The one drawback, as mentioned in the previous point is that it does not support bulk updates–only inserts are supported. But with the performance gain of bulk operations, I don’t mind clearing out the table and re-inserting.

Throttle Your Requests

If the script exceeds 30 requests per minute it is highly likely you will get rate-limited. So it is important to throttle your requests. I found that a 2.5 second wait between queries was fine and because the queries are batched 500 at-a-time, it really isn’t a big deal to wait.

Geocoding Takes Time

So the whole thing is pretty slick but there is a small pain. Because all rows get dropped every time I load the table, every row has to be geocoded and that takes time. I believe there is an API call to ask the table to be geocoded but I haven’t found that to work reliably. Instead, I have to go to the table in my browser and tell Fusion Tables to geocode the table. This takes a LONG time. For a table of about 10,000 rows it could easily take 45 minutes or more. At least it is something I can kick off and let run. I only update the table once a month. If it were more often, it would be an issue.

Voila!

That’s it! Thanks to Python and Google Fusion Tables, I now have an interactive map of forum users. Not only is it useful to use interactively, it also lets me run geographic queries against it from Python, such as, “find me the 20 forum users with more than X posts who work within a 20 mile radius of this spot” which can be handy for doing local community outreach.

Thoughts on the Alfresco forums

Back in 2009 I wrote a post called, “The Alfresco forums need your help.” It was about how I happened to come across the “unanswered posts” page in the Alfresco forums and noticed, to my horror, that it was 40 pages long. I later realized that the site is configured to show no more than 40 pages so it was likely longer.

Now that I’m on the inside I’ve got access to the data. As it turns out, as of earlier this month, in the English forums we had a little over 1100 topics created over the past year that never got a reply. That represents about 27% of all topics created for that period.

Last year I ran a Community Survey that reported that 55% of people have received responses that were somewhat helpful, exactly what they were looking for, or exceeding expectations. A little over 10% received a response that wasn’t helpful. About 34% said they never saw a response. If you look at the actual numbers for the year leading up to the survey, there were about 1500 topics created that never got a reply, which is again about 28% of all topics created for the same period.

That day in 2009 I suggested we start doing “Forum Fridays” to encourage everyone to spend a little time, once a week, helping out in the forums. I kept it up for a while. The important thing for me was that even if I didn’t check in every Friday, I did form a more regular forum habit. It felt good to see my “points” start to climb (you can see everyone’s points on the member list) and I started to feel guilty when I went too long without checking in.

Since joining Alfresco I’ve been in the forums more regularly. In fact, this month, I decided to make February a month for focusing on forums. I spent a significant amount of time in the forums each day with a goal of making a dent in unanswered posts. I also wanted to see if I could understand why posts go unanswered.

Some topics I came across were unanswered because they were poorly-worded, vague, or otherwise indecipherable. I’d say 5% fit this category. More often were the questions that were either going to require significant time reproducing and debugging or were in highly-specialized or niche areas of the platform that just don’t see a lot of use. I’d say 20% fit this category. These are questions that maybe only a handful of people know the answer to. But at least 50% or maybe more were questions a person with even a year or two of experience could answer in 15 minutes or less.

Alfresco is lucky. Our Engineering team spends significant time in the forums. The top posters of all time–Mike Hatfield, Mark Rogers, Kevin Roast, Gavin Cornwell, Andy Hind, David Caruana, Derek Hulley–are the guys that built the platform. Somehow they manage to do that and consistently put up impressive forum numbers. We also have non-Alfrescans that spend a lot of time in the forums racking up significant points. Users such as zaizi, Loftux, OpenPj, savic.prvoslav, and jpfi, just to name a few, are totally crushing it. It isn’t fair or reasonable for me to ask either of these groups to simply spend more time in the forums. And, while I have sincerely enjoyed Focus on Forums February, I’m not a scalable solution. Instead, I’d like to mobilize the rest of you to help.

I think if we put our minds to it, we should be able to address every unanswered post:

  • Questions that are essentially “bad questions” need a reply with friendly suggestions on how to ask a better question.
  • Time-consuming questions need at least an initial reply that suggests where on docs.alfresco.com, the wiki, other forum posts, or blogs the person might look to learn more, or even a reply that just says, “What you’re asking can’t easily be answered in a reasonable amount of time because…”. People new to our platform don’t know what is a big deal and what isn’t, so let’s explain it.
  • Highly-specialized or niche questions should be assigned to someone for follow-up. If you read a question and your first thought is, “Great question, I have absolutely no idea,” your next thought should be, “Who do I know that would?”. Rather than answering the question your job becomes finding the person that does know the answer. Shoot them a link to the thread via email or twitter or IRC. Some commercial open source companies I’ve spoken to about this topic actually assign unanswered posts to Jira tickets. That’s food for thought.
  • Relatively easy questions have to be answered. Our volume is manageable. We tend to get about 400 new topics each month with 100 remaining unanswered, on average. With a company of our size, with a partner network as big as we have, with as many community members as there are in this world, I see no good reason for questions of easy to medium difficulty to go without a reply.

So here are some ideas I’ve had to improve the unanswered posts problem:

  • Push to get additional Alfrescans involved in the forums, including departments other than Engineering.
  • Continue to encourage our top posters and points-earners to keep doing what they are doing.
  • Identify community members to become moderators. Task moderators with ownership of the unanswered post problem for the forums they moderate. This doesn’t mean they have to answer every question–but it does mean if they see a post that is going unanswered they should own finding someone who can.
  • Continue to refine and enhance forums reporting. I can post whatever forums metrics and measures would help you, the community, identify areas that need the most help or that motivate you to level up your forums involvement. Just let me know what those are.

What are your thoughts on these ideas? What am I missing? Please give me your ideas in the comments.

By the way, while I’m on the subject, I want to congratulate and thank the Top 10 Forum Users by Number of Posts for January of this year:

1. mrogers* 74
2. amandaluniz_z 36
3. MikeH* 30
4. jpotts* 25
5. fuad_gafarov 22
6. zomurn 21
7. Andy* 19
8. RodrigoA 16
9. ddraper* 16
10. mitpatoliya 16

As noted by the asterisk (*) half of January’s Top 10 are Alfresco employees.

And if you are looking for specific forums that need the most help in terms of unanswered posts, here are the Top 10 Forums by Current Unanswered Post Count (as of 2/16):

1. Alfresco Share 210
2. Configuration 169
3. Alfresco Discussion 89
4. Alfresco Share Development 85
5. Installation 82
6. Repository Services 54
7. Workflow 47
8. Development Environment 44
9. Web Scripts 44
10. Alfresco Explorer 40

I’ll post the February numbers next week, and will continue to do so each month if you find them helpful or inspiring.

Screencasts highlighting a few new Alfresco 4 Community features

Alfresco 4 Community was released last week. There’s a nice presentation on slideshare that summarizes what’s new in Alfresco 4, so I’m not going to give a comprehensive list here. And we’re going to be covering the technical details on all of the new features at DevCon in San Diego and London so I’ll save the code snippets for DevCon.

Next week, people all over the world will be celebrating the Alfresco 4 release with informal meetups so I thought in this post I’d prime the pump a bit with a brief list of the more buzz-worthy features and record some short screencasts of those so that if you aren’t able to join one of the worldwide release parties, you can have your own little soiree at your home or office. Just try not to let it get out of control. If the cops do show up, you might mention that the New York Police Department uses Alfresco.

Drag-and-Drop

I’ve been showing Alfresco 4 at JavaOne all week and drag-and-drop was pretty popular. You can drag one or more files from your machine into the repo. And you can move them from one folder to another by dropping onto the folder hierarchy. You’ll need an HTML5-enabled browser for this to work. Here it is in action (this one didn’t get created in HD for some reason):

Document Library In-Line Edit

It’s a little thing, but it’s handy. You can change file names and add tags from the document list without launching the edit metadata panel.

Configurable Document Library Sort Order & Better Site Config

How many times has a customer asked you to change the document library sort order? I know, I know. Now they can do it themselves. Also, you can now brand sites individually, so each site can have its own theme. And components can be renamed to things like your document library don’t have to be called “Document Library”.

Better Administration

The Share Administration panel now has a Node Browser, a Category Manager, and a Tag Manager. The Node Browser and the Category Manager were actually direct community contributions. Tell me again why you are still using the old Alfresco Explorer client?

DM to File System Publish

Last year at DevCon in New York, a bunch of us tackled Brian Remmington, wrestled him to the ground, and refused to let him up until he agreed to add this to the product. Once security was able to break up the scrum we apologized and had a good talk. I think deep down he appreciated our passion. I’m joking, of course, but what’s not a joke is that the DM-to-file system publish functionality is now in there. I’ll update this post with a screencast as soon as I figure out how it works.

So take a look at the presentation for a more complete summary. I didn’t show Activiti or Solr, which are two much-anticipated additions to the product, because the value they add is hard to convey in a short screencast. Feel free to record your own screencasts of your favorite new features and point me to them.

Seven tips after five years working from home

Yesterday morning I was enjoying a bike ride before work and it occurred to me that this month marks my fifth year of working from home. As with all things in life, there are both good and bad aspects to working remotely, but on the whole I think working from home nets out to a Good Thing: I see more of my family, I spend less time and money on driving, and I’m healthier.

Most of these didn’t take five years to figure out, but here they are anyway: Seven Tips on Working From Home:

Tip #1: Take a shower and get dressed, for crying out loud

I know there are a lot of people that like to work from home in their pajamas, but I don’t see how they do that consistently. Can you really have a serious conference call about global strategy when you’ve got Yoda staring up at you from your lounge pants? Plus, I need that shower to wake me up. And, while they may be shorts and a t-shirt, putting clothes on is part of getting into the “I’m working” mindset for you and a good external signal to others around you.

Tip #2: Set expectations with your kids

My kids were 5 and 8 when I started working from home. That meant both were in school for most of the day for most of the year. The other key factor is that they were old enough to understand that Dad’s at home during the day to work, not to play. Younger kids don’t get that at all. And little kids don’t quickly grasp the all-critical Signs of Interrupt-ability:

  • Door Open = Come on in.
  • Door Closed = Think twice!
  • Door Closed with Headphones On = Interrupt only if you are bleeding uncontrollably or the house is on fire, also realizing that it may take several minutes for Dad to come out of The Zone such that he can form words and coherent thoughts.

Tip #3: Set expectations with your spouse/partner/roommate

Similar to the previous point, you’ve got to set some ground rules with your mate. For example, I don’t answer the door or the home phone during work hours. Or work on honey-do’s. Or tell one sibling to stop bugging the other. Or figure out why the printer doesn’t work. When I’m in work mode, I’m at work. Sure, I’m happy to have lunch with the rest of the fam or take a quick break to find out how the kids’ day at school went–that’s part of the appeal to working from home–but my family understands the limits of what they can get away with when I’m in the home office.

Tip #4: Establish a clean break between work and non-work modes

A common complaint from the families of people who work from home is that “they work all of the time”. It is easy to fall into that pattern. I think you’ve got to already have a handle on work-life balance before you start working from home or it can become a bigger problem. It helps if you have space you can dedicate as your work area and a time window you can designate as work-time and try to stick to that. When you are in serious work mode, don’t work from the couch. And on the weekends, don’t hang out in your office. Sure, in crunch times you’ll burn the midnight oil, but don’t let that be all of the time. And, if it is any consolation to your family, at least when you are working all night, you don’t have to drive home in the wee hours.

Tip #5: Collaborate with co-workers/clients in-person from time-to-time

It’s important to form bonds with the rest of your teammates. You can do this when you collaborate with remote tools like Skype and Webex, but it happens much faster in-person. My job involves a lot of travel, so I get plenty of opportunities for face-time with colleagues. When I collaborate remotely with people I don’t see in-person often, I make sure some part of our online collaboration is spent talking about non-work stuff. On client projects, we always tried to be on-site at the start of a project and again at major milestones.

Tip #6: Get out of the house

When your commute is measured in steps, not miles, it is easy to get cabin fever. Staring at the same four walls every day can be a drag. In America, our average day contains an appallingly low amount of walking or other physical activity. Working from home can compound the problem–you’re not getting that vigorous walk from the parking garage to the cubicle twice a day, after all! I try to go out to lunch with friends or family, ride my bike or go for a walk, or attend meetups or networking events. Anything to get out of the house, interact with people, and get the blood flowing. A nice thing about working from home is that it is easier to do a mid-day exercise break, whereas most people in a traditional office have to settle for working out before or after work. If you can take advantage of the opportunity for more exercise and combine that with less eating out, I think working from home can have positive health effects.

Tip #7: Invest in tools

If your company relies on a remote workforce you need to make sure you are providing top-notch tools and infrastructure to facilitate that (disclaimer: I work for a software company that produces content management and collaboration tools). At Optaros, we were a globally distributed team. We used Alfresco for document management, but for project collaboration we used Trac because, although Alfresco Share is awesome for content collaboration, it lacks some of the tools critical for collaborating on code-based projects, like source code control integration and automatically-logged real-time chat. (Those would actually make good community contributions, by the way, hint, hint). Regardless of what you use, the point is, there are a lot of great tools out there (both on-premise and SaaS) that can really make remote teams hum, and this ought to be considered critical infrastructure at your company.

So, overall, it’s been a productive and happy five years working from home and it would be hard to change now. I do miss the higher level of face-time with my teammates, and actually, sometimes I miss the drive–that’s when I did most of my music listening and thinking about the day. But the pros outweigh the cons, for sure.

How about you? Got any working from home tips I’ve missed?

After more than a year, I’m still in love with my Bacchetta recumbent

It’s been about a year and a half since I bought my Bacchetta recumbent. I’ve put about a thousand miles on it so far and I still love it. I ride as much as my schedule will allow, which, unfortunately, isn’t enough.

Jeff on his Bacchetta Giro 26

People are always curious about the bike. Other cyclists chat me up, pedestrians shout questions at me as I ride by, and one couple in a car even pulled out a camera and snapped a bunch of pics while we sat at a light. I have seen other recumbents in the ‘hood and on large organized rides, but they are a very well kept secret around here so the bike tends to get noticed.

To celebrate my Bacchetta-versary, I’ve compiled a list of the most common questions I’ve been asked about the bike over the last year. Maybe it’ll motivate you to give one a spin the next time you’re at your local bike shop.

“What is that thing?”

It’s a recumbent bicycle. It’s called a recumbent because you ride in a reclined or semi-reclined position.

Recumbents come in all shapes and sizes. There are Long Wheel Base (LWB) models where the front wheel is in front of the pedals and Short Wheel Base (SWB) models where the front-pedals are above or in front of the front wheel. There are some with Above-Seat Steering (ASS; seriously, that’s what they call it) and Below- or Under-Seat Steering (BSS/USS). Many recumbents have a standard-sized wheel in the back and a smaller wheel in the front. Others have the same sized-wheel front and back. There are tandem recumbents. There are recumbent tricycles. There are tandem recumbent tricycles. It is unbelievable how many different styles there are, with significant differences in application (heavy loads, long-distance rides, racing), performance, and cost.

Bacchetta Giro 26

My bike is a Bacchetta Giro 26 (ba-KET-a is the Italian pronunciation, but ba-SHET-a is okay too). It’s a “high racer” with a Short Wheel Base, Above-Seat Steering, and 26 inch wheels on the front and back. The Bacchetta Giro and similar models have a unique-looking frame design: the bike essentially has only one main tube running from the rear wheel to the crank on the front-end. The word Bacchetta is actually Italian for “stick” and that name is certainly fitting when you look at the bike. I chose the Giro 26 because it is exciting to ride and looks sportier than its Long Wheel Base cousins.

“Why?”

I could try to make an argument about better efficiency or aerodynamics but that’s not why I ride it. I ride it because it’s comfortable. Try this: Sit in a comfortable chair, put your feet up, extend your arms, but keep them relaxed, and lay back a little bit. That’s what it’s like. While my upright cycling friends are crunched over, staring at their front tires, I ride reclined in comfort, my head naturally positioned to take a look around and enjoy the scenery. The other day a red-tailed hawk flew next to me for a short stretch. I don’t think I would have seen it had I been heads-down on an upright. It’s this open, laid-back style of riding that makes me want to ride as often as possible, as far as possible.

When people ask “why” the question often includes either an implied or an explicit question-within-a-question: “Is there a medical reason you ride a recumbent?” It’s funny that these bikes are so different, people assume something must have happened to you physically to persuade you to not go with an upright bike by default.

In my early teens I did long-distance rides with my father and uncle. I did Freewheel, a week-long ride across the State of Oklahoma, several times. On those rides, it wasn’t uncommon to end a 60- or 70-mile day with various sore spots–hands, ass, crotch, and sometimes knees. On Freewheel, you camp out, so heading to dinner, the shower, anywhere, usually means getting back on the bike. There were times when that was the last thing I wanted to do.

Hardcore upright cyclists will say that on a properly fitted bike with the right gear, you should be able to ride pain-free. That may be the case and to each his own. But for me, on my recumbent, pain is just not an issue. Sure, on a long ride I get tired, but nothing hurts. I’m not an athlete in any sense of the word, but I really feel like time is my only limiting factor when I’m riding my Bacchetta.

(When I first began riding the recumbent I did have some problems with foot numbness but some Specialized shoe inserts fixed that right up).

“Is it hard to ride?”

Honestly, it can take some getting used to. Starts are the biggest issue. On my Bacchetta, my pedal is 27 inches from the ground at its lowest point and 41 inches from the ground at its highest. On an upright, when you first start, your weight pushes down on the pedal and gives you enough forward momentum to get going. On a recumbent your weight gives you no vertical advantage. When starting, you have to push hard on the pedal with one foot while you get your planted foot off the ground and up to the pedal fast enough to get that second stroke in before you lose momentum and fall over. I’ve had some awkward starts and some close calls but I haven’t dumped it over yet.

Heel touch

Tight turns are a little exciting. Because the crank is in front of the front wheel, and because I’ve got giant size 12 feet, it is possible for my heel to come in contact with the front tire. So turns take a little bit of foresight. Even with that in mind, tight turns can be a little unsettling. I can easily turn within the width of my neighborhood street, but our neighborhood bike paths aren’t happening for me. For that reason, you may want to think twice about a recumbent if you primarily ride on tight bike paths rather than on the road.

When I first starting riding it, I found the balance to be a little twitchy. When I was really stroking, it felt like my pedaling was throwing my balance off and I had to consciously correct. Even twisting the grip shift added a wobble. Over time, my body learned to compensate automatically and now it’s a very stable, comfortable ride. When you’re on a long, flat road, maybe with a little tail wind, clipping along at about 18-20, a quiet purr coming from the wheels on the road, you’re not thinking about balance any more–you’re in some sort of recumbent Zen state.

“Is it slow/is it fast/is it hard to climb hills?”

I’m not a hardcore cyclist. I try to ride 50 miles a week, but I don’t always hit that. And I’m definitely not a fast rider. Garmin says my average speed (with stops) is about 15 mph. The Giro, a touring/commuting bike, weighs around 32 lbs, depending on seat choice and pedals. Bacchetta does offer a performance line of bikes, including the all-carbon Aero that weighs about 20 lbs and costs three times as much as the Giro. So I’m a slow rider on a heavy bike. Are you faster than me? Probably. Am I faster on my recumbent than I am on an upright? I think so, but I kind of don’t care.

Hill-climbing is a drag on a recumbent. You can’t stand up, so there’s not much to do about it other than down shift and pedal hard. At least there’s a back rest to push against. When you do make it to the top, though, the reward is oh so sweet. There’s nothing quite like flying down a hill feet first.

“Have you had any problems with it?”

The usual bike stuff. I used to throw my chain all of the time until I figured out how to adjust the derailleur. I’ve had to adjust the disc brakes a bit. From time to time, it sounds like my brake pads are dragging, but it’s intermittent. Every once in a while the chain grabs a leg hair or two, but I figure that’s a self-correcting problem.

Transporting a recumbent can be challenging. I can get it into the back of a mini-van with no problem. I’ve got a Thule roof rack with standard trays. My Bacchetta just barely fits in the tray, but the clamp that would normally hold the down tube on an upright bike doesn’t work for the Bacchetta so I bought an arm that holds the front wheel instead. I’ve seen a Thule rack with a really long tray that actually pivots to make it easier to get a long and heavy bike (like a tandem) onto the roof, which is probably what you’d need for a recumbent with a Long Wheel Base. I’ve seen recumbents on hitch- and trunk-mounted racks as well.

I bought a Garmin Edge 705 GPS cycling computer that came with a magnetic pace/speed sensor add-on. The add-on works great when the magnet on your crank arm and the magnet on your wheel spokes can pass by the same sensor. I think making that work on my Bacchetta would require some soldering, so I don’t monitor my pace and I use the GPS for speed. The included maps still made the bundle worth it, though.

“Can I ride your bike?”

If you’re thinking about buying a recumbent, you need to ride as many different styles as you can. They all feel different. And, at least when you are starting out, it helps to have someone that knows what they are doing give you some pointers and fit the bike to you.

I’m 6’1″, so I ride the “large” version of the Giro 26. Once you’ve got the right frame size, there are still several things you can tweak. The seat moves forward and backward and the recline angle is adjustable. The handle bars can be brought forward or backward and the handle bar tilt can be adjusted. Because it is so adjustable, it is a bit of a pain to let someone with different dimensions ride it. But bike shops deal with that all of the time so don’t be afraid to ask for that test ride.

“Where can I get one?”

Some bike shops specialize in recumbents. These will have the best selection and the most knowledgeable staff. For example, if you’re in the Austin area, I highly recommend a visit to Easy Street Recumbents. Mike is super friendly and very helpful. Unfortunately, there’s not a shop that specializes in recumbents here in North Texas. Shops around here tend to have a limited selection or none at all. I bought my Bacchetta at Plano Cycling and Fitness. They were great and I’d recommend them in a heartbeat.

Sometimes you can buy directly from the manufacturer. Bacchetta has that option if a dealer isn’t in your area. Also check out used bikes on Craig’s List, recumbent forums, etc.

Jeff comes home after a ride

I hate cold weather but I rode straight through winter this year. I couldn’t let it sit. I wanted to be out there, kicked back and pedaling hard. There’s something about riding that bike that I miss terribly when I don’t do it. I suspect many recumbent riders feel this way. The next time you’re about to yell, “Hey, nice bike!” at someone on a ‘bent, check to see if he isn’t already smiling.