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 Software and Tech
Tech Stuff
Storing and Retrieving Images in MySQL PDF Print E-mail
Written by Nathan McMinn   
Tuesday, 10 January 2012 13:43

One of my ongoing projects is a rich client application written in Java.  A recent request from the users was the ability to add handwritten notes or drawings to some of their records.  It's simple enough to give the users a simple canvas on which they can draw and store that data as an image.  However, we want these notes to be available to the companion web application that runs on our server.  The clients synchronize their databases with the server fairly regularly using a database sync tool called Pervasync, so it should be possible to store the images as a BLOB in the MySQL database on the client and have them sent to the server when the client and server databases are synchronized.  As with any vendor claim, I wanted to test whether or not Pervasync could synchronize BLOB data properly.  

 

To test this, I needed to import a binary file of an image into a test client database, synchronize it to the server, export the BLOB to a file and make sure the image was intact.  After a little digging around, it turns out that the SQL to accomplish this is fairly simple.  I created a table called "image_test", with two fields.  The first is a simple numeric ID field, the second a MEDIUMBLOB.  Inserting an image from a file on disk is just this simple:

 

1
INSERT INTO image_test (id, image) VALUES (1, LOAD_FILE('c:/test/test.png'));

 

After running the data synchronization, I needed to get the BLOB data back out and into a file.  MySQL makes this easy.  The output from any query can be dumped to a file by using the INTO OUTFILE/DUMPFILE syntax in a select statement.  This is very handy for scheduled jobs that take data from a MySQL database and make it available to other systems.  For example:

 

1
SELECT * FROM table_name INTO OUTFILE 'c:/test/outfile.txt'

 

The SQL statement above will take all of the data in the table_name table and dump it out to a text file.  This statement can also take the same export_options parameters used while importing a file to set things such as the field and line delimiters.  But wait, aren't we dealing with binary data?  Wouldn't field and line delimiters just muck things up?  Yep, and that's why MySQL provides the DUMPFILE option instead.  Using INTO DUMPFILE instead of INTO OUTFILE, all of the returned data is dumped to a file as a single line.  This is just the ticket for fetching my image data and storing it in a local file for verification.  The SQL looks like this:

 

1
2
3
4
SELECT image 
INTO DUMPFILE 'C:/test/test2.png'
FROM image_test 
WHERE id = 1;

 

When I first tried to run this under the MySQL workbench it kept choking with an error code 1064, complaining about the syntax.  By default, the MySQL workbench inserts a LIMIT 0, 1000 statement into queries before they run.  This causes the statement above to fail.  To turn off the limit, go to the "edit" menu in MySQL workbench and select "preferences".  In the SQL Editor tab, uncheck the "limit rows" option and the query should run, outputting the BLOB data to a file.

 

Happy Coding!

 
Adding a User to an Alfresco Share Site via the Javascript API PDF Print E-mail
Written by Nathan McMinn   
Sunday, 14 August 2011 14:46

As much as I love working with Alfresco (and I do, really), there are some things about it that still make me scratch my head and say "huh?".  One of these things is the way Alfresco Share handles adding users to sites.  Typically, a site manager simply invites a user to a Share site via the invite mechanism.  95% of the time this is exactly how I want it to work.  Sometimes, however, I need to add a user directly without going through the invite process.  Strangely, Alfresco admin users cannot simply add users to an arbitrary site.  Under older versions of Alfresco (3.1), there was a simple workaround.  A user could be added directly to a site group, and thus the site, through the Alfresco Explorer admin interface.  In newer versions of Alfresco (3.3.3, in my case), this no longer works.  The site manager, collaborator, contributor and consumer groups no longer show up in the admin interface's group search.  Aaaaarrrrgh!!!

 

Thankfully, there is another way.  It takes a little more work.  I have written a few articles before about the Alfresco Javascript API, and we're going to dive into it again to accomplish the task at hand.  

 

So, let's get started!  To add a user directly to a Share site using the Javascript API, two things are required:

 

  1. Valid Alfresco user credentials.  The account needs to either have SiteManager access to the site to which the user will be added, or it need to be an admin account.
  2. A good REST client.  There are quite a few to choose from.  Depending on the task, I either use the WizTools.org RESTClient, or the Eclipse restclient-tool.  Either one will work just fine.

 

The first step is to fire up your REST client or a browser and get an Alfresco authentication ticket.  This is done via a simple HTTP GET operation.  Just hit the following URL:

 

http://<your_alfresco_host>/alfresco/service/api/login?u=username&pw=password

 

This will return an authentication ticket that can be appended to all of your future requests.  The exact response will look something like this:

 

