Category Archives: Uncategorized

Troubleshooting Alfresco’s JMX Console Connections

Most of the time, I can get jconsole to make a JMX connection to a running instance of Alfresco but there are times when I will run into issues or a customer simply can’t seem to make it work. Below are some troubleshooting steps to getting JMX working and make a connection to it.

Make sure that the Alfresco server does not have a NAT network connection. If you’re not sure what this is, you can ask your network administrator to check and tell you for sure. I realize I have this first in the list but usually this isn’t the cause. I would suspect this as the issue only if the following troubleshooting fails and you simply can’t get it working.

Make sure you have this somewhere in your java_opts:

-Dcom.sun.management.jmxremote

This tells the running JVM to start the jmx service.

Make sure you have this in your alfresco-global.properties:

alfresco.rmi.services.port=50500
alfresco.rmi.services.host=<hostname>

The <hostname> should be resolvable using ping from the workstation from where you are running jconsole.

Make sure you connect with the jconsole in the java/bin/ using the JDK you’re using to run Alfresco with. In other words, you may have another JDK installed elsewhere and jconsole from that JDK may be on your path. It’s a good idea to do a `whereis jconsole` to see which path it comes from. If nothing else, go directly to the java/bin directory in your Alfresco install and use the jconsole executable there. This is the standard url to use when connecting:

service:jmx:rmi:///jndi/rmi://<hostname>:50500/alfresco/jmxrmi

If you’re running this on the local server, you may want to try localhost for hostname. In any case, make sure that <hostname> is set to a reachable domain name on the network. IP Address might not be a bad idea either.

If you haven’t changed the username/password for JMX, the default is:

userid: controlRole
password: change_asap

The ‘change_asap’ password should be a hint to change it as soon as you can. If you simply can’t remember the username/password combo, they should be revealed in these files:

<configRoot>/alfresco/alfresco-jmxrmi.access
<configRoot>/alfresco/alfresco-jmxrmi.password

With all these things satisfied and Alfresco started, you can test on the Alfresco server to make sure the JMX rmi service is running by either issuing these from the command line:

# lsof -i :50500 (for Linux)
# netstat -an (for Windows)

With Windows you can probably use the /find switch to look for port 50500 in the listing specifically or you can scroll through the output to look for 50500.

Next, from the client workstation, you can test connectivity to the JMX rmi port by first pinging the server’s hostname. After this, check for port opening from your workstation by issuing:

# telnet <hostname> 50500

You’ll know this is open by getting a blank screen instead of the “unable to connect” message or something similar.

If none of these work, then have  your network admin see if your server is set up with NAT addressing. This can cause problems with any of the RMI services (of which JMX is related).

HTH,

H.S. :)

Getting FTP to work for AWS

If you are expecting to get FTP to work with Alfresco installed on AWS, you’ll find you get an error when you try to connect with your FTP client (FileZilla, lftp, gftp, etc.):

Error:	Connection timed out
Error:	Failed to retrieve directory listing

This can be a bit befuddling. How to fix this? Try these settings in your alfresco-global.properties file:

### FTP ###
ftp.dataPortFrom=8101
ftp.dataPortTo=8199

Make sure of course that you add this range (8101-8199) in your E2’s security group — it’s really the same thing as opening a port range in a router or firewall. Restart Alfresco and connect with your ftp client. Voila! It works!

Submitting info for an Alfresco Enterprise support case

Disclaimer: This article is based on the author’s opinion and should not be taken as official documentation on how to enter info for a support case with Alfresco Enterprise Support.

More often than not, we support guys have to ask for things like log files, settings, component types and versions and even compressed directories (and a whole lot of other things depending on the situation!). I work at Alfresco and this article is aimed at mostly our customers but it also will help you work with support professionals who are trying to help you solve problems for many different types of software.

Let’s be honest, a lot of these requests can be very tedious. They were for me when I worked as a SysAdmin or developer in the past. Perhaps you have another case open with another support member and you’ve already submitted the same logs there. Or it’s possible that you finished getting another problem solved and submitted many artifacts there very recently.

I can certainly empathize. As a sysadmin in the past, I worked very often with an enterprise-class database server (I won’t name it but it starts with a D and end with a 2). Since we had no DBA there, I had to open a number of tickets with support to solve many issues I was not familiar with. The support for this particular company seemed at times very unsympathetic and cold to me. They would continuously ask for settings and log files. It did however make sense later that they had no idea what was going on in my environment at that particular time especially if they gave me some settings to try that did not work after testing them.

There are other times when you might have submitted current artifacts on another active case. You can let the support person who is working your case know that. You can tell them where it is (attached to another case, on an ftp server, etc) and that you believe it to be the most current. Any reasonable support person would be more than happy to help gather them and attach the files to the case at hand. Just be aware that it may take the agent a little bit of extra time to find it in some instances but if you are ok with that, we are too.

There are a number of different artifacts that we ask for to help us determine the environment and what could be going wrong. What do we normally ask for and why?

Log Files

  • alfresco.log – gives us an idea from an Alfresco perspective what’s going on from startup and we can see what’s going on when you replicate the steps that are causing the issue.
  • share.log – since around 4.1.1 this was introduced so that we get very specific information about Share in its own log file.
  • solr.log – similar to share.log except it gives us specific info on Solr (the more recent index subsystem added to Alfresco)
  • catalina.out, stdout.log, stderr.log, etc. – These are Tomcat log files. They can help us in some instances determine the cause of Alfresco not starting, memory errors, http issues, etc. The catalina.out will also include the same info as alfresco.log. In many cases, it’s best to have this as it will include the same info found in alfresco.log, share.log, solr.log. However in some advanced problems this file can be too big to effectively read. We do try to parse with ‘grep’ but we may request seperate logs in some situations to get more clarity.

