Blogroll

The New Domino Admin

A great source of information for Lotus Domino administrators

ecmarchitect.com

Jeff Potts' excellent ECM/Portal blog

Jared Ottley

Lots of very useful Alfresco articles

Looking for web hosting?  I have been using DreamHost for years and have found them to be reliable, inexpensive and very good at what they do!  Click below to sign up, use promo code 'unorganized' to get a free domain registration and 10 bucks off your first year of hosting!

 

dreamhostBadge

Home
Jython and Alfresco - CMIS to the rescue! PDF Print E-mail
Written by Nathan McMinn   
Monday, 02 August 2010 18:13

Where I work, we have a customized report generation tool called ARC.  Based on JasperReports, ARC is an insanely powerful tool for building very complex reports.  ARC goes well beyond what JasperReports can do on its own, and uses Python as a scripting language (via Jython), allowing our developers to stitch together content and data from many disparate sources into pixel-perfect reports.  Alfresco is a natural fit in this environment as a place to store images, PDF files and other report artifacts, as well as a destination for completed reports.  The question is, how do I integrate Alfresco into a Python scripting environment?  The answer is really simple:  cmislib.

 

Alfresco has a very good implementation of the CMIS interface.  This set of services is how applications such as Zia Consulting's FreshDocs interface with Alfresco.  Part of the Chemistry project hosted at the Apache Incubator, cmislib is a Python implementation of a CMIS client.  It makes use of the AtomPub bindings specified by CMIS.  While I was able to find a good bit of documentation about CMIS in a regular Python environment, I wasn't able to find any good information about using it from within Jython.  So, I decided to test it with two versions of Jython:  2.2.1 and 2.5.1.  To start, I downloaded the latest version of cmislib (version 0.3) and unzipped it.  I don't have my Jython environment set up to deal with Python "eggs", so I pulled down the source distribution and copied the /src/cmislib directory from the source distribution to the /lib directory of my Jython installations.  Once cmislib was installed, I started up a Jython interpreter and tried to create a CmisClient object:

 

1
from cmislib.model import CmisClient

 

The CmisClient object is the initial class that is used to connect to the repository. In version 2.2.1, there is an immediate showstopper:

 

1
2
3
4
5
6
Traceback (innermost last):
File "<console>", line 1, in ?
File "C:\My\jython2.2.1\Lib\cmislib\model.py", line 1325
class ResultSet():
^
SyntaxError: invalid syntax

 

So, scratch Jython 2.2.1 off the compatibility list.  With Jython 2.5.1, everything worked as expected.  Once you have the CmisClient imported, you can start mucking around with your repository.  You would typically start by getting a repository to work with.  A CMS can contain multiple repositories.  Cmislib provides a few methods for getting at them.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
# instantiate a client
client = CmisClient('http://yourserver.com/path/to/cmis', 'user', 'pass')
 
# get a dictionary of all the available repositories
repositories = client.getRepositories()
 
# get the default repo. Per the source for CmisClient, CMIS doesn't specify
# a default. So, the client just returns the first one in the dict
defaultRepo = client.getDefaultRepository()
 
# if you know the repo ID, you can get an individual repository
singleRepo = client.getRepository(id)
 

 

The Repository class represents a single repository within the larger CMS.  This class has a few handy methods.

 

1
2
3
4
5
6
7
8
9
10
11
12
# get the repository info, including repo vendor and supported CMIS version
info = repo.getRepositoryInfo()
 
# get the repo capabilities, including whether or not the repo supports
# multifiling, unfiled items, query modes, etc
capabilities = repo.getCapabilities()
 
# get the root folder in the repo
rootFolder = repo.getRootFolder()
 
# get an arbitrary folder in the repo by ID
someFolder = repo.getFolder(id)

 

The cmislib model also defines a parent CmisObject class and useful subclasses including Document, Folder, Relationship and Policy.  Document and Folder classes are fairly self-explanatory.  They represent folders and documents in the CMS.  Document objects contain methods to get and set a content stream for the document, check a document in and out, and get information about the document.  Folder objects can be used to create new documents and nested folders, and also have methods to get information about the folder, such as its children.  Relationship objects are used to define a relationship between two CMIS objects.  For example, you could define a relationship between a product image and a product brochure in the CMS.  The Policy class is pretty sparse.  I think that it is there for completeness but is just a stub for now (other than what it inherits from the CmisObject class).

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# get the root foler
root = repo.getRootFolder()
 
