Tuesday, June 19, 2018

Alfresco: How to Overwrite Node Created Date

The Alfresco cm:created property is a protected field.  It normally can't be changed.
For example, the following simple JavaScript code tries to change the created date property to January 31, 2012.  It actually runs with no error, but when you check for the value of the property on the node during the same transaction, it appears to be set.

But query the property again or look at the value in the Node Browser and you'll find that it hasn't changed.

var dir = "Sites/swsdp/documentLibrary/Presentations/Project Overview.ppt";
var node = companyhome.childByNamePath(dir);

// Change the created date
var jan312012 = new Date(2012, 0, 31);
node.properties["cm:created"] = jan312012;

Sometimes it's desirable to be able to change the created date of the node.  This is especially useful when content is being migrated from another source into Alfresco and the creation date from the other system needs to be preserved in Alfresco.

Using the Alfresco Java API, it's possible to work around the problem.  To do that, we'll create the following Java method which can be called from Alfresco JavaScript. It will allow us to run any JavaScript method as user System.  It's a dangerous method to have around since it can run with no restriction, so it would be good practice  to package it separately and use it only for situations that warrant its use.

Create and compile the Java file com/formtek/example/util/RunAsSystem.java:

package com.formtek.example.util;

import org.alfresco.repo.jscript.BaseScopableProcessorExtension;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.mozilla.javascript.Context;
import org.alfresco.model.ContentModel;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;

import org.alfresco.repo.policy.BehaviourFilter;