1
<ticket>TICKET_ce2ffccb238802825af8ae7632160dd87aa234e7b</ticket>

 

The part of the ticket that should be appended to the URL is the content of the <ticket> element.  Make a note of the ticket, it will be required in a moment.  Now, fire up your REST client if you haven't already.  The client will be used to send a POST to the site membership web service.  This web service is used by Alfresco Share internally to (duh) add a user to a site with a specified role.  You can browse all of the available web scripts on your system at this URL:

 

http://<your_alfresco_host>/alfresco/service/index

 

The script we're looking for is in the package /org/alfresco/repository/site/membership, and is called the "Add Site Membership" script.  A full description of the script and its parameters can be found here:

 

http://<your_alfresco_host>

/alfresco/service/script/org/alfresco/repository/site/membership/memberships.post

 

The script itself is pretty simple.  Take a moment to read the description, go over the associated Javascript and get a feel for what it is going to do.  I'll wait.  Done?  Good.  If you look at the URL that will accept the POST, you'll see it has a pretty simple signature.  Only one part of the URL needs to be changed.  You'll need the short name of the site to which you want to add a user.  The short name is the "URL name" that you used when you created the site.  It's a part of every URL in the site.  For this example we'll assume I have created a site called My Test Site with a URL name (short name) of "mytestsite".  The URL specified by the script looks like this:

 

http://<your_alfresco_host>/alfresco/service/api/sites/{shortname}/memberships

 

Looking at the URL template above, it's pretty clear what to do.  Substitute the shortname of your site for {shortname}.  The last part of the URL is the Alfresco authentication ticket created earlier.  Simply append it as a URL parameter named "alf_ticket".  

 

http://<your_alfresco_host>/alfresco/service/api/sites/mytestsite/memberships?alf_ticket=TICKET_dc233f7e8212825ef8fa8f945762ee24df53bcd7b

 

When I first started working on this I tried to use the authentication built into my REST client, but Alfresco constantly complained about HTTP authentication.  Appending the ticket in this manner seems to work nicely with every web script I have tried.  The last step in this process is to create a JSON object that will go into the body of the POST request.  A quick look at the Javascript for the memberships script shows that it expects a JSON object that contains a role (SiteManager, SiteCollaborator, SiteContributor or SiteConsumer, corresponding to the Share site roles), and a person object with a username property.  Here's what such a request looks like:

 

JSON Body
1
2
3
4
5
6
7
{
"role":"SiteManager",
"person":
{
"userName" : "username"
}
}

 

Note that this isn't everything that Alfresco includes in a person object, but it's enough to get the job done in this case.  Once you have entered this JSON into the body of your POST request, there is one more task and we're ready to send the request.  Alfresco is expecting a certain content type for JSON requests.  A proper REST client will let you set any additional HTTP headers that the request requires.  Add a header called "Content-type" and set its value to "application/json".  Once the header is set and your request body is ready go ahead and send the request.  You should get back an HTTP OK response, with a body that contains another JSON object with a bit of detail about what was done.  For the request and test site in this example, the response should look something like this:

 

JSON Response
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"role" : "SiteManager",
 
"authority":
{
"authorityType" : "USER",
"fullName" : "User Name",
"userName" : "username",
"firstName" : "User",
"lastName" : "Name",
"url" : "\/alfresco\/service\/api\/people\/username"
},
"url" : "\/alfresco\/service\/api\/sites\/mytestsite\/memberships\/username"
 
}

 

It's entirely possible that there was an easier way to do this that I completely missed.  Even if there is, it never hurts to get more familiar with the Javascript API.  The Alfresco Javascript API is a powerful tool for Alfresco users.  It doesn't matter if you are a developer or admin, learning the Javascript API is essential.

 

Happy coding!

Last Updated on Tuesday, 16 August 2011 11:47
 
Groovy, RCP, JasperReports and Code Reuse PDF Print E-mail
Written by Nathan McMinn   
Monday, 04 July 2011 19:22

One of my many responsibilities at my day job is guiding the architecture of and helping to develop a fairly large Eclipse RCP application.  The RCP is a pretty good platform for a desktop Java app.  SWT keeps the look and feel mostly native, and you get a lot of freebies like a help system and update engine that would have to be developed if one were to build a Java application from scratch.  Recently I was getting frustrated with the reusability of the service layer of this application and started looking for a new way.  The service layer of this application is a set of POJOs that implement the business logic of the application, mostly importantly a complex set of calculations.  The idea here was that we could reuse the same objects in the web version, ensuring that the calculations were performed consistently across both the client application and the web application (which serve different audiences, but a very similar purpose). 

 