# create 'image' and 'pdf' folders
imageFolder = root.createFolder('image')
pdfFolder = root.createFolder('pdf')
 
# create new image and pdf documents
imageDoc = imageFolder.createDocument('newimage.jpg')
pdfDoc = pdfFolder.createDocument('newpdf.pdf')
 
# add content to the image and pdf
imageDoc.setContentStream(localImage)
pdfDoc.setContentStream(localPdf)
 
# check out the PDF 
pdfDoc.checkout()
 
# if the image is checked out, find out who has it checked out and
# then undo the checkout
if imageDoc.isCheckedOut:
    user = getCheckedOutBy()
    imageDoc.cancelCheckout()
 
# create a relationship between the image and the pdf of the specified type
relationship = imageDoc.createRelationship(pdfDoc, type)
 

 

As you can see, the CMIS interface is a very full featured interface to Alfresco and other CMS packages that support the standard.  Cmislib is a solid client implementation, and seems to work perfectly with Jython.

Last Updated on Thursday, 05 August 2010 20:44
 
Joomla Editors - Best for Code? PDF Print E-mail
Written by Nathan McMinn   
Tuesday, 27 July 2010 11:30

Most of the articles I post here are at least somewhat related to my job as a software engineer.  As a result, I end up posting a fair bit of code.  I use Joomla! to manage this site, and I have never really been happy with the way it handles snippets of code in my articles.  The TinyMCE editor was installed in my Joomla site, and I never really investigated replacing it.  Lacking a better option, I've been using my theme's "preformatted" style whenever I want to insert code into an article.  It preserves my indents and provides a nice visual distinction of what is code and what is text.  But, it's a bit limited.  I want a nice, simple way to embed code in my articles that supports a few key features like line numbers and syntax highlighting. 

 

Joomla appears to have a few options.  There is a Highlight code with Jumi plugin that adds a button to TinyMCE, but the installation failed when I tried to install it.  Another plugin called SyntaxHighlighter looked promising, but it is very simple and is not much better than my existing "preformatted" solution.  There are also a few other options like CodePress and GeshiBot that come up as the top Google results, but both are unpublished because they aren't 1.5.x compatible.  Finally, I found an article that pointed me to JCE and RJ_InsertCode by Ryan Juckett.  It supports all the languages I commonly work with, including Java, JavaScript, Python, SQL and even ActionScript!.

 

1
2
3
4
5
6
7
8
function drawChart() {
var data = new google.visualization.DataTable;
data.addColumn('date', 'spotDate'); //date column
data.addColumn('number', 'eur'); // column for Euro
data.addColumn('number', 'jpy'); // column for Japanese Yen
data.addColumn('number', 'cny'); // column for Chinese Renminbi
data.addColumn('number', 'oil'); //column for oil (bbl)
}

 

Looks good, right?  Will I go back and update all my old articles?  No.  Will I use this from now on to make my code samples more readable?  You bet.

Last Updated on Tuesday, 27 July 2010 11:58
 
Google Charts PDF Print E-mail
Written by Nathan McMinn   
Sunday, 25 July 2010 19:29

It's no secret that Google offers some great free tools for content publishers and developers.  Most bloggers I know use AdSense and Google AnalyticsGWT and the App Engine both have good adoption among web developers, and Google Code hosts a ton of other useful projects.  One of these projects is Google Charts.  Google Charts provides a palette of static and dynamic data visualization components that you can easily embed in your applications.  With just a few lines of JavaScript and HTML, you can add rich, interactive charts and diagrams to any web app.  To get started, make sure you include the Google JavaScript API in your page

 

<script type='text/javascript' src='http://www.google.com/jsapi'/>

 

I recently had a project come up that requires comparing the price of several currencies and commodities in USD.  The source of data for this chart is a MySQL database that contains one table populated with time series data.  Basically, it's a big list of currency and commodity prices by date.  An annotated time line is a great choice for displaying this type of data, and Google Charts delivers.  It only takes a few lines of JavaScript to create, populate and render a chart.  The first steps are to load the particular visualization that is required, and to set the callback method that will actually populate and draw the cart.

 

