techbits.de » development http://www.techbits.de thoughts on hardware, software, development and tech news Mon, 01 Apr 2013 05:39:07 +0000 en hourly 1 http://wordpress.org/?v=3.2.1 Introducing the User Script Console http://www.techbits.de/2013/04/01/introducing-the-user-script-console/ http://www.techbits.de/2013/04/01/introducing-the-user-script-console/#comments Mon, 01 Apr 2013 03:01:15 +0000 Florian http://www.techbits.de/?p=434 Continue reading ]]> The Alfresco JavaScript Console is really popular among Alfresco administrators and developers to easy automate tasks around Alfresco. This leads to more and more requests from users to have their problems fixed and tasks automated and keeps developers and administrators from more important tasks.

With the new User Script Console extension for Alfresco Share the users finally can access the powerful JavaScript API directly by themselves without needing a specialist. It integrates as a page in a Share site:

Of cause it can not be expected of end users to know JavaScript or the Alfresco APIs right away. That is why the User Script Console slowly introduces the users to the capabilities of the API using a Gamification approach. Users start out as novices and can gain experience (XP) while using the JavaScript API.

User “Experience”

API access gradually changes with increased experience:

  • 0 XP = No Alfresco API access
  • 10 XP = Read properties and permissions, only document root object
  • 1000 XP = Add comments, add Tags to any node
  • 5000 XP = Write properties and add tags, Site API, full ScriptNode api
  • 10000 XP = Groups API (Add/Remove people from sites)
  • 20000 XP = Full Alfresco Javascript API
  • 50000 XP = runas admin, access beans using Packages.java

A new user starting out as a novice must first write a syntactically correct JavaScript using given examples. He receives 1 XP for each successful transaction and will soon gain access to some parts of the Alfreco API (XP of 10 or more). Commands above his experience level are not available:

Examples

To help users find their way around, there are examples in the “Examples” menu that are adjusted to the users experience level. It starts out with a list of simple JavaScript examples for “for”-loops and “if”-clauses.

Badges

Additionally users can earn badges for special achievements (each earns 500 XP):

  • Unlocker: Unlocked more than 10 documents that were locked by the Sharepoint API.
  • Tagmaster: Added 100 different tags to documents
  • Ninja: more than 10 “hidden” property changes with behaviourfilter.disableBehaviour()
  • Shapeshifter: More than 100 calls of the transformDocument/transformImage
  • JsGuru: Run 10 consecutive scripts that all JsLint without any warnings
  • Loadtester: Your last 10 scripts have all run longer than 30s
  • MrClean: Purge the archive store (nodeArchiveService)
  • Reporter: Generation of more than 10000 lines of print output
  • Bouncer: Removed at least 100 people from groups/sites
  • Hacker: Usage of Packages.java to access Spring beans directly

The new User Script Console will help to empower the savvy user to automate Alfresco in an unprecedented way and lets administrators focus on more important tasks like backup and restore of the Alfresco repository.

Available today for Alfresco 4.1.

]]>
http://www.techbits.de/2013/04/01/introducing-the-user-script-console/feed/ 4
Using the tag editor component in Alfresco 4.0 http://www.techbits.de/2011/11/05/using-the-tag-editor-component-in-alfresco-4-0/ http://www.techbits.de/2011/11/05/using-the-tag-editor-component-in-alfresco-4-0/#comments Sat, 05 Nov 2011 11:42:03 +0000 Florian http://www.techbits.de/?p=349 Continue reading ]]> This is just a short post to note down what I found out about the Insitu tag editor component from Alfresco 4.0 and how to use it in your own code. I have not actually used it yet, so the code below is not complete nor working. It is just meant as a reference (for me).

You need to include the documentlibary.css the editors CSS:

<@link rel="stylesheet" type="text/css" href="${page.url.context}/res/components/documentlibrary/documentlist.css " />

Then you need a DIV to create the editor:

<div id="${el}-tageditor"></div>

You can create a Insitu-Editor for tags from Javascript like this:

var tageditor = Alfresco.util.createInsituEditor(this.id + "-tageditor",
{
	type: "tagEditor",
	nodeRef : "workspace://SpacesStore/79cced9b-947b-4833-bf03-5fb4660449d9",  // use nodeRef here
	name: "prop_cm_taggable",
	value: "", // here go the tags of the current node
	validations: [{
		type: Alfresco.forms.validation.nodeName,
		when: "keyup",
		message: this.msg("validation-hint.nodeName")
	}],
	title: this.msg("tip.insitu-tag"),
	errorMessage: this.msg("message.insitu-edit.tag.failure")
},
{
	 fn: this._insituCallback,  // your callback
	 scope: this,
	 obj: record // your object
});