This approach worked well, but it did turn out to have some drawbacks.  The service objects had dependencies that make it difficult to work with our reports (based on JasperReports).  The result is that the reports end up with their own code for handling the calculations, either in the field expression or in the report query itself.  This doubles the amount of work we have to do when a calculation is altered.  The service layer objects themselves are compiled and are part of the RCP plugin, meaning that an update to the calculation logic required an update to the plugins.  The update process, while very powerful and useful, can be cumbersome to the user community.  I don't like forcing a big update on the community any more often than I have to.  Finally, we want to have our analysts (who define the calculations) more involved in the development and maintenance of the service layer.  These folks are bright, but they aren't coders.  Java's syntax is a bit too verbose and obtuse for them to work with directly.

 

So, there are few problems to solve.  How can I build a service layer for this RCP app that can easily be reused in both a set of web services and a web application, and can also be easily called from JasperReports?  How can I deploy this layer in such a way that I don't have to push out a bulky RCP feature update every time an analyst wants to change a calculation?  How can I bake-in unit testing?  How can I get my analysts more involved in maintaining the calculations and double-checking them for correctness?

 

Groovy!

 

Groovy neatly fits all of my requirements.  It runs on the JVM, so it should play nicely alongside both the RCP and our existing web environment.  Groovy also can be used to develop scriptlets for JasperReports (with a little work).  It's a simple matter to have the RCP application download the latest scripts from the server when it has a chance, and the scripts are tiny making this a very quick operation and much less disruptive to the users (we do it via an embedded Subversion client).  Finally, Groovy's syntax is simple and clean enough that the analysts will be able to at least read it, if not write it.  As an added bonus, Groovy is also very well suited to writing a DSL (Domain Specific Language).  While this isn't planned for the first go, this capability could be handy in the future if we decide to define a DSL for this app.

 

Enough about the "why", time for the "how".  Let's look at some code!  The simplest way to embed Groovy in an existing Java application of any sort is by using the GroovyScriptEngine.  This class handles finding, loading, compiling and running a Groovy script.  Almost all of the complexity is hidden from the developer.  It's a simple as giving the script engine one or more paths to search, binding some variables (if you need them) and telling it which script to run.

 

Let's create a simplified example in which we take the unit price for an item and the quantity, using these values to calculate an extended price.  For this example we'll assume a working directory of /home/groovytest/scripts.  Here's what the Groovy script might look like:

 

ExtendedPrice.groovy
1
2
3
4
5
6
7
8
def ep = new ExtendedPriceService();
extended_price = ep.calcExtended(unit_price, qty);
 
class ExtendedPriceService {
	double calcExtended(double unit_price, int qty) {
		return unit_price * qty;
	}
}

 

Pretty simple stuff.  We're creating a new extended_price variable and assigning it the value of unit_price multiplied by quantity.  You might be asking yourself, why define the calculation in a class and not just do it in the script and return the result?  We'll get to that later.  Now, here's how we might call that script from the Java application:

 

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
import groovy.lang.Binding;
import groovy.util.GroovyScriptEngine;
 
public class ScriptEngineTest {
 