google.load('visualization', '1', {
'packages' : [ 'annotatedtimeline' ]
});
google.setOnLoadCallback(drawChart);

 

In this example the 'drawChart' function will create the underlying DataTable and draw the chart.  Populating any Google Chart is done using a DataTable.  A DataTable is basically just a wrapper for JavaScript arrays, which make up the underlying data stored in the table.  In this example, I'm creating a DataTable to hold EUR, JPY and CNY currency values, as well as the price of oil by the barrel.  Creating and defining a DataTable is simple:

 

function drawChart() {

    var data = new google.visualization.DataTable;
    data.addColumn('date', 'spotDate'); //date column
    data.addColumn('number', 'eur'); // column for Euro
    data.addColumn('number, 'jpy'); // column for Japanese Yen
    data.addColumn('number', 'cny'); // column for Chinese Renminbi
    data.addColumn('number', 'oil'); //column for oil (bbl)
}


Now that your DataTable is created and defined, it can be populated with data.  The Google Charts API expects this data as JavaScript arrays.  In the case of the annotated line chart, a two-dimensional array is expected.  Each row in the data table is an array of vars that match the types defined when you built the DataTable.  So, in the case above, each row should be a JavaScript array that looks something like this:

 

var chartData = [
[new Date(2010, 07, 24), 1.27, 87.60, 0.15, 79.60],
[new Date(2010, 07, 25), 1.25, 87.68, 0.15, 78.94]
]

 

If the data types of your array don't match what you have set in the DataTable, an error will be raised.  To generate this array, you have a ton of options.  You could create a public data source, or, you can use just about any tool of your choosing to spit out JSON data that can be de-serialized into the two dimensional array expected by the Charts API.  Since I am integrating this particular chart into an existing Liferay Portal environment, I wrote up a quick Java Servlet to deliver the required data.  Using the GSON library, serializing Java objects to JSON is a snap.  Using an ArrayList<Object> makes it simple to group together heterogeneous objects into a collection that can be properly serialized by GSON to the required JavaScript array.  In my case, I use jQuery to retrieve the JSON string from the server, but any method will do.  Call eval() with the serialized JSON string to convert it back to JavaScript objects.  Adding the array to the DataTable is just a function call.

 

function drawChart() {
...

    data.addRows(chartData);
}

 

Finally, once the data is retrieved and added to the DataTable, the table can be used to populate the chart.  A div must be created to hold the chart, and this div element must be passed in when the chart object is created.  One peculiarity of the Google Charts API:  you must explicitly set the width and height of the div that will hold the chart.

 

function drawChart() {
...

    var chart = new google.visualization.AnnotatedTimeLine(
        document.getElementById('chart_div'));
    chart.draw(data, {displayAnnotations : true});
}

 

The end result is a nicely rendered line graph, drawn in 'chart_div'.  This particular graph is rendered in Flash.  This is not the case for all Google Charts visualizations, some of which render as static images or pure HTML.  If you need quick, easy charts for your web application, it's probably worth your time to check out Google Charts.

 

In part 2 of this article, I will cover DataViews, annotations and how to tie it all up with jQuery.

Last Updated on Monday, 26 July 2010 08:50
 
iPad + Alfresco = Mobile Awesome PDF Print E-mail
Written by Nathan McMinn   
Friday, 09 July 2010 09:19

Unless you have been living in a cave, you have probably seen all the hype about the iPad.  It's a neat tablet, if a bit underwhelming from a technical perspective.  I, for one, would have liked to see a device based on the full OSX, not just the iOS.  I would have also liked to see the platform be a bit more open, not absolutely beholden to the iTunes store for app installation.

 

With that little complaint out of the way, it is still a great device for reading documents.  It's compact, has a beautiful screen, good battery life and supports most of the common doc formats in use at my company.  With the explosive growth of Alfresco for document management, it was a natural fit to try and get our stored documents over to the iPad platform.  At the last Alfresco event I attended, I met Dan Hopkins from Zia Consulting.  He was giving a demo of Zia's new iPhone/iPad application (also available on Android, BTW) that integrates with Alfresco.  Working via the CMIS interface, Fresh Docs connects to your Alfresco instance and allows you to browse spaces, search for documents and set favorites, as well as the obvious function of viewing Alfresco documents on the device.  Outstanding.  So far I have tested it with Alfresco Enterprise 3.1, 3.2 and 3.3, and it works perfectly across all three.  It is available for free on the App Store, just search for "Zia" or "Alfresco".

 

Zia's offering would be stellar even if they simply stopped with what I have already seen.  But, Zia went a step further.  They released the app as open source.  While this might not mean anything to your average iPhone/iPad user (since you can't build and install it yourself due to Apple's approach to iOS application installation), it does mean something to Apple Enterprise developers.  Enterprise developers are able to build and deploy applications directly to the device through iTunes.  This makes sense, as many enterprise developers are likely developing proprietary, domain-specific applications for in-house consumption.  These types of applications won't find an audience on the App Store, and are likely not the type of thing an enterprise would release to the general public anyway.

 

So, Enterprise developer account in hand, I went out and pulled down Zia's source code.  The project is called freshdocsalfrescoiphone and is hosted on Google Code.  The actual code is available via Subversion.  You'll need a Mac and XCode to build the project, which can be opened by clicking the Alfresco.xcodeproj file in the project directory.  Why would you want to build your own version instead of using the version on the App Store?  Well, several reasons.  In my case, we are building a version that carries our corporate branding (while still giving Zia their due credit on the "About" page) as well as our corporate server information plugged in as the configuration defaults.  Finally, we plan to extend the application.  The current plan calls for adding offline caching of documents, making content available even when a data connection is not.  Hopefully these functional changes will find their way back into the mainline source code.  Kudos to Zia for releasing a project that Apple Enterprise developers can use to get Alfresco + iPad integration up and running right away!  Thanks!

Last Updated on Friday, 09 July 2010 09:54
 
Liferay Portal - Log Levels for Third Party Portlets PDF Print E-mail
Written by Nathan McMinn   
Monday, 07 June 2010 10:26

If you are developing your own portlets for Liferay, you have surely noticed that your portlet log statements don't show up in the logs by default.  Or, like me, you may have moved a portlet from test to production only to have it fail.  When you are running with a debugger attached, it's a simple matter to set a breakpoint and see where things are going wrong.  On a production server, this isn't really an option.  You need detailed, fine-grained control over your log configuration.  Liferay can output logging as detailed as you want, class by class or package by package.  These can either be set using portal-log4j.xml, an extension file or (my preference), the server administration console.  Changes made via the administrative interface can be applied immediately, without a server restart, making it the best choice for troubleshooting in a live environment.

 

To get started, open the main portal menu and select "Control Panel".  At the bottom of the left side menu there is a "Server Administration" option which takes you to the following screen:

 

 

At the top of this page is a "Log Levels" option.  This tab allows the user to set the log level for various classes and packages.  Each "category" can consist of either a package name (at any level) or even a specific class.

 

 

To enable logging for a specific custom portlet, click the "Add Category" tab.

 

In the text box, enter the package name of your portlet class.  In this example I am using the package "com.um", which is the base package for the Alfresco Web Script Portlet.  This will turn on logging for any classes that reside in the package hierarchy beginning with "com.um", including the main portlet class com.um.portlets.alfresco.WebscriptPortlet and the proxy servlet class com.um.portlets.alfresco.servlets.ProxyServlet.  Next, select your log level.  These correspond with the log levels defined by Log4j.  Click "Save" to create the new category and apply the change.

 

 

Once the category is saved, it can be seen in the category list.  From this list you can adjust the log level.  When you are done debugging, go back in and set it to "Info" or another category.

 

More info on this topic can be found in the Liferay Wiki.

Last Updated on Monday, 07 June 2010 11:39
 
<< Start < Prev 1 2 3 4 5 6 7 8 9 10 Next > End >>

Page 7 of 12
RSS Feed Icon

About Me

 

My profile picture

 

My name is Nathan McMinn.  I'm a software engineer, beer geek, wannabe adventurer and genuinely curious guy.  Find me on Facebook, Linkedin or Twitter

Latest Comments