The most efficient way to gather log files is to follow these steps:

  1. Stop Alfresco
  2. Clear all log files (delete if not needed, rotate and/or backup if they are needed)
  3. Add any debug statements relevant to the issue given to you by your Support agent to log4j.properties (tomcat/webapps/alfresco/WEB-INF/classes/).
  4. Start Alfresco
  5. Perform the steps that replicate and reveal the issue
  6. Compress log files together and attach back to the case.

Settings Files

  • alfresco-global.properties – After Alfresco 3.1, alfresco-global.properties was introduced as a unified settings file. This can give us very quick visibility into your settings that you’ve added.
  • JMX Dump – A JMX dump will give us a very holistic and effective group of settings that Alfresco is using at a given time. Think of it in a way as a snapshot of your system. A big reason we ask for it is while you may have certain setting values in alfresco-global.properties they may not be used at that time because it’s possible a user has changed settings using the JConsole. The settings from JConsole that are added will override any property settings in the files until you go back in via JConsole and change them back. While it doesn’t tell us *everything* , it is the most effective way of us knowing exactly what your Alfresco settings are at a given point in time.
  • Compressed tomcat/shared/classes directory – For those wishing to customize their Alfresco installation, this is the start of where those files should be. Also, in situations that call for multiple means of the same type of authentication and user/group synchronization (example: multiple Active Directory servers/domains) the user will have to create additional configuration settings. For example, in this situatio these will be found in tomcat/shared/classes/alfresco/extension/Subsystems/authentication. It’s very good to have this when troubleshooting customizations.

As mentioned about log files, it’s very helpful to have all of these settings files compressed too and added with logs.

Others

  • screenshots – If you’re having a UI issue or you encounter an error that only shows up in the UI (and not in the logs), a screenshot can help us very quickly determine what’s going on. These should only be used when copying text is not an option.
  • thread dumps, heap dumps – Dumps are great for helping to solve performance or memory issues.

The settings and log files are valuable to us. We do our best to keep from requesting files that are not necessary but usually we will need to see them all again after we suggest some corrective action or when we know a change was made to the system. It’s easy to forget or misspell something. Believe it or not, most settings errors are because of this. The next group of things we may ask for is types and versions of Alfresco components. More than likely we only have to ask for these once per case:

Server

  • OS type and version, 64bit or 32bit?
  • Alfresco version
  • JDK version
  • Database type and version
  • Application server type and version

Client

  • OS type and version
  • Browser type and version
  • Office version

3rd party (optional and when needed)

  • OpenOffice (or LibreOffice) version
  • ImageMagick version
  • Swftools version
  • Kofax, Transformation server, etc. version

We need to know these things because like almost all Enterprise software out there, Alfresco maintains a list of supported software that is used by our product. In a lot of cases, the user uses the Alfresco package installer. This installer ensures you are using the supported versions of everything needed. In this case, if you’re asked for Alfresco server-side versions, just let your support technician know if you’ve installed Alfresco with our standard installer.

For client-side issues (SharePoint protocol, custom UI, etc.), we will most likely need to know things like client OS type and versions, browser and MS Office version.

We need to know these things because each Alfresco version is only certified with a particular mix of components. If we have to go to an advanced engineer or developer, they will insist on a supported software stack. Adding too many different platforms to our supported ones adds complexity to possible issues that arise and to our development/QA cycle which can be very expensive and more difficult to support and maintain for you, the customer.

How do I compress files to send them back to you?

Ideally it’s best to use only standard tools. I try to make sure I have compression tools so I can handle things like 7-zip, RAR and zx files. However, some of these don’t work on every laptop that a support person has. While I may have them on mine, we occasionally have to pass cases on to other support technicians and they may not have these tools. It’s best to use these:

  • tar – Linux/Mac OS X
  • gzip/bzip2 – Linux/Mac OS X
  • zip – Windows

If you’re unable to use these compression tools on your system or it’s not practical, no worries, just send them in the best way you can.

Hopefully all of this is helpful and makes sense when you open a case with us and a support tech is asking for these files. It really does help us solve your issue quicker when you help us help you :)

– H.S.

Best Practices for Using Active Directory with Alfresco

Normally when I help a user that involves issues with setting up synchronization of users and groups, the customer has settings that are extremely generic like these:

ldap.synchronization.groupSearchBase=dc\=example,dc\=foo
ldap.synchronization.userSearchBase=dc\=example,dc\=foo

ldap.synchronization.groupQuery=objectclass\=group
ldap.synchronization.personQuery=(&(objectclass\=user)(userAccountControl\:1.2.840.113556.1.4.803\:\=512))

ldap.synchronization.personDifferentialQuery=(&(objectclass\=user)(userAccountControl\:1.2.840.113556.1.4.803\:\=512)(!(modifyTimestamp<\={0})))
ldap.synchronization.groupDifferentialQuery=(&(objectclass\=group)(!modifyTimestamp<\={0}))

Syntactically speaking, these queries are fine but they synch users and groups from a very naive perspective. What these queries and settings are telling you are this:

1. We’ll start our search for groups and users in example.foo (based on the settings below).

ldap.synchronization.groupSearchBase=dc\=example,dc\=foo
ldap.synchronization.userSearchBase=dc\=example,dc\=foo

2. We will synch in ALL users and ALL groups inside of example.foo.

ldap.synchronization.groupQuery=objectclass\=group
ldap.synchronization.personQuery=(&(objectclass\=user)(userAccountControl\:1.2.840.113556.1.4.803\:\=512))

3. When the differential synchronization occurs we will synch in any additional users and groups that are created that fit the query we’ve set up previously (which to say will be ALL of them).

ldap.synchronization.personDifferentialQuery=(&(objectclass\=user)(userAccountControl\:1.2.840.113556.1.4.803\:\=512)(!(modifyTimestamp<\={0})))
ldap.synchronization.groupDifferentialQuery=(&(objectclass\=group)(!modifyTimestamp<\={0}))