  public static void main(String args[]) {
    try {
      //set the paths the script engine will use to find the script
      String[] paths = new String[] {"/home/groovytest/scripts"};
      GroovyScriptEngine engine = new GroovyScriptEngine(paths);
 
      //create a Binding object to hold the variables
      Binding binding = new Binding();
      binding.setVariable("unit_price", 3.50);
      binding.setVariable("qty", 10);
 
      //execute the script
      engine.run("ExtendedPrice.groovy", binding);
 
      //print the returned result
      System.out.println("Ext Price: " + binding.getVariable("extended_price"));
    catch(Exception ex) {
      System.out.println("Exception: " + ex);
    }
  }
}

 

Looking at the code, it should be pretty clear what is happening here.  First, we're setting up an array of Strings that lists all the paths in which scripts are located.  Next, we instantiate the script engine and give it the list.  Once the script engine is ready, we create a Binding object to hold the variables that we will pass to the script as arguments and give us access to variables in the script itself.  Finally, we run the script and get the results back from the Binding object.  Simple, simple, simple, and this approach works for both the RCP application and our J2EE web app.  Of course our actual calculations are much more complex, but conceptually it's the same thing.

 

It's worth noting that you can pass ANY Java object to your Groovy script using the Binding object.  Using Hibernate?  Just pass in your mapped objects.  Alternately, you can pass in the db connection details and use Groovy's built in database features to pull whatever data you need.

 

So we've seen how Groovy can be used to externalize calculations (or any other logic, really) from an RCP application.  Now what about that promise of reuse?  Now that I've gone through all the effort of embedding Groovy and externalizing my calculations into Groovy scripts, how can I reuse these, say, in a web service?  There are a couple of options.  Probably the simplest way to reuse the scripts as a service is to use the GroovyWS module to expose the script as a WS-I compliant service.  How easy is this?  Surprisingly easy.

 

1
2
3
4
5
6
7
8
9
10
import groovyx.net.ws.WSServer
 
//define a new WSServer
def server = new WSServer()
 
//set a server node to point to the extended price class created earlier
server.setNode("ExtendedPriceService", "http://localhost:80/ExtendedPriceService")
 
//crank up the server!
server.start()

 

Earlier, when we defined the ExtendedPrice class, it would have been visibly simpler to just create a script that took the two variables and returned a calculated value.  The reason that we put the calculation in a class is so that we could reference it here and easily expose its methods as a service.  It is also pretty simple to take the class defined in ExtendedPrice and use it in a server framework like Grails.  It's nice to have options, right?

 

Now, what about JasperReports?  The whole point of this exercise is to build a single set of scripts that encapsulate my complex calculations and make them available to all of the parts of this application including the RCP app, web app / services and reporting.  This part is a bit trickier.  While JasperReports supports Groovy as an expression language (which greatly simplifies report development, IMHO), there is no direct support for scriptlets written in Groovy.  However, all is not lost.  It just takes a little extra work.  Since Groovy can be compiled to a regular old Java class (via groovyc), there's nothing stopping you from writing your scriptlets in Groovy, compiling them and using them in JasperReports.  Or, write the scriptlets in Java and call the calculation scripts via the GroovyScriptEngine.  Either way works.  It's not a perfect solution, but it's pretty simple to whip up an Ant script to compile the Groovy scriptlet wrappers and jar 'em up.  I'll have another article coming soon that details exactly how this works with an extended JRDefaultScriptlet that works nicely with Groovy.

 

Now that the service script can be used in the RCP and web apps, as a web service, and in the reporting engine, there's just one last piece of the puzzle.  Unit testing.  Again, Groovy makes this very simple.  JUnit is baked into the Groovy runtime.  It's simply a matter of creating a class that extends GroovyTestCase.  Here's a simple example that tests the calcExtended method of the ExtendedPriceService class that contains the calculation used throughout this article:

 

ExtendedPriceTest.groovy
1
2
3
4
5
6
7
8
9
10
//define the test case
class ExtendedPriceTest extends GroovyTestCase {
 
