Forum OpenACS Q&A: How to integrate an existing application package with dotLRN

<h3>How to integrate an existing package in dotLRN</h3>

Since a lot of magic involved there is to integrate a package with dotLRN, a mystical path
a Jedi has to go and trust he must show at every time to overcome the temptations of the dark side (Yoda).

<h4>Use Case</h4>

You have created a package called foo that does something nice in OpenACS
and want to integrate this package in dotLRN. You can learn more about how to create an application
package here.

<h4>The path to truth</h4>

In order to do so you need two more packages that make your package available to dotLRN:

  • dotlrn-foo package
  • foo-portlet package
Both packages are required so that you application can be added to dotLRN communities and classes
as well as to the "My Space" of a student. The integration is done through you by providing two
portlets:
  • foo-admin-portlet

  • foo-portlet

The first one provides community and class admins with at least a link to you application. You can also
add some more stuff to that portlet but usually it is used to simply link to the admin area of your
package.

The second portlet is destined for the student and can have two different states depending on wether
it is displayed in a community/class/subgroup or on "My Space". In the first scenario it should only provide
group specific content of your application in the second case it should provide user oriented content over
all groups. Take a look at the FAQ, Forums, Calender ... portlets and how they change depending on the
area you are (group or "My Space").

<h4>The solution - Simple Steps to Heaven</h4>

Until the new portal system is available to dotLRN we have to integrate using the current solution. Since
most of the integration part is a lots of Cut & Paste and the application developer should put more time
in creating nice portlets I have prepared integration templates that does all the work for you.

All you need is to do the following steps.
Note: ALL FIND AND REPLACE STUFF BELOW MUST BE CASE SENSITIVE AND WHOLE WORDS:

  1. Download the archive and extract it to your workspace. It contains templates
    of the two required packages.
  2. Open a text editor that can find and replace strings over several pages. You can also write some perl scripts or other stuff if.
    you know what you are doing.
  3. Replace all occurrences of foo with actual package name of your application.
  4. Then replace Foo with the pretty name of your package.
  5. Now replace YourName with your full name like 'Luke Skywalker'.
  6. Replace mailto:test@test.com with your correct e-mail.

  7. Now replace YourInstitution with the full name of the institution you work for 'Jedi School'.
  8. Replace InstitutionURL with fully qualified URL to your institution like 'http://www.jedi.org';.
  9. Replace all yyyy-mm-dd to the current date like '2005-06-21'.
  10. Change ALL file and folder names where foo appears with your package name.

  11. The templates assume that your application's package version is 1.0. Change the *.info files acordingly
    if that is not the case.
  12. Copy the two packages to your test server. Make a dump of your database before you try to install
    the packages using the Package Manager. If something goes wrong you are able to restore everything.
  13. After a restart you can start working on the foo-admin-portlet and foo-portlet files
    by adding your application to a community Control Panel-->Manage Applets-->Your Package [add].
FINISHED! :)

The code has been sucessfully tested PostgreSQL with dotLRN 2.1.1 and OpenACS 5.1 installed. The packages are i18n-ized and currently support the locales en_US, es_ES and de_DE.

Oracle is also support though I have not tested it but I assume that it will install properly.

Drop scripts are also available for both PostgreSQL and Oracle.