Now, you may have a use-case that requires this but that’s probably not likely. Almost more likely is the fact that most of your AD users will not be using Alfresco. A lot of them maybe but not all of them. The best practice here is to create an Alfresco organizational unit and then create a couple of different Alfresco groups in this OU:

Create an Alfresco organizational unit with a distinguished name like so:

OU=Alfresco,DC=example,DC=foo

Then you can create any Alfresco specific groups underneath OU=Alfresco like so:

CN=AlfrescoAdmins,OU=Alfresco,DC=example,DC=foo
CN=AlfrescoUsers,OU=Alfresco,DC=example,DC=foo

At this point, you can assign your users to these different two groups. For my testing purposes I created 3 AD users (aduser1, aduser2, aduser3) and then made aduser1 a member of AlfrescoAdmins and then all three, members of AlfrescoUsers. Now we can change our queries to look thusly:

Our LDAP queries will now only search for groups in ou=Alfresco,dc=example,dc=foo and users throughout the directory (as they could realistically exist in many places).

ldap.synchronization.groupSearchBase=ou\=alfresco,dc\=example,dc\=foo
ldap.synchronization.userSearchBase=dc\=example,dc\=foo

We can keep at least the groupQuery the same. This will bring in every group in OU=Alfresco:

ldap.synchronization.groupQuery=objectclass\=group

This will only bring in users who are members of AlfrescoAdmins and AlfrescoUsers and not every single user in Active Directory:

ldap.synchronization.personQuery=(&(objectclass\=user)(userAccountControl\:1.2.840.113556.1.4.803\:\=512)(|(memberOf=cn\=AlfrescoAdmins,ou=alfresco,dc=example,dc=foo)(memberOf=cn\=AlfrescoUsers,ou=alfresco,dc=example,dc=foo)))

Next of course, for differential synchs we’ll use the same queries except add the modifiedTimestamp directive at the end:

ldap.synchronization.personDifferentialQuery=(&(objectclass\=user)(userAccountControl\:1.2.840.113556.1.4.803\:\=512)(|(memberOf=cn\=AlfrescoAdmins,ou=alfresco,dc=example,dc=foo)(memberOf=cn\=AlfrescoUsers,ou=alfresco,dc=example,dc=foo))(!(modifyTimestamp<\={0})))

ldap.synchronization.groupDifferentialQuery=(&(objectclass\=group)(!modifyTimestamp<\={0}))

Below are the LDAP and Synchronization settings I used for 4.2.x and this works with no issues:

### AD authentication only ###
authentication.chain=alfrescoNtlm1:alfrescoNtlm,ldap-ad1:ldap-ad
ldap.authentication.active=true
ldap.authentication.allowGuestLogin=true
ldap.authentication.userNameFormat=%s@example.foo
ldap.authentication.java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
ldap.authentication.java.naming.provider.url=ldap://example.foo:389
ldap.authentication.java.naming.security.authentication=simple
ldap.authentication.escapeCommasInBind=false
ldap.authentication.escapeCommasInUid=false
ldap.authentication.defaultAdministratorUserNames=Administrator

ldap.synchronization.active=true
ldap.synchronization.java.naming.security.principal=administrator@example.foo
ldap.synchronization.java.naming.security.credentials=Alfr3sc0
ldap.synchronization.queryBatchSize=1000
ldap.synchronization.attributeBatchSize=1000
synchronization.synchronizeChangesOnly=false
synchronization.allowDeletions=true
synchronization.syncWhenMissingPeopleLogIn=true

ldap.synchronization.groupQuery=objectclass\=group
ldap.synchronization.groupDifferentialQuery=(&(objectclass\=group)(!(modifyTimestamp<\={0})))

ldap.synchronization.personQuery=(&(objectclass\=user)(userAccountControl\:1.2.840.113556.1.4.803\:\=512)(|(memberOf=cn\=AlfrescoAdmins,ou=alfresco,dc=example,dc=foo)(memberOf=cn\=AlfrescoUsers,ou=alfresco,dc=example,dc=foo)))

ldap.synchronization.personDifferentialQuery=(&(objectclass\=user)(userAccountControl\:1.2.840.113556.1.4.803\:\=512)(|(memberOf=cn\=AlfrescoAdmins,ou=alfresco,dc=example,dc=foo)(memberOf=cn\=AlfrescoUsers,ou=alfresco,dc=example,dc=foo))(!(modifyTimestamp<\={0})))

ldap.synchronization.groupSearchBase=ou\=alfresco,dc\=example,dc\=foo

ldap.synchronization.userSearchBase=dc\=example,dc\=foo

ldap.synchronization.modifyTimestampAttributeName=modifyTimestamp
ldap.synchronization.timestampFormat=yyyyMMddHHmmss'.0Z'
ldap.synchronization.userIdAttributeName=sAMAccountName
ldap.synchronization.userFirstNameAttributeName=givenName
ldap.synchronization.userLastNameAttributeName=sn
ldap.synchronization.userEmailAttributeName=mail
ldap.synchronization.userOrganizationalIdAttributeName=company
ldap.synchronization.defaultHomeFolderProvider=largeHomeFolderProvider
ldap.synchronization.groupIdAttributeName=cn
ldap.synchronization.groupDisplayNameAttributeName=displayName
ldap.synchronization.groupType=group
ldap.synchronization.personType=user
ldap.synchronization.groupMemberAttributeName=member
ldap.synchronization.enableProgressEstimation=true

Now all groups show up and all users show up in the proper group. I hope this is helpful.

-H.S.

Javascript: Templating Folders when created by Share Rules

question

This one has had me perplexed for some time. We seem to get this question just a few times a year but it’s a really good one:

I’m creating a rule on a folder in Share. This rule will create 3 particular subfolders in the new folder that’s being created with a script. How do I accomplish this?

It made sense to me that your script should look like:

var subfolder1 = space.childByNamePath("subfolder1");
subfolder1 = space.createFolder("subfolder1");

As I’ve found out, the “space” counts as the root folder where this new folder is being placed. If this does anything, it will only create the folders in the same directory as your new folder. It took me a while of looking through blogs, articles and our own documentation to find out that this is the way to get it done:

var invoices = document.childByNamePath("Invoices");
invoices = document.createFolder("Invoices");

I tested this with a rule and it works like a champ. It didn’t dawn on me initially to use document to represent the node being created that triggers the rule. And from here we can then do things like copy, change/add aspects, create associations, and so on. 

Happy Scripting!

-H.S.

Alfresco Custom Data Lists

Summary

The data lists feature allows site members to create and manage lists of data relevant to the site. Users can work with their own lists and can also contribute to lists created by other site members. Out of the box there are many list templates provided such as: Contact list, Event list, Issue list, To-do list, Feedback list, etc.

Since there are a limited number of canned or out of the box data lists, you will likely need to create your own custom datalist.

To do this, you’ll need to create a custom model file that will define the data list essentially. You’ll also need a context file that references the custom model and finally, make modifications to share-config-custom.xml so that your data list will register and display in your Share site. Be aware that I was able to successfully create a custom data-list using these steps on Alfresco versions 3.4.x and 4.x. I did not test in 3.3, 3.2 or before.

Below are the steps to accomplish this.

Custom Model File

I have called this one slModel.xml to be placed in the extensions directory. This is usually in <alfresco_install_dir>/tomcat/shared/classes/alfresco/extension directory:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Definition of new Model -->
<model name="sl:slDatalist" xmlns="http://www.alfresco.org/model/dictionary/1.0">
 <!-- Optional meta-data about the model --> 
 <description>KB datalist</description>
 <author>Harlin Seritt</author>
 <version>1.0</version>
 <!-- Imports are required to allow references to definitions in other models --> 
 <imports>
     <!-- Import Alfresco Dictionary Definitions -->
     <import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
     <!-- Import Alfresco Content Domain Model Definitions -->
     <import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
     <!-- Import Alfresco Data List Model Definitions -->
     <import uri="http://www.alfresco.org/model/datalist/1.0" prefix="dl"/>
 </imports>

<!-- Introduction of new namespaces defined by this model --> 
 <namespaces>
     <namespace uri="sl.customlists.com" prefix="sl"/>
 </namespaces>
 <types>
 <!-- Data list defintions For this model go here -->
     <type name="sl:slArticle">
         <title>SL Article</title>
         <description>Simple Article</description>
         <parent>dl:dataListItem</parent>

         <properties>
             <property name="sl:slTitle">
                 <title>Title</title>
                 <type>d:text</type>
                 <mandatory>true</mandatory>
             </property>

             <property name="sl:slContent">
                 <title>Content</title>
                 <type>d:text</type>
                 <mandatory>false</mandatory>
             </property>
         </properties> 

         <associations>
             <association name="sl:slAttachments">
                 <title>Attachements</title>
                 <source>
                     <mandatory>false</mandatory>
                     <many>true</many>
                 </source>
                 <target>
                     <class>cm:content</class>
                     <mandatory>false</mandatory>
                     <many>true</many>
                 </target>
             </association>
         </associations>
     </type>
 </types> 
</model>

Next, you’ll need to create a context file. This file (slModel-context.xml) needs to be placed in the extension directory :

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
    <!-- Registration of new models --> 
    <bean id="sl.extension.dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="dictionaryBootstrap">
    <property name="models">
        <list>
            <value>alfresco/extension/slModel.xml</value>
        </list>
    </property>
 </bean>

<!-- Shows how to add an additional model if needed
<bean id="extension.mtg.dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="dictionaryBootstrap">
 <property name="models">
     <list>
         <value>alfresco/extension/myOtherDatalistModel.xml</value>
     </list>
 </property>
</bean>
-->

</beans>

Last, add these configs to the share-config-custom.xml file (to be overwritten in the web-extensions directory usually in tomcat/shared/classes/web-extension):<config evaluator=”model-type” condition=”sl:slArticle”> <forms>

     <!-- Create item form -->
     <form>
         <field-visibility>
             <show id="sl:slTitle" /> 
             <show id="sl:slContent" /> 
             <show id="sl:slAttachments" /> 
         </field-visibility>
         <create-form template="/org/alfresco/components/data-lists/forms/dataitem.ftl" />
         <appearance>
             <field id="sl:slTitle">
                 <control template="/org/alfresco/components/form/controls/textarea.ftl" /> 
             </field>
             <field id="sl:slContent">
                 <control template="/org/alfresco/components/form/controls/textarea.ftl" /> 
             </field> 
             <field id="sl:slAttachments">
                 <control>
                     <control-param name="startLocation">{doclib}</control-param>
                 </control>
             </field>
         </appearance>
     </form>

 <!-- Data Grid view -->
 <form id="datagrid">
      <field-visibility> 
          <show id="sl:slTitle" /> 
          <show id="sl:slContent" /> 
          <show id="sl:slAttachments" /> 
      </field-visibility>
 </form>
</forms>
</config>

 <!-- Edit view -->
 <config evaluator="node-type" condition="sl:slArticle">
 <forms>
     <!-- Edit marketing item form -->
     <form>
          <field-visibility> 
              <show id="sl:slTitle" /> 
              <show id="sl:slContent" /> 
              <show id="sl:slAttachments" /> 
          </field-visibility>
          <create-form template="/org/alfresco/components/data-lists/forms/dataitem.ftl" />
          <appearance>
              <field id="sl:slTitle">
                 <control template="/org/alfresco/components/form/controls/textarea.ftl" /> 
              </field>
              <field id="sl:slContent">
                  <control template="/org/alfresco/components/form/controls/textarea.ftl" /> 
              </field> 
              <field id="sl:slAttachments">
                  <control>
                      <control-param name="startLocation">{doclib}</control-param>
                  </control>
              </field>
          </appearance>
     </form>
 </forms>