To display the editor you call:

tageditor.doShow();

This displays the following tag editor you know from the document library:

What it does:

  • Provide a textbox, a save and a cancel button (as text)
  • Suggest and auto complete tags as you enter them
  • Create new tags in the repository on save
  • Save the tags for the node (using the nodeRef you specified)
  • Call your code after the update in the repo

What it does not do:

  • It does not read the current tags. You have to pass them in using the value parameter.

 

 

]]>
http://www.techbits.de/2011/11/05/using-the-tag-editor-component-in-alfresco-4-0/feed/ 0
Adding a like button to your Alfresco extensions http://www.techbits.de/2011/10/14/adding-a-like-button-to-your-alfresco-extensions/ http://www.techbits.de/2011/10/14/adding-a-like-button-to-your-alfresco-extensions/#comments Fri, 14 Oct 2011 09:30:05 +0000 Florian http://www.techbits.de/?p=267 Continue reading ]]> Alfresco 4.0 introduces social features into the Share client – the most prominent being the Like button. I’d like to give you a short tutorial on how to add the new Like button to your own Alfresco 4.0 Share extensions.

Webscripts Backend

Let’s start with the backend. I am assuming you already have a repository webscript set up that is returning a list of nodes or a single node to the Share client as JSON objects. Now you’d like to add a like button to your client for each document.

In the repository javascript tier you have the ratingService at your disposal. The wiki documentation doesn’t include this service yet, so I did some digging. This is how you would determine if the current user has liked the document and the number of total likes the document has:

isLiked = ratingService.getRating(node, "likesRatingScheme") !== -1;
totalLikes = ratingService.getRatingsCount(node, "likesRatingScheme");

To make it even easier you can import a utility function from the document library that does this

<import resource="classpath:/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/parse-args.lib.js">

and then use the Common.getLikes() function to retrieve the information:

nodes.push({
  "name" : n.name,
  "title" : n.properties["cm:title"],
  "description" : n.properties["cm:description"],
  "nodeRef" : "" + n.nodeRef,
  "likes" : Common.getLikes(n)
});

With this small change (and possibly a change to the webscript’s freemarker template) you have a JSON result from your webscript that returns the like information and looks similar to this: 

{
  "name" : "document.txt",
  "title" : "A test document",
  "description" : "",
  "nodeRef : "workspace://SpacesStore/...",
  "likes" : {
    "isLiked": true,
    "totalLikes": 5
  }
}

Share frontend

Now that we have our webscript returning the like information we need to add the like button to the Share frontend code. Here I assume you have some kind of YUI code already in place which we can extend. The share.js (webapps/share/js/share.js) utility script contains a Like Button component that we can easily use.

First we need to add an empty DIV to our components freemarker template.

<div id="${el}-like"></div>

Then we can add the Like component in the client javascript:

new Alfresco.Like(this.id + '-like').setOptions({
     siteId: this.options.siteId, 
     nodeRef: item.nodeRef,
     displayName: item.name
}).display(item.likes.isLiked, item.likes.totalLikes);

This is all you need to display the Like button.

  • You only have to set the initial values using the display() function. When the user clicks the Like button the totalLikes value is automatically increased by one.
  • This works for documents (for folders you need to set the type=”folder” option).
  • You could leave out the siteId if your component is not site specific. It is used to post the like event to the site’s activity stream.

The only problem I had with this component is that it does not provide a callback or an event when the like status is updated. It posts the like status the the repository, changes it’s display state but since it doesn’t provide feedback you can not update the state of your data model (the item variable) accordingly. This means whenever you redraw or create the Alfresco.Like component you have to make sure you read the most current state of the node from the repository webscript.

All in all adding the like button is pretty painless and I hope you find it as easy to add to your Alfresco extensions.

]]>
http://www.techbits.de/2011/10/14/adding-a-like-button-to-your-alfresco-extensions/feed/ 2
Recursive file iteration in Java http://www.techbits.de/2010/02/11/recursive-file-iteration-in-java/ http://www.techbits.de/2010/02/11/recursive-file-iteration-in-java/#comments Thu, 11 Feb 2010 21:15:48 +0000 Florian http://www.techbits.de/?p=198 Continue reading ]]> In a java frameworks talk I gave recently I showed the following example for finding files recursively…