How do I prevent a portlet to show up for the users (if this portlet is only "community enabled" ?

How do I give permissions on a portlet (e.g. only Role "Professor" can see the portlet in the community) ?

Malte,

to find out if you are in a community you can use

dotlrn_community::get_community_id

which either returns nothing or the community id.

Since the dotLRN roles have (from what I understand) nothing to do with the permission system you need to query for the role or rel_type of the person and limit the access.


select dotlrn_member_rels_approved.rel_type,
dotlrn_member_rels_approved.role
from
dotlrn_member_rels_approved
where dotlrn_member_rels_approved.community_id = :community_id
and dotlrn_member_rels_approved.user_id = :user_id

Hello!

For find text, replace text or rename files
recursively on a dir tree we are using the
next scripts (on Linux):

-Script: replaceall ----- Cut here -----------------
#! /bin/sh
# (c) Jose Agustin Lopez Bueno (mailto:Agustin.Lopez@uv.es)

if [ $# -ne 3 ]
then
echo "Usage: $0 begindir filefilter whatfind"
echo " Search text in several files (recursively)"
echo " Example: $0 /tmp \"*.txt\" whatfind"
exit 1
fi

find "$1" -type f -name "$2" -print | while read i
do
grep -H -s -i $3 $i
done

-Script: renameall ----- Cut here -----------------
#! /bin/sh
# (c) Jose Agustin Lopez Bueno (mailto:Agustin.Lopez@uv.es)

if [ $# -ne 4 ]
then
echo "Usage: $0 begindir filefilter whatfind whatreplace"
echo " Rename several files (recursively)"
echo " Example: $0 /tmp \"*.*\" .jpg .jpeg"
exit 1
fi

find "$1" -name "$2" -print | while read i
do
mv $i `echo $i | sed "s|$3|$4|g"`
done

-Script: replacetext ----- Cut here -----------------
#! /bin/sh
# (c) Jose Agustin Lopez Bueno (mailto:Agustin.Lopez@uv.es)

if [ $# -ne 4 ]
then
echo "Usage: $0 begindir filefilter whatfind whatreplace"
echo " Replace text in several files (recursively)"
echo " Example: $0 /tmp \"*.txt\" wrong right"
exit 1
fi

find "$1" -type f -name "$2" -print | while read i
do
sed "s|$3|$4|g" $i > $i.tmp && mv $i.tmp $i
done
-------------------------------------------------

Collapse
Posted by Antonio Luis on
I have tryed to integrate an openACS package with the Nima`s solution but I get an error when trying to add the application to the community by Control Panel-->Manage Apllets-->My Package [add].
This error is:

portal::get_datasource_name error! No datasource with name "prueba2_admin_portlet" found

I think i have done all correctly, the sql scripts executly correctly and the aliases in the table acs_sc_impl_aliases are correct.

I have dived into the source code of dotlrn and I reach to the procedure portal::get_datasource_name this is the code:

##############################Code#########################

ad_proc -private get_datasource_name { ds_id } {
Get the ds name from the id or the null string if not found.

@param ds_id
@return ds_name
} {
if { ![catch {db_1row select {}} errmsg] } {
return $name
} else {
global errorInfo
set error_text "portal::get_datasource_name error! No datasource with id \"$ds_id\" found"
ns_log Error $error_text
ns_log Error "$errorInfo"
ad_return_complaint 1 $error_text
}
}

##########################Code############################
so look at the if clausule. The db_1row always catch an error isnt it?the sql sentence "select" always gives an error so this is a bug? Nima says it tested succesfully so i assume didn`t had to pass by this procedure???
Any suggestion????
Thanks in Advance

Can you send me your *-portlet and your dotlrn-* packages so that I can test them?
Antonio,

from what I see you didn't use the *.info shipped with the packages. Please use the packages as they are. Also you didn't replace the dates. Can you do that and check if it works?

Ok sorry i was creating the package instead of installing it so it created another .info.
With your .info all works perfectly!
Thanks a lot you have save me a lot of time
<h2>New Improved Version</h2>

Since all the renaming and replacing stuff can be dull I created a little script that does all the magic for you. You can download a new version of the integration package here.

<h2>Usage</h2>

Simply extract the archive and call the script via

tclsh run.tcl

Here a sample output. User entries are highlighted:

====================================================
dotLRN Integration Support
----------------------------------------------------
Note: You need a clean copy of the integration
      package each time you run this script.
      This service assumes that you have already
      created a package and want to integrate it
      with dotLRN.
----------------------------------------------------
Enter the package key (no white-space):
my-package
The pretty name for your package     :
My First Package
Your lastname                        :
Mazloumi
Your first names                     :
Nima
Your email                           :
mailto:mazloumi@uni-mannheim.de
Your Institution                     :
University of Mannheim
University of Mannheim's URL (http://...)
http://www.uni-mannheim.de
----------------------------------------------------
Thank you Nima Mazloumi
for using the integration support.
Two packages will be created for the package
My First Package (my-package).

---------------------------------------------------- Creating Package my-package-portlet... ... done. ---------------------------------------------------- Creating Package dotlrn-my-package... ... done. ---------------------------------------------------- Finished! ---------------------------------------------------- Copy the packages to your OpenACS packages folder and use the Package Manager for installation.

Author: Nima Mazloumi, 2005 ====================================================

Enjoy!

Added version support for dependencies and clean up:
https://openacs.org/storage/view/.lrn/dotlrn-integration.zip
Hi all,
I've just given a shot to the latest zipped file.
Run the tcl script and tried to install the resulting package.

The TCL script worked perfectly. Good work.

Nonetheless, during the installation of the package I got the following errors, at the dotlrn-xxxx-create.sql:
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "DOTLRN.ACS_SC_IMPL", line 40
ORA-06512: at "DOTLRN.ACS_SC_IMPL_ALIAS", line 15
ORA-06512: at "DOTLRN.ACS_SC_IMPL", line 92
ORA-06512: at line 15

The other, xxxx-portlet-create.sql went ok, with no errors.
Looking at DB (oracle, by the way), I see the the acs_cs_impls record is there, as well as the acs_cs_imps_aliases ones.

When I try to uninstall I get the same error. And re-installing doesn't improve it either.

Looking at sql script that fails I noticed it's using the marked as obsolete function acs_sc_impl.new_alias , I guess it would be a good idea to replace it with acs_sc_impl_alias.new. I did so but got the same error.

So far the applet doesn't work cause it's not added to dotlrn_applets table. I guess due to the sql failed part.

If anyone may provide a little light on this I'm willing to try anything, and will post the results.

Thanks in advance.

Hi David,

from you post I assume that you tested it with Oracle. I have created the templates for Oracle without ever being able to test it, since I don't have an Oracle installation.

I already thought that it might break here and there since I was only able to deduce how the code should look like.

Please let me know if you find a fix, I will change the template to accordingly.

Greetings,
Nima

There are two rather simply things that we should fix in the future:

1. In dotLRN the removal of an applet to a community is not implemented.

2. Though right now with this script you can easily install/uninstall the generated packages, the unistall with APM will fail as soon as an applet was added to a community due to foreign keys constraints in dotlrn_applets, and dotlrn_community_applets. Therefore the relevant entry in apm_package_types cannot be deleted.

P.S. A new version will be available within the next 30 min with a fix to the portlet adps to support shaded portlets.

Greetings,
Nima

Hi again,
I found the error on the sql/oracle/dotlrn-xxxx-create.sql:

we find:
-- create the implementation
test2portlet := acs_sc_impl.new (
impl_contract_name => 'dotlrn_test2portlet',

and should be:

-- create the implementation
test2portlet := acs_sc_impl.new (
impl_contract_name => 'dotlrn_applet',

After that, everything else seems to work alright.

Kind of tricky to test, because any uninstall must be followed to a manual "applet" deletion at DB->dotlrn_applets,
as well as DB->acs_sc_impls and DB->acs_sc_impls_aliases ,
otherwise next time you install you get a nice mess.

Hope this helps.

I forgot,
also this should be changed on xxxx-portlet-drop.sql, and xxxx-admin-portlet-drop.sql:

we find:
-- drop the impl
test2portlet := acs_sc_impl.del (

should be:
acs_sc_impl.del (

That should be all (hopefully).

Hi David,

thank you. I changed that in the templates. Regarding the uninstall we need to write the queries and extend the drop templates to do that for us automatically.

What queries do you call for this purpose. Can you send them to me?

Greetings,
Nima

Hi, Nima!

The links for dotlrn-integration is not working.
Where can I get the soft?

Thanks,
Agustin

Hi Nima!

I'm a beginner in dotLRN and I'm trying to integrate the myfirstpackage for openACS into dotLRN. I've tried to download the zip file integration-dotlrn.zip but the link doesn't work. Can you solve the link's problem so that I can dowload the file.

Thanks for your attention.

Thank you very much Nima!
Hi Nima!

I ran the file run.tcl and installed my package into dotlrn and all went ok. But after all this, I tried to add my applet to a community or course in the admin-panel and I got the following error ... and I can't stand what's wrong because all the installation progess went ok. Can you help me to get running my firt applet in dotlrn? The foo-package I called it my-package.

Thanks in advance.

Selection did not return a value, and no default was provided
while executing
"db_string pretty_name_from_key {select pretty_name
from apm_enabled_package_versions
..."
(procedure "apm_package_instance_new" line 4)
invoked from within
"apm_package_instance_new -package_id $package_id -package_key $package_key -instance_name $package_name -context_id $context_id"
(procedure "site_node::instantiate_and_mount" line 39)
invoked from within
"site_node::instantiate_and_mount -node_name $mount_point -parent_node_id $parent_node_id -package_key $package_key -context_id $package_id "
(procedure "dotlrn::instantiate_and_mount" line 15)
invoked from within
"dotlrn::instantiate_and_mount $community_id [package_key]"
(procedure "dotlrn_my-package::add_applet_to_community" line 6)
invoked from within
"dotlrn_my-package::add_applet_to_community $community_id"
(procedure "AcsSc.dotlrn_applet.addapplettocommunity.dotlrn_my_package" line 1)
invoked from within
"AcsSc.dotlrn_applet.addapplettocommunity.dotlrn_my_package 5532"
("uplevel" body line 1)
invoked from within
"uplevel $func_and_args"
(procedure "apply" line 3)
invoked from within
"apply $proc_name $arguments"
(procedure "acs_sc_call" line 6)
invoked from within
"acs_sc_call dotlrn_applet $op $list_args $applet_key"
(procedure "applet_call" line 2)
invoked from within
"applet_call $applet_key AddAppletToCommunity [list $community_id]"
invoked from within
"set package_id [applet_call $applet_key AddAppletToCommunity [list $community_id]]"
("uplevel" body line 2)
invoked from within
"uplevel 1 $transaction_code "
(procedure "db_transaction" line 39)
invoked from within
"db_transaction {
set package_id [applet_call $applet_key AddAppletToCommunity [list $community_id]]

register_a..."
(procedure "dotlrn_community::add_applet_to_community" line 2)
invoked from within
"dotlrn_community::add_applet_to_community $community_id $applet_key"
("uplevel" body line 43)
invoked from within
"uplevel {
#
# Copyright (C) 2001, 2002 MIT
#
# This file is part of dotLRN.
#
# dotLRN is free software; you can redistribute it and/or modify it u..."
(procedure "code::tcl::/var/www/dotlrn-2.3.0/packages/dotlrn/www/applet-..." line 2)
invoked from within
"code::tcl::$__adp_stub"
invoked from within
"if { [file exists $__adp_stub.tcl] } {

# ensure that data source preparation procedure exists and is up-to-date
adp_init tcl $__adp_stub
..."
("uplevel" body line 3)
invoked from within
"uplevel {

if { [file exists $__adp_stub.tcl] } {

# ensure that data source preparation procedure exists and is up-to-date
adp_init t..."
(procedure "adp_prepare" line 2)
invoked from within
"adp_prepare"
invoked from within
"template::adp_parse [file root [ad_conn file]] {}"
(procedure "adp_parse_ad_conn_file" line 5)
invoked from within
"$handler"
("uplevel" body line 2)
invoked from within
"uplevel $code"
invoked from within
"ad_try {
$handler
} ad_script_abort val {
# do nothing
}"
invoked from within
"rp_serve_concrete_file [ad_conn file]"
(procedure "rp_serve_abstract_file" line 60)
invoked from within
"rp_serve_abstract_file "$root/$path""
("uplevel" body line 2)
invoked from within
"uplevel $code"
invoked from within
"ad_try {
rp_serve_abstract_file "$root/$path"
set tcl_url2file([ad_conn url]) [ad_conn file]
set tcl_url2path_info..."

To do a search and replace I recommend using this:

find . -type f | xargs perl -pi -e "s/foo/mypackage/g"

You can use the pattern to seach and replace recursively all files: where foo is the text you want to replace and mypackage is the replacement text.

Most linux distributions contain a perl script called rename you can use to rename the files and directories.

ie:

rename "s/foo/mypackage/"

Oops, rname is not recursive!

use

find . | xargs rename "s/foo/mypackage/"