	//test the extended price calculation
	void testExtendedPrice() {
		//create an instance of the extended price service
		def ep = new ExtendedPriceService();
		assert 350 == ep.calcExtended(3.5, 100);
	}
}

 

That's all there is to it.  Classes that extend GroovyTestCase can either be run directly from the command line, or they can be compiled and run like any other JUnit test case.

 

Groovy is a relative newcomer (version 1.0 came out in 2007), but it's already finding a place in my toolbox.  Java has its fair share of detractors, but languages like Groovy help make it fun again and can give some significant gains in productivity when applied properly.

Last Updated on Tuesday, 05 July 2011 13:21
 
Alfresco - How to Find All Content Created by a User PDF Print E-mail
Written by Nathan McMinn   
Friday, 10 June 2011 09:55

I was recently approached with a request to find all the content that has been created by a particular user in our Alfresco repository.  At first this seemed like a simple request, surely there is a way to view the user account through the Explorer or Share interface and see everything they have created.  Not so, unfortunately.  The Share interface will show you content created recently, but only goes back a short amount of time.  The Explorer interface will allow an admin to see how much disk a user has consumed, but not all of their individual pieces of content.  So, how do we find what we're looking for?

 

The answer lies in Alfresco's robust search capabilities.  Everything in Alfresco is a node, and you can search on any property of those nodes if you know the document model and the search syntax.  To further complicate things Alfresco offers several search options, each with its own pros/cons and syntax.  Perhaps the most powerful and useful of these is the Lucene search.  There are a few ways to execute a Lucene search in Alfresco.  In this case I chose to use the Alfresco Node Browser.  This console can be accessed at the following URL on your Alfresco installation:

 

https://<your_server_name>/alfresco/faces/jsp/admin/node-browser.jsp

 

Once you have signed in and can see the node browser, one of the first things to take note of is the "Search" section at the top of the page.  The drop down menu provided allows you to specify the type of search desired.  For this example, select "Lucene".  Lucene has its own search syntax, some of which is documented in the Alfresco Wiki.    There is also an excellent presentation up on SlideShare that details the various Alfresco search options and has some great examples of how to search for Node aspects, properties, etc using Lucene.

 

OK, so I know I want to use Lucene to search my repository, I know what property I am looking for (creator), I know what value I need that property to have (the user's login) and I have the Node Browser page loaded.  What's the exact string to search for?  In Lucene, the syntax for searching for nodes that have a certain property value is simple.

 

1
@<property_qname>\:"property_value"

 

So, back to my original request.  I need all the documents created by user "John Q. Public", who has the login of "johnqpublic".  

 

1
@<creator>\:"johnqpublic"

 

Pretty simple, right?  This same syntax can be applied to search for nodes with any property value in the Alfresco Repository.  

Last Updated on Friday, 10 June 2011 12:17
 
Need a Resume Boost? Get Involved with an Open Source Project - Part 1 PDF Print E-mail
Written by Nathan McMinn   
Friday, 25 February 2011 20:52

There are a lot of excellent reasons to get involved with an open source project.  You can learn a new language, improve your existing skills, be challenged by a community that is at the top of their field or even get better at managing complex distributed projects.  There are also dozens of ways to participate.  Open up a project's bug tracker and find an issue that needs to be fixed.  Write a useful new extension or plugin.  Even if you don't code, just about every open source project out there could use more testing, more documentation and tutorials and help handling the load on their support forums and mailing lists. If you are a heavy user of open source software it feels great to give something back to the community that has contributed so much.

 

One of the most overlooked reasons to get involved with an open source project is career advancement.  Developers, project managers, testers and technical writers are judged on their skills, and what better way to show off what you can do than to do it in public!  I've always suspected that this is the case, but had no way to really quantify what open source participation means to potential job seekers.  So, I set out to find out.  This is the first of a series of articles about how employers, recruiters and other developers view open source contribution, how to get the most out of your work and how to couch it on your resume.

 

If you are in a technology field, you probably hear from recruiters fairly regularly.  It seems to be one of the more common ways for tech folk to find a new gig.  This includes both corporate recruiters that work for a specific company and freelance recruiters that find candidates for a number of different clients.  To find out how these professionals view open source experience I turned the tables on them a little bit.  Over the last several months whenever a recruiter contacted me about a position I replied with a counter-proposal:  I love my job and don't want to leave, but I'd like to interview you instead.  Almost all of them were good sports and over a few months I was able to collect some interesting (if anecdotal) information about how open source is used at their client companies, how they view open source experience and even a little bit about how open source projects can be fertile hunting grounds for recruiters.

 

What I found was mostly expected, but there were some surprises.  Recruiters and their clients have a universally positive view of those that participate in open source projects at all levels.  One corporate recruiter at a firm in Pennsylvania went so far as to say "I think people who are active in the open source community are rock stars.  The average employee works 8 hours a day, the rock stars continue to do it after hours not because they have to but because they want to.  I don't think there is an employer in the world that would look at that as anything but a positive.".  While I myself am not a big fan of the "Rock Star" analogy, the point is well taken.  People that code, document, test and otherwise contribute outside of what is required for their career demonstrate a passion for the job that employers find very attractive.

 

Companies that make use of open source technologies naturally gravitate toward people that are active in the ecosystem around those technologies.  For example, if a company is looking for a good Drupal developer, it would be perfectly natural to scour the Drupal support forums, module contributors and even commit logs for active, competent candidates.  Is this poaching?  Maybe, but that is part of a recruiter's job.  As open source software continues to weave itself into the fabric of IT organizations large and small, this trend will only continue.  Recruiters know where to find people with experience in the technologies that they need, and those that are active in their project communities will have an edge when it comes to finding employment.

 

On a slightly more cautionary note, don't think that casual open-source participation is equivalent to work experience.  Based on my interviews it isn't viewed as such, except in some rare cases.  If you are a core contributor to the Linux Kernel, for example, you can certainly claim equivalence.  If you release a few bug fixes and write a plugin or two?  Not so much.  Employment means a lot more than your technical work.  It means getting along with colleagues and working on a team.  It means building what the customer needs or wants, not writing code that scratches your particular itch as is so often the case in the open source world.  Writing code to satisfy yourself is awesome, but it isn't the same thing as writing it to a customer's specification.  Also be very careful to stay positive and professional on project forums and mailing lists.  The content posted to these forums is basically around forever and you have no control over the content retention, so make sure to put your best foot forward.  You wouldn't want to have a potential employer Google your name and find a bunch of petty fighting and name calling.

 

In part 2 of this series, I set out to interview a much more elusive group:  The CIO.

Last Updated on Tuesday, 08 March 2011 08:56
 
<< Start < Prev 1 2 3 4 5 6 7 8 9 10 Next > End >>

Page 1 of 10
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