</config>

Add these in place and restart Alfresco. You can then go to any Share site and add this datalist:

<screenshot>

Choose the SL Article data list:

<screenshot>

Add data:

<screenshot>

Now, you have a custom data list!

Cheers! -H.S.

How To Install Alfresco Dashlets

Screen Shot 2013-02-05 at 2.20.30 PM

Summary

Alfresco Share Dashlets are mini applications (some may be tempted to say Applets but that is more of a Java term 😉 ) that are able to be added on the fly to add some very minor functionality to your Alfresco server. You can get Share dashlets here. In case you weren’t aware, you can pick up many new dashlets created by the community and even peek inside some sample ones to get an idea how to create your own.

Make sure you have a look at the individual page for each dashlet you’re interested. The dashlet’s page may tell you how to build them (usually with ant), deploy them, which Alfresco version is required, etc.

How To Deploy Dashlets to Alfresco

Which jar file to use for them may depend on the build method used.

Create a tomcat/shared/lib directory if you haven’t already:

# cd <alf_install>/tomcat
# mkdir -p shared/lib

Add the shared/lib/*.jar to shared.loader in tomcat/conf/catalina.properties:

shared.loader=${catalina.base}/shared/classes,${catalina.base}/shared/lib/*.jar

Afterwards, copy the dashlet jars into tomcat/shared/classes and restart Alfresco.

Open your Share page and go to Customize Dashboard.

Screen Shot 2013-02-05 at 10.07.15 AM

When you click on Add Dashlets you should now see your dashlet added to the list. In my case this is the BBC Weather dashlet.

Screen Shot 2013-02-05 at 10.08.03 AM

Drag this one to your list and click Ok. I dragged mine from Add Dashlets to Column 1 in this case. This will bring you to your dashboard and the dashlet should be now showing. To configure this particular one to show the weather for a particular city, click on the pencil icon in the upper right corner of the dashboard (look on yours, in the screenshot below the pencil icon isn’t shown).

Screen Shot 2013-02-05 at 10.10.23 AM

Change the city to yours and click Ok.

Screen Shot 2013-02-05 at 10.10.47 AM

Voila! The BBC Weather Dashlet should be showing on your dashboard.

This method should work for most dashlets but keep in mind, some of them may take some additional steps to configure.

Happy Dashletting!

Cheers! -H.S.

Installing Oracle for use with Alfresco

oracle-11g-express-edition

This article is about installing Alfresco with Oracle database. In getting Oracle installed I followed most of the information at this link. The article mentioned here is mainly about setting up an Oracle RAC — which is out of the scope of our article really — but has some good steps to getting Oracle 11g installed on a RHEL 5 server.

Where do you get Oracle 11g? Right here. How much does it cost? Nothing but of course you get no support.

My Oracle “server” is a RHEL 5 virtual machine. Keep in mind if you weren’t aware of the ramifications already but Oracle is serious enterprise software. It has a lot of system requirements that you’ll have to fulfill before it will allow you to install it without complaining. I followed these steps to getting 11g installed here:

Install these packages using yum:

yum install binutils elfutils-libelf glibc glibc-common libaio \
 libgcc libstdc++ make compat-libstdc++-33 elfutils-libelf-devel \
 glibc-headers glibc-devel libgomp gcc gcc-c++ libaio-devel \
 libstdc++-devel unixODBC unixODBC-devel sysstat

Add these lines to /etc/sysctl.conf:

# Kernel sysctl configuration file for Red Hat Linux
#
# For binary values, 0 is disabled, 1 is enabled. See sysctl(8) and
# sysctl.conf(5) for more details.
# Controls IP packet forwarding
net.ipv4.ip_forward = 0
# Controls source route verification
net.ipv4.conf.default.rp_filter = 1
# Do not accept source routing
net.ipv4.conf.default.accept_source_route = 0
# Controls the System Request debugging functionality of the kernel
kernel.sysrq = 0
# Controls whether core dumps will append the PID to the core filename
# Useful for debugging multi-threaded applications
kernel.core_uses_pid = 1
# Controls the use of TCP syncookies
net.ipv4.tcp_syncookies = 1
# Controls the maximum size of a message, in bytes
kernel.msgmnb = 65536
# Controls the default maxmimum size of a mesage queue
kernel.msgmax = 65536
# Controls the maximum shared segment size, in bytes
kernel.shmmax = 68719476736
# Controls the maximum number of shared memory segments, in pages
kernel.shmall = 4294967296
kernel.shmmni = 4096
# semaphores: semmsl, semmns, semopm, semmni
kernel.sem = 250 32000 100 128
net.ipv4.ip_local_port_range = 9000 65500
net.core.rmem_default=4194304
net.core.rmem_max=4194304
net.core.wmem_default=262144
net.core.wmem_max=1048576
# Additional and amended parameters suggested by Kevin Closson
#net.core.rmem_default = 524288
#net.core.wmem_default = 524288
#net.core.rmem_max = 16777216
#net.core.wmem_max = 16777216
net.ipv4.ipfrag_high_thresh=524288
net.ipv4.ipfrag_low_thresh=393216
net.ipv4.tcp_rmem=4096 524288 16777216
net.ipv4.tcp_wmem=4096 524288 16777216
net.ipv4.tcp_timestamps=0
net.ipv4.tcp_sack=0
net.ipv4.tcp_window_scaling=1
net.core.optmem_max=524287
net.core.netdev_max_backlog=2500
sunrpc.tcp_slot_table_entries=128
sunrpc.udp_slot_table_entries=128
net.ipv4.tcp_mem=16384 16384 16384
fs.file-max=6815744
fs.aio-max-nr=1048676

Note that some of these lines are different than what’s mentioned in article. I had to add a couple of missing settings and increase the values for a few of them contrary to the article. After these are added to sysctl.conf run the following to have the system accept them:

# sysctl -p

Add these lines to /etc/security/limits.conf:

oracle soft nproc 2047
oracle hard nproc 16384
oracle soft nofile 1024
oracle hard nofile 65536

Add this line to /etc/security/limits.conf:

session required pam_limits.so

You’ll also want to disable SELinux (Redhat’s advanced security suite) by changing to the setting below in /etc/selinux/config file:

SELINUX=disabled

You’ll need to restart the server so that this setting takes before installing Oracle. Actually you can disable this after adding that line without a server restart. You can do this now or wait until you’re ready for the actual install.

Next, create the groups and users needed for Oracle to work properly:

# groupadd oinstall
# groupadd dba
# groupadd oper
# groupadd asmadmin

Add the Oracle user:

# useradd -u 500 -g oinstall -G dba,oper,asmadmin oracle

Set the password for the “oracle” user:

# passwd oracle

I did add these settings below to the .bash_profile file in user oracle’s home directory:

# Oracle Settings
TMP=/tmp; export TMP
TMPDIR=$TMP; export TMPDIR
ORACLE_HOSTNAME=rac1.localdomain; export ORACLE_HOSTNAME
ORACLE_BASE=/u01/app/oracle; export ORACLE_BASE
ORACLE_HOME=$ORACLE_BASE/product/11.1.0/db_1; export ORACLE_HOME
ORACLE_SID=RAC1; export ORACLE_SID
ORACLE_TERM=xterm; export ORACLE_TERM
PATH=/usr/sbin:$PATH; export PATH
PATH=$ORACLE_HOME/bin:$PATH; export PATH
LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib; export LD_LIBRARY_PATH
CLASSPATH=$ORACLE_HOME/JRE:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib; export CLASSPATH
if [ $USER = "oracle" ]; then
    if [ $SHELL = "/bin/ksh" ]; then
        ulimit -p 16384
        ulimit -n 65536
    else
    ulimit -u 16384 -n 65536
    fi
fi

But, after installing Oracle I went back and made changes to paths and other settings to reflect the installed environment. For yours, remember to set the correct values for the ORACLE_SID and ORACLE_HOSTNAME here.

Now, you can run the Oracle installer. Hopefully the prerequisite checks should clear but you may have to work out whichever issues you may come across. Generally for any unexpected issues I found, I was able to Google a solution for it.

If you’re not familiar with the way Oracle manages its database, know that it makes use of schemas as traditional databases (unlike DB2, MySQL or Microsoft SQL Server). The Oracle database is akin to a database server instance. When you create and manage a traditional database in Oracle, know that this is referred to as a schema. For more on how this works, have a look at: http://forums.devshed.com/mysql-help-4/schema-vs-database-388038.html

This one has a crude answer but explains it simply enough. Think of it this way:

MySQL:
tables -> database -> database server or instance (commonly called a MySQL instance)

DB2:
tables -> schema -> database -> database server or instance (commonly called a DB2 instance)

Oracle:
tables -> schema -> database server or instance (commonly called an Oracle database)

The schema when created will have a user owner with the same name. Make sure you use this schema when setting up your database for use with Alfresco. My database settings within alfresco-global.properties look like this:

db.driver=oracle.jdbc.OracleDriver
db.username=alf400
db.password=alfresco
db.name=alf400
db.url=jdbc:oracle:thin:@localhost:1521:orcl
db.port=1521

Know that it’s entirely possible to have a schema created but use a different username other than the one generated on schema creation to connect with Alfresco. In this case db.username is the username created for the schema. The db.name is the schema. A lot of times they are the same but not necessarily especially in high security environments. With the jdbc url know that “orcl” refers to the used SID or instance installed.

Lastly before starting up Alfresco, you’ll need to make sure that the jdbc driver file, ojdbc6.jar, is inside tomcat/lib directory. Make sure you use the ojdbc6.jar found at the Oracle website instead of the one that comes with the Oracle install. With all that when Alfresco starts up, your database should be recognized and all tables Alfresco needs will be set up and populated with initial data.

Cheers! -H. S.

Configuring Authentication with Alfresco: OpenLDAP

Screen Shot 2013-01-15 at 8.22.49 AM

When it comes to authentication, the Alfresco NTLM authentication that comes out of the box will only get you so far in terms of efficiency. In almost all serious Enterprise environments you’re going to use a directory service for managing users and groups and for authentication. It’s likely you may use more than one directory service or type of directory service. This article focuses on how to set up Alfresco to work with an OpenLDAP directory service.

You may already have an LDAP system you can work with but in case you don’t, I’ll provide directions on how to get one up and running so you can see how this works with Alfresco

My server for this test is a RHEL server. I’ve managed to install the OpenLDAP server by issuing these commands:

# yum install openldap-servers openldap openldap-clients

After this finishes, you can open up /etc/openldap/slapd.conf and ensure these settings exist in the file:

include /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/inetorgperson.schema
include /etc/openldap/schema/nis.schema
pidfile /var/run/openldap/slapd.pid
argsfile /var/run/openldap/slapd.args
database bdb
suffix "dc=<domain>,dc=com"
rootdn "cn=Manager,dc=<domain>,dc=com"
rootpw secret
directory /var/lib/ldap
index objectClass eq,pres
index ou,cn,mail,surname,givenname eq,pres,sub
index uidNumber,gidNumber,loginShell eq,pres
index uid,memberUid eq,pres,sub
index nisMapName,nisMapEntry eq,pres,sub

After saving, you can then run /etc/init.d/ldap restart.

To populate the OpenLDAP server with a few users you can use a sample ldiff import file I have here:

dn: dc=<domain>,dc=com
objectClass: dcObject
objectClass: organization
dc: <domain>
o: support

dn: ou=people,dc=<domain>,dc=com
objectClass: organizationalUnit
objectClass: top
ou: people

dn: cn=<firstname lastname>,ou=people,dc=<domain>,dc=com
objectClass: person
objectClass: top
objectClass: inetOrgPerson
objectClass: organizationalPerson
cn: <firstname lastname>
sn: <lastname>
mail: <email address>
uid: <username>
userPassword:: c2VjcmV0aHM= <- this is actually "secreths"

dn: cn=<firstname lastname>,ou=people,dc=<domain>,dc=com
objectClass: person
objectClass: top
objectClass: inetOrgPerson
objectClass: organizationalPerson
cn: <firstname lastname>
sn: <lastname>
mail: <email address>
uid: <username>
userPassword:: c2VjcmV0aHM= <- this is actually "secreths"

dn: ou=groups,dc=<domain>,dc=com
objectClass: organizationalUnit
objectClass: top
ou: groups

dn: cn=all,ou=groups,dc=<domain>,dc=com
objectClass: groupOfNames
objectClass: top
cn: all
member: cn=<cn name from users above>,ou=people,dc=<domain>,dc=com
member: cn=<cn name from users above>,ou=people,dc=<domain>,dc=com

The <domain> name is a simple domain and not a fully qualified domain name. So, if you’re fqdn was called alfresodemo.com, your domain in this case would be called “alfrescodemo”. Fill in the firstname, lastname, email address and username placeholders. Be aware the passwords I have set translate to “secreths” if you want to authenticate with them. From the command line you do this to import the ldif file:

# ldapadd -x -D "cn=Manager,dc=<domain>,dc=com" -W -f example.ldif

If you wish, you can use Apache Directory Studio to connect to this LDAP server and check the structure. It’s very simple to use and the best part is it’s free.

Once you’re satisfied with your LDAP server, you can move on to configuring Alfresco to communicate with this LDAP server.

Open alfresco-global.properties and add these settings:

authentication.chain=alfrescoNtlm1:alfrescoNtlm,ldap1:ldap # Tells Alfresco to add LDAP to the authentication chain.

ldap.authentication.active=true
ldap.authentication.java.naming.security.authentication=simple
ldap.authentication.userNameFormat=cn\=%s,ou\=people,dc\=<domain>,dc\=com
ldap.authentication.java.naming.provider.url=ldap://<domain>.com:389
ldap.authentication.allowGuestLogin=false
ldap.authentication.escapeCommasInBind=false
ldap.authentication.escapeCommasInUID=false

# Below this we set up the synchronization to run. If you update your OpenLDAP, the changes in Alfresco will be reflected when the synchronization is run.
ldap.synchronization.active=true
ldap.synchronization.java.naming.security.authentication=simple
ldap.synchronization.java.naming.security.principal=cn\=Manager,dc\=<domain>,dc\=com
ldap.synchronization.java.naming.security.credentials=secret

ldap.synchronization.groupSearchBase=ou\=groups,dc\=<domain>,dc\=com
ldap.synchronization.groupType=groupOfNames
ldap.synchronization.groupQuery=(objectclass=groupOfNames)
ldap.synchronization.groupMemberAttributeName=member

ldap.synchronization.userSearchBase=ou\=people,dc\=<domain>,dc\=com
ldap.synchronization.userIDAttributeName=uid
ldap.synchronization.personQuery=(& (objectclass\=inetOrgPerson) (uid\=*))
ldap.synchronization.personType=inetOrgPerson

Save the global properties file and restart Alfresco. You should now be able to log in with any of the users that you put in your ldif file.

Cheers! – H.S.

Installing Alfresco (4.1.1) with JBoss (EAP 5.1.1)

With your Alfresco install you may have decided that Tomcat as an application server is not robust enough. You can opt for WebSphere, WebLogic and even JBoss if you feel you require the extra functionalities. This article addresses how to install Alfresco with JBoss.

First, you’ll need the JBoss installer. I had to get mine at access.redhat.com. Keep in mind though, Alfresco still only supports 5.1.1 EAP (enterprise version of JBoss). My installer looks like this file: jboss-eap-installer-5.1.1.jar.

I also went out and got the Java JDK 1.6.0_33 to use with this. For this installation I used Alfresco Enterprise 4.1.1. You’ll want to get the .ear file for this instead of the usual .zip file you get for Tomcat.

So, getting started, install the JDK to the directory of your choice. I have to install a number of different versions of Java, Alfresco, Tomcat and JBoss so I tend to have a top level directory with each of those names and then install the particular version beneath it. My installation of Java and JBoss look this respectively:

  • /java/jdk1.6.0_33
  • /jboss/jboss-eap-5.1

Install JBoss is fairly simple. You simply run the following:

# <path_to_jdk1.6.0_33>/bin/java -jar jboss-eap-installer-5.1.1.jar

To make it simple, I’ll refer to JBOSS_HOME as my jboss directory:

/jboss/jboss-eap-5.1/jboss-as

Follow the instructions and install it. Next, put alfresco-enterprise-ear-4.1.1.zip into a tmp directory and unzip it. You’ll also have to “unzip” the resulting alfresco-enterprise-ear.4.1.1.ear. If you need to, you can change the .ear extension to .zip to get the unzip to work.

Copy the alfresco-global.properties.sample file from the temporary directory to the <JBOSS_HOME>/server/default/conf directory as alfresco-global.properties minus the .sample on the end.

Make sure you refer to this article on how to set up your repository. Remember that you’ll need to create a database, modify it for Alfresco use and set up a directory to use for your contentstore and indexes. Edit the parameters in the alfresco-global.properties.sample file to suit your environment. Save the alfresco-global.properties in the conf dir.

Here are my settings. Please adjust to reflect your environment. Make sure these lines are added in your alfresco-global.properties file:

dir.root=/srv/4119jboss/alf_data
dir.license.external=/jboss/jboss-eap-5.1/jboss-as/server/default/conf/alfresco/extension/license
db.username=alfresco
db.password=alfresco
ooo.exe=/alfresco/4119/openoffice/program/soffice.bin
ooo.enabled=false
ooo.port=8100
img.root=/alfresco/4119/common
img.dyn=${img.root}/lib
img.exe=${img.root}/bin/convert
swf.exe=/alfresco/4119/common/bin/pdf2swf
swf.languagedir=/alfresco/4119/common/japanese
jodconverter.enabled=true
jodconverter.officeHome=/alfresco/4119/openoffice
jodconverter.portNumbers=8100
db.driver=org.gjt.mm.mysql.Driver
db.url=jdbc:mysql://localhost/alf4119jboss?useUnicode=yes&characterEncoding=UTF-8
index.subsystem.name=lucene
index.recovery.mode=FULL
alfresco.context=alfresco
alfresco.host=${localname}
alfresco.port=8080
alfresco.protocol=http
#
share.context=share
share.host=${localname}
share.port=8080
share.protocol=http
alfresco.rmi.services.host=0.0.0.0

Copy the alfresco.war and share.war file from the tmp directory to the <JBOSS_HOME>/deploy directory
Copy database jdbc driver to <JBOSS_HOME>/server/default/lib
Add URIEncoding=”UTF-8″ to Connector stanzas for 8080 and 8009 in both of these files:

  • <JBOSS_HOME>/server/default/deploy/jbossweb.sar/server.xml
  • <JBOSS_HOME>/server/all/deploy/jbossweb.sar/server.xml

JBoss by default can have a lot of debug entries in the logs. To squelch this a bit, edit the <JBOSS_HOME>/server/default/conf/jboss-log4j.xml file to reduce the huge debug log output:

<root>
 <priority value="INFO" />
 <appender-ref ref="CONSOLE"/>
 <appender-ref ref="FILE"/>
</root>

Add these log settings to the <JBOSS_HOME>/server/default/conf/jboss-log4j.xml file:

<category name="org.jboss.logging.Log4jService$URLWatchTimerTask">
 <priority value="INFO"/>
</category>
<category name="org.jboss.system.server.Server">
 <priority value="INFO"/>
</category>
<category name="org.jboss">
 <priority value="WARN"/>
</category>
<category name="net">
 <priority value="WARN"/>
</category>
<category name="org.alfresco">
 <priority value="WARN"/>
</category>
<category name="org.alfresco.repo.policy">
 <priority value="WARN"/>
</category>
<category name="org.springframework">
 <priority value="WARN"/>
</category>
<category name="org.hibernate">
 <priority value="WARN"/>
</category>
<category name="org.hibernate.cache.ReadWriteCache">
 <priority value="ERROR"/>
</category>
<category name="org.hibernate.cache.EhCacheProvider">
 <priority value="ERROR"/>
</category>
<category name="org.hibernate.engine.StatefulPersistenceContext.ProxyWarnLog">
 <priority value="ERROR"/>
</category>
<category name="org.apache.myfaces">
 <priority value="ERROR"/>
</category>
<category name="org.jbpm.jpdl.xml.JpdlXmlReader">
 <priority value="ERROR"/>
</category>

Save this file and next, edit the <JBOSS_HOME>/server/default/deployers/ejb3.deployer/META-INF/jpa-deployers-jboss-beans.xml file, and then change the hibernate.bytecode.provider=javassist line to hibernate.bytecode.provider=cglib.

For example:

<entry>
 <key>hibernate.bytecode.provider</key>
 <value>cglib</value>
</entry>

Add these to your <JBOSS_HOME>/bin/run.sh file near the top:

export JAVA_HOME=/alfresco/4119/java
JBOSS_CLASSPATH="/jboss/jboss-eap-5.1/jboss-as/server/default/conf"

Then, after this line:

JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=true"

add these:

JAVA_OPTS="$JAVA_OPTS -Xms512m -Xmx1024m -XX:MaxPermSize=512m"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -Dalfresco.home=."

Edit the filtered packages list.

Open the <JBOSS_HOME>/server/default/deployers/jbossweb.deployer/META-INF/war-deployers-jboss-beans.xml file, and then locate the filteredPackages property of the WarClassLoaderDeployer bean.

Open the <extension>\war-deployers-jboss-beans.xml.fragment.sample file.
This sample file contains a WarClassLoaderDeployer bean definition fragment for use when configuring JBoss.

Copy the full WarClassLoaderDeployer bean from the sample file.
In the war-deployers-jboss-beans.xml file, paste the sample bean fragment over the WarClassLoaderDeployer bean. The bean definition contains the filteredPackages list that is required for Alfresco. This list is on one line and must not contain any breaks.

Save the <JBOSS_HOME>/server/default/deployers/jbossweb.deployer/META-INF/war-deployers-jboss-beans.xml file.

Now, the moment of truth. Go to JBoss Server <JBOSS_HOME>/bin and do:

# ./run.sh -b 0.0.0.0  <- This will allow JBoss to bind to all ip addresses. 
*Change it to suit your environment if needed.

The alfresco.log file will be generated wherever you start it. So if you are in <JBOSS_HOME>/bin you should see it there. You can “tail” the file and follow along. Work through any issues. Try to access it like you would any other Alfresco install (http://<hostname>:<port>/share) and voila! Success! Hopefully 😉

Cheers! -H.S.