public class RunAsSystem extends BaseScopableProcessorExtension 
    protected BehaviourFilter behaviourFilter;
    public void setBehaviourFilter(BehaviourFilter behaviourFilter)
      this.behaviourFilter = behaviourFilter;

    public void exec(final Function func) {
        final Context cx = Context.getCurrentContext();
        final Scriptable scope = getScope();
        RunAsWork<Object> raw = new RunAsWork<Object>() {
            public Object doWork() throws Exception {
                func.call(cx, scope, scope, new Object[] {});
                return null;
        AuthenticationUtil.runAs(raw, AuthenticationUtil.getSystemUserName());

Then wire this file into Alfresco with the file alfresco/extension/runas-context.xml:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
    <bean id="com.formtek.RunAsSystem" parent="baseJavaScriptExtension" class="com.formtek.example.util.RunAsSystem">
      <property name="extensionName">
   <property name="behaviourFilter" ref="policyBehaviourFilter" />

With that in place, it is possible then to write the following JavaScript:

function doit()
 // Find a test node
 var dir = "Sites/swsdp/documentLibrary/Presentations/Project Overview.ppt";
     var node = companyhome.childByNamePath(dir);
 // Change the created date
 var jan312009 = new Date(2009, 0, 31);
 node.properties["cm:created"] = jan312009;

The method ftk.exec() will run any JavaScript method as user System.
In this example, it changes the creation dates on one of the standard sample documents that comes with Alfresco.

Wednesday, May 2, 2018

How to Connect to Alfresco with JConsole for JMX Access

The most straight-forward and basic way to make configuration changes in Alfresco is to stop Alfresco. Open alfresco-global.properties file (in tomcat/shared/classes sub-directory), make settings changes, save them and then start Alfresco. If you are making long-term changes to a production environment, this is the best way to go about doing that. However, before you can make these well-thought-out changes to production, it is a good idea to test them first in a test, staging or QA environment. But making changes to the configuration in global properties can be a bit time consuming. Were you aware that you can make most changes to Alfresco using JMX without a restart? Most Java applications do allow for this if they have enabled the JMX protocol.

The Java Management Extension (JMX) interface allows you to make changes to Alfresco Content Services through a JMX client that supports JMX Remoting (JSR-160). This client called JConsole allows you to:

  • Manage subsystems (includes many configuration setting changes)
  • Change log levels
  • Enable or disable file servers (FTP/CIFS)
  • Set the server to read-only mode
  • Set the server to single-user mode
  • Set server maximum user limit, including ability to prevent further logins
  • Count user sessions/tickets
  • User session/ticket invalidation

Setting up Alfresco for JMX connections

In order to allow for Alfresco to make use of JMX, we'll need to add a few settings to a Alfresco.

In alfresco-global.properties we add:


For alfresco.rmi.services.host, make sure you are setting a hostname that is externally and internally resolvable. When you start Alfresco, you can make sure that JMX is enabled by running in Linux:

# sudo lsof -i :50500
java    13248 root  552u  IPv6 13356213      0t0  TCP *:50500 (LISTEN)

You should of course, see a running process listening on 50500.

Running JConsole

If you happen to have GUI access on the server you are running Alfresco, you can run the following to start jconsole:

If you have a full JDK installed, you can typically run:

# jconsole


# java/bin/jconsole

If using Alfresco's JRE:

# java/bin/java -jar java/lib/jconsole.jar

If you can pull up jconsole, you can typically connect to Alfresco using the Local Process option. This won't require a long and complex URL or username/password. If you use the jconsole executable, you choose Local Process (make sure you select the running Tomcat process)

Next, you'll see a pop-up box showing insecure connection. Go ahead and click on the Insecure connection button.

Once it starts up, you'll see the start up window.

Click on the MBeans tab at the top and you should then see the Alfresco drop-down line.

If you have to use the Alfresco JRE, you will first need to add the JMX url and a username/password combo to get in.

You will need to add the following:

  • URL: service:jmx:rmi:///jndi/rmi://localhost:50500/alfresco/jmxrmi
  • Username: controlRole
  • Password: change_asap

Keep in mind that these are the default properties. It is possible that maybe an admin may have changed the username and passwords. In that case, you'll need to have a look through these files to get that information:

  • alfresco-jmxrmi.password
  • alfresco-jmxrmi.access

Keep in mind that this process will also allow you to connect to a remote Alfresco server provided you are on the same network.

Now, if your Alfresco install is in an AWS environment, you will need to follow a little bit of a different process. For reasons I don't fully understand, jconsole seems to have a difficult time making a direct connection to Alfresco running in AWS. What I've found that works is using an ssh tunnel to get to it.

To get this to work, you can run ssh client using a console on your workstation:

# ssh -D 1234 username@hostname

Next, you can run jconsole using a socket proxy:

# jconsole -J-DsocksProxyHost=localhost -J-DsocksProxyPort=1234

Note that this also works with jvisualvm:

# jvisualvm -J-DsocksProxyHost=localhost -J-DsocksProxyPort=1234

For jconsole, you then would fill in the rest of the URL, username and password in the dialog box and you should be able to get in.


Wednesday, April 18, 2018

Alfresco Share: Build New Share Pages with Familiar Tools

Standard Alfresco Share is based on standard HTML, CSS and Javascript, but it also uses a number of frameworks and tools, like Alfresco Surf, Alfresco Aikau, YUI2 JS framework, the Dojo Toolkit and Freemarker. Knowing about Java and the Spring Framework will help too.  All those different technologies could be a barrier to getting started with Share development.

Granted, if you build new pages in Share, you'll probably want to reuse standard Share components, like the header, footer, menus, etc.  In that case it makes sense to stick with using Share technologies.

But you might be interested in knowing that you can build and wire in a web page that interoperates with other pages in Alfresco Share using totally different technologies.

Let's look at what is needed to build a page that works in Alfresco Share but which is built using JSP, for example.  We can't totally escape the Surf configuration.  But we only need three files to define the Share page: page, template-instance and template-type. The files are relatively small.


<?xml version='1.0' encoding='UTF-8'?>
   <title>Share JSP Page</title>
   <description>Share JSP Page</description>


<?xml version='1.0' encoding='UTF-8'?>


<?xml version="1.0" encoding="UTF-8"?>
    <title>Share JSP Page</title>
 <description>Custom page for Alfresco Share</description>
 <processor mode="view">

That's it!  Now let's define the content for the JSP page.  The JSP file needs to go within the Share expanded WAR area.  The location and file is defined by the template-type definition.


<%--  Custom Alfresco Share JSP Page Example --%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 
<%@ page import="org.alfresco.web.site.*" %>

    String ShareHome = "http://localhost:8080/share/page";

    // Retrieve user name from the session
    String userid = (String)session.getAttribute(SlingshotUserFactory.SESSION_ATTRIBUTE_KEY_USER_ID);
    out.println("<center><h1>" + userid + "!  Welcome to a Custom JSP Page</h1></center>"); 
    out.println("<center><img src=\"https://svn.alfresco.com/repos/alfresco-open-mirror/alfresco/HEAD/root/projects/web-client/source/web/images/logo/alfresco3d.jpg\" /></center>"); 
    // Set up a button to navigate to another authenticated Share page
    out.println("<input type=\"button\" value=\"Return to Share Home\" onclick=\"window.location.href='" + ShareHome + "'\" />");

And finally, here is the rendered custom JSP page within Share:

The new page obeys Share authentication.  For example, if you enter the URL to the page when you're not logged into Share, you will be first redirected to the standard Share login page.

On the client page in the browser, by using the proxy URL to the Alfresco repo, calls can be made to the Alfresco repo REST API with Javascript/AJAX.  Within the JSP page on the server, Java HTTP requests calls can be made to the Alfresco repo, just remember to pass along the JSESSIONID cookie from the page as part of your request to enable authentication.

Tuesday, April 3, 2018

Alfresco - How to create a custom Admin Console Component

If your extension module needs an Administration interface, you can add a custom Admin Console Component to manage your module. The Admin Console is composed of default administration pages. Each Admin Console page is a simple web script component built from a library of useful functions and macros that are imported into each Admin Console web script.

The custom Admin Console component can be added by implementing a repository web script. In this example we will add a custom component under a new section called “Formtek”. The “General Information” custom page displays the Formtek Root Directory Path and the Formtek Modules installed.

To have the new component listed under the Formtek section we will have to store the web script files in a specific directory path - org/alfresco/enterprise/repository/admin/zformtek.

The web script descriptor file shown below automatically adds this custom component to the Admin Console. In the web script descriptor file the url, family and the authentication tag values are very important. The Admin Console is available only in the Alfresco Enterprise edition and only an Administrator can access it so the url has to begin with /enterprise/admin, the custom component needs to belong to the AdminConsole family and the authentication has to be set to admin.

In the web script controller, we have to inform the Admin Console system which MBean and its properties we want to use in our custom component. In this custom component we are using the ModuleService MBean to get the list of installed modules.
The web script template contains the page layout. For this custom component it loops through the list of installed modules and displays only the Formtek modules. The template uses a number of resource properties that are fetched using the msg function.

The resource properties should be defined in a web script resource file.

Tuesday, March 13, 2018

What Happened to My Alfresco Simple Modules?

Alfresco supports two methods for packaging Repository and Share extensions:

  • Alfresco Module Package (AMP)
  • Simple Module

The Simple Module method makes use of JAR files and has the advantage of not having to modify the alfresco.war and share.war files as is required by the AMP method.

The Formtek Extensions for Alfresco (Auditing, File Linking, Peer Association, and Version Browser) are all installed as Simple Modules and each contain Repository and Share extensions. The Repository extensions are bundled in a JAR file that is placed in the modules/platform directory, where as the JAR file with the Share extensions is placed in the modules/share directory.

When Alfresco starts up, it checks for JAR files in these two directories to see if there are any modules to load. If a module is found, it is loaded and subjected to any required checks, such as its dependent Platform and Share versions. If it passes these checks, the module is started.

So far, so good. Well, most of the time. On multiple occasions when I restarted my Alfresco installation, my Simple Modules failed to load even though they had not changed since the last successful startup. For me, it seemed the Repository extensions were not being found. It is was as if the Alfresco startup process wasn't even looking in the modules/platform directory anymore. The first time this happened I figured I had done something wrong and messed up my Alfresco installation. But when it happened a third and fourth time, I began my investigation.

I figured some Tomcat-related file in my installation is telling (or should be telling) Alfresco to look in the modules/platform directory on startup for JAR files to load. I eventually landed in the tomcat/conf/Catalina/localhost directory and discovered it only contained two files: share.xml and solr4.xml. When I compared this to another installation I had that was working fine, I found that I was missing the alfresco.xml file.

Indeed, it is the alfresco.xml and share.xml files that tell Alfresco where to look for Simple Modules as follows:

<?xml version='1.0' encoding='utf-8'?>
<Context crossContext="true">
  <Loader className="org.apache.catalina.loader.VirtualWebappLoader" virtualClasspath="${catalina.base}/../modules/platform/*.jar" />

<?xml version='1.0' encoding='utf-8'?>
<Context crossContext="true">
  <Loader className="org.apache.catalina.loader.VirtualWebappLoader" virtualClasspath="${catalina.base}/../modules/share/*.jar" />

Once I recreated the missing alfresco.xml file and restarted Alfresco, my Simple Module Repository extensions loaded and started just fine. What I have yet to determine, however, is why the file was missing in the first place? But, at least I now know how to fix it should it reoccur.

NOTE: If you've deviated from the traditional Alfresco installation and placed your modules directory elsewhere, it is worth noting that you will need to edit the virtualClasspath location in these two files to match your installation.