public void listFilesInDirectory(File dir) {
  File[] files = dir.listFiles();
    if (files != null) {
      for (File f : files) {
         if (f.isDirectory()) {
	    listFilesInDirectory(f);
	 }
	 else {
	    System.out.println(f.getName());
	}
     }
  }
}

… which in real projects often grows to a larger block of code. The web is full of code blocks like this for walking a directory tree. The best version I came across is this object oriented one by Torsten Curdt. Since you usually don’t want to write this yourself, I suggested in my talk to use FileUtils which makes recursive iteration much easier:

Collection jspFiles = FileUtils.listFiles(rootDirName,
                        new String[] { "jsp" }, true);

This looks concise and useful but as I tried to use it, I wasn’t too pleased with the FileUtils’ solution. Here is why:

  • The recursion is processed in one go, i.e. all results are written to a List even when using the iterateFiles method. The recursion is not processed iteratively.
  • You can not influence the directories that are searched.
  • Only files are returned, you can not search for directories.
  • The API is not very expressive (e.g. what does the “true” mean).
  • No generics (raw collection types are returned).

A Better API

Not being satisfied with the solutions I found, I “dreamed up” my own API for listing and finding files. I don’t consider it complete but for the most part I am pleased with the ease of use that the builder pattern provides. The code for this can currently be found in an unrelated goole code project. The rest of this article shows the functions that are currently supported.

Find files two ways

There are generally two ways to use the result – as interator or as list:

1. Iterate over all files in the windows directory:

for (File f : Files.find("c:\\windows")) {

}

2. Get all the files in a directory as a list of files:

List<File> allFiles = Files.find(somedir).list();

Except from the return type the second version does the same as the JDK command listFiles:

File[]  allFiles = (new File(somedir)).listFiles()

Easy recursive listing

To iterate all the files in the C:\Windows directory, you would use:

for (File f : Files.find("c:\\windows").recursive()) {

}

Note: This actually works iteratively, i.e. the recursion happens as you fetch files from the iterator. The result is not fetched into a huge list.

With a Predicate you can limit the recursion to specific directories. In this example all .svn directories within a source tree are skipped:

Predicate<File> noSvnDirs = new Predicate<File>() {
boolean apply(File file) {
return !file.getName().equals(".svn");
}
}
for (File f : Files.find("src/java/").recursive(noSvnDir)) {

}

Want Files, Directories or both?

Define if you want only files, only directories or both in your result with yield*()-Methods.

Files.find(someBaseDir).recursive().yieldFiles()  // this is the default
Files.find(someBaseDir).recursive().yieldDirectories()
Files.find(someBaseDir).recursive().yieldFilesAndDirectories()

Filtering the results

To get all textfiles within a dir use:

Files.find(dir).withExtension("txt").list();
Files.find(dir).ignoreCase().withExtension("txt").list();

You can also filter by Name, e.g. to find README files:

Files.find(dir).withName("README").list();
Files.find(dir).ignoreCase().withName("readme").list();

Note that the default matching is case sensitive. The commands caseSensitive() and ignoreCase() can be used to toggle the matching behaviour.

For special needs you can also specify a Predicate<File> to filter the resulting files.

Files.find(dir).recursive().withFilter(somePredicate).list();

Finding Directories

When looking for directories there are some special usecases that are supported, e.g. looking for directories that contain a specific file:

Files.find(dir).recursive().yieldDirectories()
               .containingFile("Thumbs.db");
]]>
http://www.techbits.de/2010/02/11/recursive-file-iteration-in-java/feed/ 15
Android exploration continued http://www.techbits.de/2010/01/04/android-exploration-continued/ http://www.techbits.de/2010/01/04/android-exploration-continued/#comments Mon, 04 Jan 2010 12:01:13 +0000 Florian http://www.techbits.de/?p=192 Continue reading ]]> I extended my android application with a preferences screen now, which is quite easy to do.

  • A tutorial for creating a Preferences Activity got me started – unfortunaltely the xml preferences definition it uses is incorrect. The tags are names of Classes which have to be capitalized.
  • The open the preferences activity I added a Option Menu.
  • I wanted to add some kind of progress indicator. I ended up using the ProgressDialog and the AsyncTask to run the downloading and xml parsing in the background. To fix issues with device rotation I might have a look at the BetterAsyncTask in the Droid-FU library later.
  • I also ran into DateFormat and Date issues with the UTC formated Date in the XML file. I Thought about using  joda-time at least twice but then stuck to the JDK implementation for smaller app size. The fact that android brings it’s own class named DateFormat which just provides a localized JDK-DateFormat object doesn’t help either.
]]>
http://www.techbits.de/2010/01/04/android-exploration-continued/feed/ 0
First Steps with Android http://www.techbits.de/2009/12/30/first-steps-with-android/ http://www.techbits.de/2009/12/30/first-steps-with-android/#comments Wed, 30 Dec 2009 10:02:54 +0000 Florian http://www.techbits.de/?p=189 Continue reading ]]> In the last few days I started out with some android development. Here are some things learned so far developing my first app:

  • The Android Tutorials are a great starting point, though i only followed through with the HelloWorld Tutorial. In retrospect I should have looked at the Notepad Tutorial a little closer because it explains important concepts (namely activities/intents).
  • http://www.anddev.org/ is a useful source for tutorials and code snippets
  • It’s still java but a completely different API, so you often have to look for classes and methods via code completion oder in examples to get things done.
  • Downloading: Can be done with the included HTTP Client library. Unfortuantely Android still uses an old version of the HTTP Client though, which made it hard to find documentation (e.g. how to set authentication credentials). Additionally you shoudn’t forget to declare the INTERNET-permissions in your application manifest.
  • Storing and retrieving Files looks fairly easy (getDir(), getCacheDir()-Methods are there) at first sight but you have to unerstand the Android filesystem security model if you don’t want to spend hours with debugging. The before mentoined methods use internal storage where each application stores it’s data independently. Public read/write (e.g. file exchange with other applications) is only possible when you store your content with the specific method openFileOutput(). The external SD card on the other hand can be openly accessed with the regular Java File API.
  • XML Parsing: I started out with the sax parser but since my XML file was pretty complex I ditched it and downloaded dom4j which has a really easy to use API. Unfortunately it adds at least 200KB of final app size. I now realized I could have gone with the regular DOM parser which has a decent API. I’ll have to reevaluate this later – maybe the end user responsiveness does require the faster streaming parser approach (sax).
  • UI design: Declarative XML based looks powerful and well thought out but I mostly stuck to tutorial layout for now. This is an area I still have to get into.

Ok, that’s it for now. Android is turning out to be a great plattform – exciting times.

]]>
http://www.techbits.de/2009/12/30/first-steps-with-android/feed/ 1
Adding Googles GData Java API to your maven repository http://www.techbits.de/2009/08/06/adding-googles-gdata-java-api-to-your-maven-repository/ http://www.techbits.de/2009/08/06/adding-googles-gdata-java-api-to-your-maven-repository/#comments Thu, 06 Aug 2009 17:09:34 +0000 Florian http://www.techbits.de/?p=181 Continue reading ]]> The google gdata apis do not come with maven POM-files. Someone went through the trouble to “mavenize” the source but it is limited to linux as build plattform and currently out of date (compile errors). So I installed the JARs from the binary distribution of the APIs into my local repository – which are of course missing the dependencies between the individual JAR files. Here are two batch files which I used to install the JARs quite painlessly:

install.bat:

@SET mvn=d:\java\maven\bin\mvn
@%mvn% install:install-file -DgroupId=com.google.gdata
       -DartifactId=%1 -Dversion=%2 -Dfile=%3 -Dpackaging=jar
       -DgeneratePom=true

installall.bat:

call install.bat gdata-analytics 2.0 gdata-analytics-2.0.jar
call install.bat gdata-appsforyourdomain 1.0 gdata-appsforyourdomain-1.0.jar
call install.bat gdata-base 1.0 gdata-base-1.0.jar
call install.bat gdata-blogger 2.0 gdata-blogger-2.0.jar
call install.bat gdata-books 1.0 gdata-books-1.0.jar
call install.bat gdata-calendar 1.0 gdata-calendar-2.0.jar
call install.bat gdata-client 1.0 gdata-client-1.0.jar
call install.bat gdata-codesearch 2.0 gdata-codesearch-2.0.jar
call install.bat gdata-contacts 3.0 gdata-contacts-3.0.jar
call install.bat gdata-core 1.0 gdata-core-1.0.jar
call install.bat gdata-docs 2.0 gdata-docs-2.0.jar
call install.bat gdata-finance 2.0 gdata-finance-2.0.jar
call install.bat gdata-health 2.0 gdata-health-2.0.jar
call install.bat gdata-maps 2.0 gdata-maps-2.0.jar
call install.bat gdata-media 1.0 gdata-media-1.0.jar
call install.bat gdata-photos 2.0 gdata-photos-2.0.jar
call install.bat gdata-spreadsheet 3.0 gdata-spreadsheet-3.0.jar
call install.bat gdata-webmastertools 2.0 gdata-webmastertools-2.0.jar
call install.bat gdata-youtube 2.0 gdata-youtube-2.0.jar

You surely could get fancy and automate the splitting between artifact-name and version number, but hey, I needed those JARs installed quickly and that’s what it does.

]]>
http://www.techbits.de/2009/08/06/adding-googles-gdata-java-api-to-your-maven-repository/feed/ 9
IndexedList: A hybrid of a Java List and a Map http://www.techbits.de/2009/07/18/indexedlist-a-hybrid-of-a-java-list-and-a-map/ http://www.techbits.de/2009/07/18/indexedlist-a-hybrid-of-a-java-list-and-a-map/#comments Sat, 18 Jul 2009 11:00:09 +0000 Florian http://www.techbits.de/?p=164 Continue reading ]]> If been working on legacy data import code in the last months with a lot of code searching for exisiting objects in lists. I realized I needed a different collection to speed up searching for identifiers and couldn’t find any standard collection that matches my needs. I basically need an index like Maps.uniqueIndex() from the Google Collections Library provides but it should be updating dynamically and not only be generated once.

To summarize my requirements:

  • A List (ArrayList) which can be modified as usual
  • A way to find objects (contains and get) in constant time by a custom attribute (like a HashMap)
  • No reliance on equals() and hashcode() because they cover more attributes (an can not be changed)

The LinkedHashMap seems to almost fit the bill but it is not a true List and therefore not a great drop in replacement.

What I’m using right now is a wrapper around a List which maintains an additional HashMap to find objects by the index criterium. The index is automatically updated whenever the list is modified. This is an example on how I use it:

// function to index Persons by their social security number
Function<Person, String> getSsnrForPerson = new Function<Person, String>() {
  String apply(Person person) {
    return person.getSocialSecurityNumber();
  }
}

To create an indexed list for an empty ArrayList<Person> with an index on a person’s social security number you can then easily use the Class UniqueIndexedList:

UnqiueIndexedList<Person, String> myList =
  UnqiueIndexedList.create(getSsnrForPerson);

Of course all the usual methods of the List<Person> interface can be used as usual:

myList.add(somePerson);
myList.add(anotherPerson);
myList.get(i);
myList.iterator();

Additionaly there are  methods to access objects by index:

boolean personIsInList = myList.containsByIndex("34897634853");
Person p = myList.getByIndex("34897634853");

The code for the list implementation currently resides here:

It is basically a hybrid of a List and a special index-Map and works well so far. I am sure that finding objects in list for a given attribute is a very common usecase. Why hasn’t anyone solved this yet? Are there (better) alternatives that I’ve missed?

]]>
http://www.techbits.de/2009/07/18/indexedlist-a-hybrid-of-a-java-list-and-a-map/feed/ 0
Back with SQL Script Creator… almost http://www.techbits.de/2006/06/18/back-with-sql-script-creator-almost/ http://www.techbits.de/2006/06/18/back-with-sql-script-creator-almost/#comments Sun, 18 Jun 2006 12:47:26 +0000 Florian http://www.techbits.de/2006/06/18/back-with-sql-script-creator-almost/ Continue reading ]]> SQL Script Creator Splash Screen

Being annoyed by creating a cursor script in SQL and having to define tons of variables manually I wondered if there was any tool to aid in this process. I quick google did not yield promising results. So spend the weekend conjuring up an application that eases the script creation by providing specialized generators to create scripts automatically from a given SELECT statement. It works pretty well and will be tested further in the next week until I’ll release it here under some opensource license.

SQL Script Creator Screenshot

Putting this app together thought me some new things about the settings and localization concepts of .NET 2.0. Two articles that got me introduced to the concept are the tutorial Localization in ASP .NET 2.0 on ondotnet.com and the detailed article
Localization Practices for .NET 2.0 on theserverside.net.

]]>
http://www.techbits.de/2006/06/18/back-with-sql-script-creator-almost/feed/ 0