Skip navigation
All Places > Alfresco Content Services (ECM) > Blog
1 2 3 Previous Next

Alfresco Content Services (ECM)

366 posts

We’ve received your feedback since we took the AddOns site offline on May 25th and I can appreciate people’s disappointment in seeing this resource being seemingly taken away, especially for those Community members who’d worked hard on creating AddOns.

 

I wanted to pause and answer to some of the questions that have come up in the community since:

 

Why did we take the site offline?

During an internal audit of all of our sites and systems ahead of GDPR we found out that there were some serious problems with the AddOns site security. The AddOns site stored personally identifiable information and with GDPR compliance looming, we took the difficult decision to take the site offline.

 

What we’re doing now

In the next 5-10 days, we’re going to create a version of the AddOns directory inside of the existing Alfresco Community website and import the previous add-ons to that space. Kristen Gastaldo is working on that, so expect to see some content in the next few days.

 

What we’re doing in the future

We’re currently gaining momentum internally on building what is next for an Alfresco AddOns / Extensions directory and we’d like to hear from you on how we can make it bigger and better than the AddOns site that went before.

Unfortunately we’ve had to temporarily remove access to addons.alfresco.com - we understand that you may be disappointed, we’re working on bringing it back in a read-only mode whilst we work out what the next steps for the Alfresco AddOns Community.

 

We’d love to hear more from you on your thoughts on how we can move AddOns forward as we begin planning the next evolution of the Alfresco Community we kindly invite you to contact us with a message. We will do our best to face and solve the issue as soon as possible. We sincerely hope that this won't cause problems to anyone. If it will happen, we apologise in advance.

 

Update of 7th of June - You can find the draft of the static list at Alfresco Addons *Incomplete list* 

 

About Alfresco AddOns

 

If you have ever customised or extended Alfresco Content Services (and/or Alfresco Share), you might have found a website called addons.alfresco.com. Alfresco Add-on website is a large collection of customisations and extensions for the Alfresco platform, contributed by the company's global developer community. The Alfresco Add-on website was designed to be a one-stop shop for Alfresco users looking to extend the functionality of Alfresco with pre-built modules.

 

The Alfresco Add-on website has been active since 2012 and since the beginning it grew rapidly, hosting several hundreds of different projects: Open Source and Proprietary, developed by Alfresco official partners or Community enthusiasts, supported or "given as is" in terms of production readiness. From this point of view, the initiative has been a success and a positive achievement of the entire Alfresco ecosystem (Alfresco as a Company, partners, customers, users, enthusiasts, etc.).

 

Most of the Alfresco enthusiasts agree that a sort of "Alfresco Marketplace" would be something useful for everyone, even if some concerns were around since a long time about the (proven) level of maturity of the (oldest) releases of the projects with the newest versions of Alfresco Content Services (and Alfresco Share). In addition to that, an improved experience in searching and installing the add-ons were something suggested, but never discussed and defined with enough details.

 

Today the GDPR is forcing us to the decision to put the Alfresco Add-on website in stand-by mode, until its future version will be defined and re-launched again. Looking forward to start the discussion around the next version of the Alfresco Marketplace, Add-on mechanism or whatever it will be.

Alfresco is delivering a Docker Compose for ACS Community deployment that can only be used for local testing environments:

 

acs-community-deployment/docker-compose at master · Alfresco/acs-community-deployment · GitHub 

 

In order to deploy the product in real environments, some additional configurations must be performed. You can find some of this configurations described at Using Alfresco 201804-EA in a simple PROD environment 

 

However, as it should be advisable to maintain original Alfresco resources untouched, another approach is required. Docker Compose allows to share configuration by using additional YML specification files to override the original one. Below some instructions to configure default Alfresco Docker Compose for ACS 6 Community are provided.

 

Checkout or download official Docker Compose

 

$ git clone git@github.com:Alfresco/acs-community-deployment.git
Cloning into 'acs-community-deployment'...
remote: Counting objects: 145, done.
remote: Compressing objects: 100% (91/91), done.
remote: Total 145 (delta 79), reused 103 (delta 49), pack-reused 0
Receiving objects: 100% (145/145), 27.53 KiB | 240.00 KiB/s, done.
Resolving deltas: 100% (79/79), done.

$ cd acs-community-deployment/docker-compose/

$ ls
docker-compose.yml

 

Create a docker-compose.override.yml file

 

You can add volumes mapping, ports exposition and additional Docker images to original Docker Compose.

 

$ touch docker-compose.override.yml

$ cat docker-compose.override.yml
version: "3"

services:

    httpd:
        build: ./httpd
        ports:
          - 443:443
        links:
          - alfresco
          - share
          - solr6 

    alfresco:
      volumes:
          - ./data/alf-repo-data:/usr/local/tomcat/alf_data
      ports:
          - 21:2121

    postgres:
      volumes:
          - ./data/postgres-data:/var/lib/postgresql/data

    solr6:
      volumes:
          - ./data/solr-data:/opt/alfresco-search-services/data

 

Add your customised images

 

Adding an NGIX or Apache HTTPd server should be recommendable for many environments.

 

$ tree httpd
httpd
├── Dockerfile
└── assets
    ├── CA.pem
    ├── alfresco-vhost.conf
    ├── server.crt
    └── server.key

 

You can use something provided by the Community like this one, or any other you like.

 

Start the composition

 

You can use default commands to run Docker Compose.

Extensions declared in docker-compose.override.yml file will be picked automatically, so your volumes, ports and additional Docker images will be available in the composition.

 

$ docker-compose up -d --build

 

Now Alfresco is running in a real environment by using official (and untouched) Docker Compose resource.

It is time, at last, to announce the release of the Records Management Community 2.7.b, which follows 2.7.a from February and brings improvements over the existing features, mostly on auditing events and on the search results.

 

What's in 2.7.b?

In this release, we have focused more on fixing audit bugs, for instance, event filtering (RM-5794, RM-5234), logging user creation and deletion (RM-5235) and logging group events (RM-5236).

 

Another noteworthy improvement is that we have also fixed a security issue (RM-6275) and a few bugs on the search feature, including GROUP_EVERYONE disappearing from search results after installing RM module (RM-2504).

 

Also on the records search results, we have introduced a new component in the metadata, the Record Category Identifier that refers to the record category that is the first in the record primary parental hierarchy (RM-6137).

For those who missed the wiki pages, now they can enjoy the feature again as the bug of not being able to create new pages has been fixed (MNT-19114).

 

What's coming up next?

 

Most significantly, compatibility with community release of ACS 6.0.x is our priority for the next release in AGS 3.0.a, and as usual we will continue to keep you updated on this.

 

We are really interested to hear about your feedback on 2.7.b or on anything that you would like to see in our future releases. You may use both the comments below or consider writing a message to any of the team members.

 

Links

 

A while ago, Alfresco decided to replace the Ghostscript engine in our products. It has been used as a rasteriser to transform PDF files to PNG images within Alfresco Content Services (ACS). The main cause was due to Ghostscript’s change to an AGPL license, which caused some concerns among our customers and limited us in the way how we could distribute ACS.

 

Alfresco Engineering was tasked to evaluate different options for PDF rendition under a permissive open source license. Unfortunately, we found almost no independent performance and fidelity comparison between the different engines out there — especially no study that is thorough enough to base such a decision on. Since the new engine will be used as the default in our next version of ACS, it would have the potential to cause severe problems for our customers if it fails either due to poor performance or poor fidelity.

 

In the end, we decided to do this study ourselves. With this blog post, we want to share our results with you.

 

Market Overview

After research on Wikipedia and Google, our team came up with this list of PDF rendering engines:

EngineLicenseNotes
GhostscriptAGPLv3 or CommercialFull PostScript interpreter. Can also handle PDF files.
MuPDFAGPLv3 or CommercialPDF, XPS and EPUB rendering engine based on the modern high performance Fitz graphics engine
Adobe PDF Library SDKCommercialOriginal Adobe PDF engine.
Foxit SDKCommercialEngine behind the Foxit PDF reader products.
Fork released under BSD license as Pdfium by Google.
PdfiumBSD styleEngine behind PDF Plug-In in Chrome.
Fork of the Foxit SDK.
PopplerGPLv2 or GPLv3Fork of XPdf
XpdfGPLv2 or CommercialPDF viewer for X-Windows & PDF Rasterizer for all platforms (pdftopng). 
GnuPDFGPLv3
PDFBox 2.0Apache 2.0
SejdaAGPLv3 or Commercial
IcePDFApache 2.0 and Commercial Pro version
Aspose PDFCommercial

(Note: There are multiple PDF Reader products out there, but this is the consolidated list of PDF rendering engines behind these products)

 

The Candidates

Given our constraints on license terms and other factors, we decided to start our deep and thorough investigation with this list of candidates. We included some leading proprietary libraries for reference.

EngineTypeVersion
GhostscriptNative9.21
MuPDFNative1.10a
XpdfNative3.04
PdfiumNative2017-04-10
AsposeJava17.2.0
ICEPdfJava6.2.0
SejdaJava3.0.13
PDFBoxJava2.0.5

The version numbers are the latest released version at the time of our investigation.

 

Performance

Ghostscript has been used until ACS 5.1 to render all PDF files to PNG images for things like thumbnails. Most other file formats, like MS Office files, are converted to PDF first for previewing and then the PDF is converted to PNG. In our analysis, we have been interested in the average overall performance.

Our team randomly picked 3071 PDF documents (17,226 pages) from our internal Alfresco Repository to get a sample set representing a typical ACS repository. We are aware that there are ACS installations out there that mainly contain documents of one specific kind, but we are confident that our sample set represents the majority of ACS repositories.
To compare the performance, we rendered all documents to PNG files at 100 dpi. Each engine was configured to produce results at comparable fidelity (e.g. by activating anti-aliased text and graphics) and we guaranteed the same resources to each engine. For all Java based engines, we kept the JVM running and invoked the rendition for each document in the same JVM process, enabling Hotspot to best optimise the generated native code.
This led to the following total process times:

Rendition times of different PDF engines

(total rendition time; smaller is better)

 

We played with different dpi settings to see how the results would change. We found that the relative difference between engines is affected by the resolution (dpi), but the order in which the candidates ranked stayed the same across different dpi settings (except for close candidates).

 

Our key findings are:

  • Native engines are always faster than Java based engines
  • MuPDF is clearly the fastest engine
  • Pdfium comes in second, but is significantly slower than MuPDF

 

Features  and Fidelity

Because our new transformation engine will be used for a server based rendition of PDF documents to PNG files, all interactive features like form filling, signature validation, video or 3D were out of scope for our investigation.

 

Based on the latest PDF specification, we compiled a list of features that are provided by the PDF drawing model. For each feature, we picked a sample document for testing or created such a document ourselves. The rendition of these sample documents was then visually compared and rated. We used the latest Adobe Acrobat Reader as our reference viewer.

 

Text rendition and font support

 

Text  rendition & font support

Ghostscript

MuPDF

Xpdf

Pdfium

Aspose

ICEPdf

Sejda

PDFBox

Type1

4

5

4

5

1

1

4

4

TrueType

4

5

4

5

4

0

5

5

Type1 CID

yes

yes

yes

yes

yes

no

yes

yes

TrueType CID

yes

yes

yes

yes

yes

no

yes

yes

Type3

3

5

6

6

1

0

1

1

AVG

3.67

5

4.67

5.33

2

0

3.33

3.33

 

We awarded 0 to 5 points for each rendition compared to the Acrobat reference. In two situations, we awarded an extra point for visually better results than Acrobat.

(click to enlarge)

 

Images

PDF supports 6 different “filters” (i.e. compression formats) that can be used to store raster graphic data. The decoded raster graphic then needed to be mapped to the pixels of the rendered output graphic. This process has a huge impact on the final visual result.

 

Images

Ghostscript

MuPDF

Xpdf

Pdfium

Aspose

ICEPdf

Sejda

PDFBox

Anti Aliasing

no

yes

yes

yes

no

partial

no

no

CCITTFaxDecode

yes

yes

yes

yes

yes

yes

yes

yes

DCTDecode

yes

yes

yes

yes

yes

yes

yes

yes

LZWDecode

yes

yes

yes

yes

yes

yes

yes

yes

FlatDecode

yes

yes

yes

yes

yes

yes

yes

yes

JPXDecode

yes

yes

yes

yes

no

partial

no

no

JBIG2Decode

yes

yes

yes

yes

yes

yes

partial

partial

SUM Image

3

5

5

5

2

2

1

1

 

Every engine starts with 5 points. We removed 1 point for each missing filter support and we removed 2 points for non-working anti aliasing.

 

Drawing model

We noticed that the atomic drawing operations (MoveTo, LineTo, CurveTo) and shading models are supported almost equally in all candidates. Visually different results on complex drawings are mainly caused by the composition of these atomic building blocks, and not by the basic operations themselves.

This is why we decided to focus on the composition of drawing operations for our comparison.

 

Compositing and Blend Modes

PDF supports 16 different blend modes. These can either be applied to single objects or to multiple objects in a transparency group. Each blend mode affects the image channels individually and thus produces different results in different colour spaces (RGB, CMYK).
We used a set of test and reference PDF files (link these two for RGB and CMYK) and counted the errors made by each engine. We then used the relative number of errors to assign points, with 5 points being awarded for the fewest errors averaged over all test files and 0 points representing lots of errors. Here are the final results:

 

Blend Modes

Ghostscript

MuPDF

Xpdf

Pdfium

Aspose

ICEPdf

Sejda

PDFBox

AVG

3.33

3.33

3

2

1.67

1

2

2

 

Fidelity results

Combining all of the above gives the following results for features and fidelity:

(rendition fidelity; larger is better)

 

Conclusion

MuPDF came out of this investigation as the clear winner, followed by Pdfium second. It also became apparent that there is big gap between native PDF renderers and the group of Java based PDF renderers — considering performance as well as features and fidelity.

We ended up selecting PDFium as the PDF rasterization engine for these reasons:

  • The BSD-style license of Pdfium gives us and our customers the most flexibility
  • Since this engine drives the PDF display in Chrome, we expect a very good and continued support from Google for this library, especially when it comes to finding and fixing vulnerabilities
  • It shows a very good overall performance, although it is not the fastest engine in the test
  • It shows very good rendition fidelity

 

The Alfresco PDF Renderer

Based on the Pdfium library, we started a new project: the alfresco-pdf-renderer. This native command line program is inspired by the test application used within the Pdfium builds. But it does not provide support for JavaScript and offers additional parameters to specify the size of the output image.

There are great resources inside this Community on how to deploy Alfresco 6 using Docker Compose

Although some real environments will require Kubernetes deployment, many others will be managed with a simple Docker Composition. This post is based in Alfresco 201804-EA release, but these instructions can be applied on many other Alfresco 6 releases.

 

This post includes sample configuration for every point, but you can check detailed and running configuration at 201804-EA Docker template

 

Images

Alfresco 6 provides several Docker Images to build every container for different services:

 

Persistent storage

Docker relies on external storage to persist information. When running an Alfresco server, repository, database and search containers are storing data that needs to be persisted.

A volumes tag must be added in docker-compose.yml file to every container definition to map local storage from your server with logical storage inside the container.

alfresco:
    volumes:
        - alf-repo-data:/usr/local/tomcat/alf_data
postgres:
    volumes:
        - postgres-data:/var/lib/postgresql/data
solr6:
    volumes:
        - solr-data:/opt/alfresco-search-services/data

volumes:
    alf-repo-data:
        external: true
    postgres-data:
        external: true
    solr-data:
        external: true

This code is using named volumes. In case they didn't exists, they can be created by using following shell lines:

$ docker volume create alf-repo-data
$ docker volume create postgres-data
$ docker volume create solr-data

Once this configuration is applied, your data will survive any Docker or Server re-starting.

 

Ports configuration

Docker uses internal ports for containers and it exposes to the server a mapping of these ports. In order to configure Alfresco protocols, ports exposition needs to be declared in Alfresco Repository Dockerfile...

EXPOSE 2121 1143 2525 1445 1137/udp 1138/udp 1139

... and mapping needs to be declared in docker-compose.yml

alfresco:
ports:
- 21:2121      # FTP port
- 25:2525      # SMTP port
- 143:1143     # IMAP port
- 445:1145     # CIFS
- 137:1137/udp # CIFS
- 138:1138/udp # CIFS
- 139:1139     # CIFS

It's also required to open these ports in the firewall of the operative system hosting Docker. 

Once this configuration is applied, your Alfresco server will be accessed by FTP, SMTP, IMAP and CIFS.

 

Web applications ports (AJP 8009 for Alfresco, AJP 8009 for Share and HTTP 8983 for Solr) must be also exposed to configure the Proxy at httpd container.

ProxyPass "/share" "ajp://share:8009/share"
ProxyPassReverse "/share" "ajp://share:8009/share"

ProxyPass "/solr" "http://solr6:8983/solr"
ProxyPassReverse "/solr" "http://solr6:8983/solr"   

ProxyPass "/alfresco" "ajp://alfresco:8009/alfresco"
ProxyPassReverse "/alfresco" "ajp://alfresco:8009/alfresco"

It can be used any other Web Container (as NGINX) to provide such configuration.

Once this configuration is applied, your Alfresco server will be accessed by using the same HTTP Port. In the next point the use of port 443 for HTTPs is detailed.

 

Configuring SSL Certificates

To provide real SSL Certificates, assets folder can be filled with working files:

  • CA.pem - CA Certificate Path
  • server.crt - Certificate File
  • server.key - Certificate Key File

Otherwise, it can be configured an external Docker volume to hold these certificates. 

Listen 443
<VirtualHost *:443>
ServerName alfresco.keensoft.es
SSLEngine on
SSLCertificateFile /usr/local/apache2/conf/server.crt
SSLCertificateKeyFile /usr/local/apache2/conf/server.key
SSLCACertificatePath /etc/pki/tls/certs/
SSLOptions +StdEnvVars +ExportCertData
</VirtualHost>

Once this configuration is applied, your Alfresco server will be accessed by HTTPs.

 

Adding modules

Folders to hold AMP or JAR modules has been provided.

alfresco/target/amps
alfresco/target/jars
share/target/amps_share
share/target/jars

Every addon copied into this folders will be deployed in the container.

If further configuration is required in alfresco-global.properties, Dockerfile can be modified to add pairs of property=value blocks

# Add services configuration to alfresco-global.properties
RUN echo -e '\n\
property=value\n\
\n\
' >> /usr/local/tomcat/shared/classes/alfresco-global.properties

Once this configuration is applied, your Alfresco server will provide features from installed modules.

 

Resources

Before migrating any AMP projects to ACS 6, I recommend to read the blog post about the Anatomy of an ACS 6 AMP module to understand the basics of an AMP project with ACS6.

This article is about modules for the ACS repository and does not cover Share. Although Share uses the same packaging format, extension modules for Share are fundamentally different and will be covered in new blog posts in the future.

This article describes how to migrate Alfresco SDK 2 based projects to plain maven projects, essentially by moving off the Alfresco SDK track. This requires more knowledge about the ACS build process and is not as convenient as using the Alfresco SDK. In Alfresco engineering however, we need to build AMPs before we release a new version of ACS and before the updated Alfresco SDK becomes available. As a third party developer, it might be a lot easier for you to wait for the next version of our official Alfresco SDK.

 

Step 1: Remove parent reference to SDK artifact

With the Alfresco SDK2, it has been required that your projects import a basic project definition by setting a specific pom as parent:

    <parent>
        <groupId>org.alfresco.maven</groupId>
        <artifactId>alfresco-sdk-parent</artifactId>
        <version>2.1.1</version>
    </parent>

This needs to be removed. You can either replace this with your own parent in a multi module project or just have no parent at all.

 

Step 2: Remove dependency management

The SDK2 managed dependencies for you by delegating dependency management to a pom file that got produced during our build:

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>${alfresco.groupId}</groupId>
                <artifactId>alfresco-platform-distribution</artifactId>
                <version>${alfresco.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

This artifact does no longer exist in ACS6. You need to remove this section from your pom file as well.

 

Step 3: Remove H2 artifacts

The H2 database has never been supported officially and got deprecated even for test and development use in 5.0.
With the removal of Hibernate, we fundamentally changed the management of SQL dialects and the required files are no longer available for ACS6.
Remove this dependency:

    <dependency>
        <groupId>${alfresco.groupId}</groupId>
        <artifactId>alfresco-repository</artifactId>
        <version>${alfresco.version}</version>
        <classifier>h2scripts</classifier>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>*</groupId>
                <artifactId>*</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

 

Step 4: Cleanup properties

The SDK2 defined a set of properties that are used in the imported parent pom and various other locations. It is a good idea to at least comment out these properties now and remove them when we are finished migrating this project.
These properties are (among others):

    <properties>
        <alfresco.groupId/>
        <alfresco.version/>
        <alfresco.repo.artifactId/>
        <alfresco.share.artifactId/>
        <alfresco.version/>
        <alfresco.data.location/>
        <app.log.root.level/>
        <env/>
        <alfresco.db.*/>
        <app.amp.*/>
        <maven.tomcat.port/>
        <h2.version/>
    </properties>

This will also help you to identify any pieces that are left over from the SDK2 project setup.

 

Step 5: Configure alfresco-maven-plugin

Now that we no longer import the SDK2 parent pom, the build will fail as it is missing the important configuration required to build AMPs.
If you try to run it like this, it will immediately complain about the unknown packaging type "amp" and that maven does not know what to do with your project.
So you need to add in the alfresco-maven-plugin:

    <properties>
        <app.amp.output.folder>${project.build.directory}/amp</app.amp.output.folder>
    </properties>
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
            <resource>
                <directory>src/main/amp</directory>
                <targetPath>${app.amp.output.folder}</targetPath>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.alfresco.maven.plugin</groupId>
                <artifactId>alfresco-maven-plugin</artifactId>
                <version>2.1.1</version>
                <extensions>true</extensions>
            </plugin>
        </plugins>
    <build>

Since the alfresco-maven-plugin only packages an exploded AMP from the /target folder, we also need to make sure that the content of src/main/amp is copied over and that the app.amp.output.folder is properly set for the plugin.

 

Step 6: Fix dependencies

Now, maven knows how to build your project, but it will start to complain about a lot of missing dependencies and you will most likely see some compile errors. At least, you need to add these dependencies and define the location of our
public maven repository:

    <dependencies>
        <dependency>
            <groupId>org.alfresco</groupId>
            <artifactId>alfresco-repository</artifactId>
            <version>6.37</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.alfresco</groupId>
            <artifactId>alfresco-remote-api</artifactId>
            <version>6.23</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>alfresco-public</id>
            <url>https://artifacts.alfresco.com/nexus/content/groups/public</url>
        </repository>
    </repositories>

From ACS 6 onwards, each artifact is on its own lifecycle. You can look up the version numbers of each artifact either in the release notes or simply take a look in your ACS 6 deployment.
It is important to define each ACS artifact as provided so that it is only used during the compilation of your Java classes, but it is not packaged into the AMP file.

 

You should try to tackle one problem after another. Try to run just the first phase of the build lifecycle:

$ mvn validate

This will tell you if maven is able to read and understand the project object model and if it has all plugins to build it.

 

Next, go a tiny step further and try to compile your code:

$ mvn compile

This will probably give you some errors. It is possible that you are just missing a dependency. If so, try to identify the artifact that contains this class and add it to your project.

Otherwise:

 

Step 7: Refactor your code where required

In ACS6, we have updated almost all dependencies to the most recent feasible version. Some noticeable updates that might affect your custom code are (among others):

  • Spring
  • Quartz
  • POI
  • Jackson
  • multiple commons-* libraries

In addition, we removed some deprecated code like

  • Hibernate

You should see the release notes for a detailed list. If your custom code is using these libraries, it is possible that a class or method got renamed or removed. You need to refactor your code accordingly and sometimes change bean definitions in your custom context files.

Our ACS 6 Migration Guide wiki page on GitHub collects useful information about updating Java code to work with the ACS6 repository.

 

Step 8: Testing part 1: Test code

The Alfresco SDK2 used the H2 database to provide a full ACS repository for unit testing. With ACS6, we now recommend to use unit testing only for small isolated tests. All larger tests that require a ACS repository should be treated as an integration test. See it as an integration of your custom code into the ACS repository.
This means that you need to rename all such *Test classes to *IT. The surefire and failsafe plugins are configured by default to look for test classes with these naming conventions during the test and the integration-test phases and execute them automatically.
If you followed the SDK2 guidelines and used the boilerplate code provided by archetype generator, then your test classes most likely look like this:

@RunWith(RemoteTestRunner.class)
@Remote(runnerClass=SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:alfresco/application-context.xml")
public class DemoComponentTest {
   
    private static final String ADMIN_USER_NAME = "admin";

    static Logger log = Logger.getLogger(DemoComponentTest.class);

    @Autowired
    protected DemoComponent demoComponent;
   
    @Autowired
    @Qualifier("NodeService")
    protected NodeService nodeService;
   
    @Test
    public void testWiring() {
        assertNotNull(demoComponent);
    }
   
    @Test
    public void testGetCompanyHome() {
        AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER_NAME);
        NodeRef companyHome = demoComponent.getCompanyHome();
        assertNotNull(companyHome);
        String companyHomeName = (String) nodeService.getProperty(companyHome, ContentModel.PROP_NAME);
        assertNotNull(companyHomeName);
        assertEquals("Company Home", companyHomeName);
    }
   
}

You can either keep the RemoteTestRunner and simply add it as a dependency:

    <dependency>
        <groupId>com.tradeshift</groupId>
        <artifactId>junit-remote</artifactId>
        <version>3</version>
        <type>jar</type>
        <exclusions>
            <exclusion>
                <artifactId>servlet-api</artifactId>
                <groupId>javax.servlet</groupId>
            </exclusion>
        </exclusions>
        <scope>test</scope>
    </dependency>

Or you can choose to remove the RemoteTestRunner and change the jUnit test  configuration to this:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:alfresco/application-context.xml")
public class DemoComponentTest {

After this step, when you run maven until the test phase

$ mvn test

then it should only execute tests that do not require a Spring Context (i.e. don't require the ACS6 repository).

 

Step 9: Testing part 2: Test environment

Trying to run the integration tests will fail with an error message either complaining that it cannot find the JDBC database driver or some other configuration related problem. The tests can start a ACS6 repository now, but it is yet completely unconfigured.
At first, we need to add this dependency for tests:

    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>9.4.1212</version>
        <scope>test</scope>
    </dependency>

Next, we need to add this configuration for the failsafe build plugin:

    <build>
        <plugins>
            ...
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>2.17</version>
                <configuration>
                    <systemPropertyVariables>
                        <db.name>alfresco-test</db.name>
                        <db.driver>org.postgresql.Driver</db.driver>
                        <db.url>jdbc:postgresql://localhost:${database.port}/alfresco-test</db.url>
                        <dir.root>${project.build.directory}/alf-data-test</dir.root>
                    </systemPropertyVariables>
                </configuration>
                <executions>
                    <execution>
                        <id>integration-test</id>
                        <phase>integration-test</phase>
                        <goals>
                            <goal>integration-test</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    <build>

This configures the ACS repository to store the file content in the folder

    /target/alf-data-test

and use a PostgreSQL database on localhost. To provide this database, we recommend to use docker as we can start a clean DB for every test run automatically. Add this fabric8 docker-maven-plugin to your project:

    <build>
        <plugins>
            ...
            <plugin>
                <groupId>io.fabric8</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>${maven.fabric8.version}</version>
                <configuration>
                    <images>
                        <image>
                            <alias>test-database</alias>
                            <name>postgres:9.4.12</name>
                            <run>
                                <ports>
                                    <port>database.port:5432</port>
                                </ports>
                                <env>
                                    <POSTGRES_PASSWORD>alfresco</POSTGRES_PASSWORD>
                                    <POSTGRES_USER>alfresco</POSTGRES_USER>
                                    <POSTGRES_DB>alfresco-test</POSTGRES_DB>
                                </env>
                                <cmd>
                                    <shell>-c max_connections=300</shell>
                                </cmd>
                                <wait>
                                    <log>database system is ready to accept connections</log>
                                    <time>20000</time>
                                </wait>
                            </run>
                        </image>
                    </images>
                </configuration>
                <executions>
                    <execution>
                        <id>start</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>start</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>stop</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>stop</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    <build>

This pulls the image postgres in version 9.4.12 from DockerHub and starts a new, clean container from this image. After running the integration tests, it stops and removes this image again.
This requires that you have Docker installed and set up properly on your machine.

 

Now you can run maven past the integration tests with

$ mvn verify

 

Conclusion

These steps are just a guideline how to convert existing ACS extension projects to ACS6. They are based on lessons learned from converting our own AMP projects here at Alfresco.
However, all custom AMP projects are different and you might hit completely different problems than we did.
So I want to encourage you to leave comments under this blog post and share your experience. This will help others who experience the same problems as you did.

At first, I want to highlight that an AMP module is not the recommended way to extend or develop against ACS 6. Instead, you should build a (micro-)service that sits next to the repository and use the v1 REST API to talk to the repository.

However, there are certain requirements that cannot yet be met by an extension outside the ACS repository. And, of course, you simply might want to port existing extension projects to ACS 6.

There is also the official "Alfresco SDK" that can help you to jump start extension projects. But this SDK is not updated until after the release of a new ACS version. So we in engineering need to build AMPs independent of the SDK. In this post, I want to share our experiences in the hope that it contains some useful background information.


Basic project structure

We provide plugins for maven to build AMP files. The smallest possible AMP project has a pom.xml file that looks like this:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example.acs-module</groupId>
    <artifactId>my-awesome-module</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>amp</packaging>
    <properties>
        <app.amp.output.folder>${project.build.directory}/amp</app.amp.output.folder>
    </properties>
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
            <resource>
                <directory>src/main/amp</directory>
                <targetPath>${app.amp.output.folder}</targetPath>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.alfresco.maven.plugin</groupId>
                <artifactId>alfresco-maven-plugin</artifactId>
                <version>2.2.0</version>
                <extensions>true</extensions>
            </plugin>
        </plugins>
    <build>
</project>

This defines amp as the packaging type of your project and brings in our alfresco-maven-plugin which provides this packaging. Our plugin is available through maven central so that you do not need to define an additional plugin repository.


Required files

Each AMP project should consist at least of these files:

/my-awesome-module
  |
  +-- pom.xml
  |
  +-- src
       |
       +-- main
            |
            +-- amp
            |    |
            |    +-- module.properties
            |
            +-- resources
                 |
                 +-- alfresco
                      |
                      +-- module
                           |
                           +-- my-awesome-module
                                |
                                +-- module-context.xml

The module.properties file defines this module and helps our module manager to do its job. It basically looks like this:

module.id=my-awesome-module
module.title=My awesome module
module.description=This is an awesome module
module.version=1.0
module.repo.version.min=6.0

The second file is the entry point to the Spring context that makes up the ACS server. You can define new beans in there that will be instantiated during startup and that can be wired up with other components of ACS.


Dependencies

If your project contains Java code, as almost all AMP projects do, then you need to define certain artifacts from the ACS 6 repository as dependencies:

<project>
    ...
    <packaging>amp</packaging>
    <dependencies>
        <dependency>
            <groupId>org.alfresco</groupId>
            <artifactId>alfresco-repository</artifactId>
            <version>6.37</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.alfresco</groupId>
            <artifactId>alfresco-remote-api</artifactId>
            <version>6.23</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <repositories>
        <repository>
            <id>alfresco-public</id>
            <url>https://artifacts.alfresco.com/nexus/content/groups/public</url>
        </repository>
    </repositories>
    <build>
        ...
    <build>
</project>

From ACS 6 onwards, each artifact is on its own lifecycle. You can look up the version numbers of each artifact either in the release notes or simply take a look in your ACS 6 deployment.
It is important to define each artifact as provided so that it is only used during the compilation of your Java classes, but it is not packaged into the AMP file.
If your customization depends on enterprise specific bits, then you need to include the artifacts alfresco-enterprise-repository and alfresco-enterprise-remote-api as well.

Since our artifacts are not always available through maven central, you should add our artifact repository to your build as shown above.


Testing

During the test phase in maven, you should only run isolated jUnit tests that do not require a full ACS repository.
Tests that require a repository, e.g. to create or modify nodes, should be run as integration tests.
The default configuration of the "surefire" (test) and "failsafe" (integration-test) plugins define wildcards for test cases. All classes in src/main/test with a name like *Test are run during the test phase and all classes with a name like *IT are run during the integration-test phase.
Your integration tests then might look like this:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration( { "classpath:alfresco/application-context.xml" } )
@TestExecutionListeners( listeners = { DependencyInjectionTestExecutionListener.class,
                                       MyAwesomeModuleIT.class} )
public class MyAwesomeModuleIT extends AbstractTestExecutionListener
{

    @Autowired
    @Qualifier("NodeService")
    protected NodeService nodeService;

    @Autowired
    @Qualifier("FileFolderService")
    protected FileFolderService fileFolderService;

    @Before
    public void initializeTest()
    {
    }

    @After
    public void cleanupTest()
    {
    }

    @Test
    public void testAwesomeFeature() throws Exception
    {
    }

}

This definition of a jUnit test executes the tests in a Spring environment.The @ContextConfiguration of the spring jUnit runner then loads the main ACS context file which starts up the entire ACS 6 repository.

These jUnit tests require additional dependencies in your pom.xml file:

<project>
    ...
    <dependencies>
        ...
        <!-- test -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.4.1212</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>3.0.6.RELEASE</version>
            <type>jar</type>
            <scope>test</scope>
        </dependency>
    </dependencies>
    ...
</project>

And we need to configure the maven-failsafe-plugin plugin to set the required ACS configuration properties as system properties:

<project>
    ...
    <build>
        <plugins>
            ...
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>2.17</version>
                <configuration>
                    <systemPropertyVariables>
                        <db.name>acs-test</db.name>
                        <db.driver>org.postgresql.Driver</db.driver>
                        <db.url>jdbc:postgresql://localhost:${database.port}/acs-test</db.url>
                        <dir.root>${project.build.directory}/alf-data-test</dir.root>
                    </systemPropertyVariables>
                </configuration>
                <executions>
                    <execution>
                        <id>integration-test</id>
                        <phase>integration-test</phase>
                        <goals>
                            <goal>integration-test</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    <build>
</project>

The configuration above uses a PostgreSQL database on localhost for testing. We suggest to use docker to provide this temporary database instance during the integration tests:

<project>
    ...
    <build>
        <plugins>
            ...
            <plugin>
                <groupId>io.fabric8</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>0.25.0</version>
                <configuration>
                    <images>
                        <image>
                            <alias>test-database</alias>
                            <name>postgres:9.4.12</name>
                            <run>
                                <ports>
                                    <port>database.port:5432</port>
                                </ports>
                                <env>
                                    <POSTGRES_PASSWORD>alfresco</POSTGRES_PASSWORD>
                                    <POSTGRES_USER>alfresco</POSTGRES_USER>
                                    <POSTGRES_DB>acs-test</POSTGRES_DB>
                                </env>
                                <cmd>
                                    <shell>-c max_connections=300</shell>
                                </cmd>
                                <wait>
                                    <log>database system is ready to accept connections</log>
                                    <time>20000</time>
                                </wait>
                            </run>
                        </image>
                    </images>
                </configuration>
                <executions>
                    <execution>
                        <id>start</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>start</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>stop</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>stop</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    <build>
</project>

This pulls the image postgres in version 9.4.12 from DockerHub and starts a new, clean container from this image. After running the integration tests, it stops and removes this image again.
This requires that you have Docker installed and set up properly on your machine.

Introduction

The way you deploy and run the Alfresco Content Services (ACS) solution has changed significantly in version 6.0. Traditionally you would download an installer that would install Java, Tomcat, Database, WARs, tools, etc, and things would be configured to work together. Then you would use a script to kick things off. That’s no longer the case and there are no installers available. We will be working with Docker containers instead.

 

It’s now possible to kick off an ACS 6.0 solution from a number of Docker images. These images are available in the https://hub.docker.com repository. However, kicking off individual Docker containers based on these images, and configuring them to work together, might not be the most productive way to get up and running with ACS. To make things easier, and achieve a one-click to deploy and run solution, a Docker compose file is available to quickly deploy and run the ACS solution when you need to test something or work on a proof-of-concept (PoC).

 

There are also Helm Charts available to deploy the ACS solution in production as a Kubernetes cluster in for example AWS, this is not covered in this article.

Source Code

The source code for this article can be downloaded here. It will become useful when you read the section about creating custom ACS images.

Concepts and Technologies

The following is a list of concepts (terms) and technologies that you will come in contact with when deploying and using the Alfresco Content Services version 6.0. If you know all about Docker, then you can skip this part.

Virtual Machine Monitor (Hypervisor)

A Hypervisor is used to run other OS instances on your local host machine. Typically it's used to run a different OS on your machine, such as Windows on a Mac. When you run another OS on your host it is called a guest OS, and it runs in a so called Virtual Machine (VM).

Image

An image is a number of layers that can be used to instantiate a container. This could be, for example, Java + Apache Tomcat. You can find all kinds of Docker Images on the public repository called Docker Hub. There are also private image repositories (for things like commercial enterprise images), such as the one Alfresco uses called Quay.  

Container

An instance of an image is called a container. You have an image, which is a set of layers as described. If you start this image, you have a running container of this image. You can have many running containers of the same image.

Docker

Docker is one of the most popular container platforms. Docker provides functionality for deploying and running applications in containers based on images.

Docker Compose

When you have many containers making up your solution, such as with ACS, and you need to configure each one of the containers so they work nicely together, then you need a tool for this.

Docker Compose is such a tool for defining and running multi-container Docker applications locally. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.

Dockerfile

A Dockerfile is a script containing a successive series of instructions, directions, and commands which are to be executed to form a new Docker image. Each command executed translates to a new layer in the image, forming the end product. They replace the process of doing everything manually and repeatedly. When a Dockerfile is finished executing, you end up having built a new image, which then you use to start a new Docker container.

Difference between Containers and Virtual Machines

It is important to understand the difference between using containers and using VMs. Here is a picture from What is a Container | Docker  that illustrates:

 

 

The main difference is that when you are running a container you are not kicking off a complete new OS instance. And this makes containers much more lightweight and quicker to start. A container is also taking up much less space on your hard-disk as it does not have to ship the whole OS.

Installing Software Required to Deploy ACS

Before we can deploy and run the Alfresco Content Services it is necessary to install the technologies that it uses.

Docker

You probably already have Docker installed as everything these days is easily accessible and run as containers. If you don't, go to the Docker Store and download the latest stable community edition (CE). Make sure the Docker daemon is running:

 

mbergljung$ docker -v

Docker version 17.09.0-ce, build afdb6d4

 

Also, verify that you have the recommended Docker version for running ACS, which is at least 17.09. You also want to verify the Docker Compose version, which should be at least 1.16.1:

$ docker-compose -v

docker-compose version 1.18.0, build 8dd22a9

 

If you are on Windows make sure that you are executing Docker commands from Windows PowerShell:

 

Getting to know the public Alfresco Docker Images

To find out about all the Alfresco images that are available at the Docker Hub registry go to https://hub.docker.com/u/alfresco/ and you will see a list of images belonging to the alfresco user. You should see something similar to the following screenshot (note: not all images are visible in the screenshot):

 

 

As we can see, a number of Docker images are available that relate to ACS:

 

  • alfresco/alfresco-share - the Alfresco Share web interface (i.e. share.war) running on Apache Tomcat
  • alfresco/alfresco-search-services - the Solr 6 based search service running on Jetty
  • alfresco/alfresco-content-repository-community - the Alfresco Repository app (i.e. alfresco.war) running on Apache Tomcat

 

There are also other supporting features available, such as Docker images for image and document transformation:

 

  • alfresco/alfresco-docker-imagemagick
  • alfresco/alfresco-docker-libreoffice
  • alfresco/alfresco-docker-alfresco-pdf-renderer

To build the alfresco/alfresco-content-repository-community image Alfresco uses the GitHub - Alfresco/acs-community-packaging  project. This project does not include any deployment templates. The GitHub - Alfresco/acs-community-deployment project contains deployment templates and instructions. It includes a Docker Compose script that can be used to launch a demo, test, or PoC ACS 6.0 system. You can customize this script if you like in order to run with different versions than those set by default, which are usually the latest versions.

When the ACS system is up and running you will have the following containers running:

  • Alfresco Community Repository 6.0 with:
    • Alfresco Share Services AMP
    • Alfresco Office Services (AOS) AMP
    • Alfresco vti-bin war - that helps with AOS integration
    • Alfresco Google Docs Integration Repo AMP
  • Alfresco Share 6.0 with:
    • Alfresco Google Docs Integration Share AMP
  • Alfresco Search Services (Solr 6)
  • A Postgres Database

 

To build custom images based on these Alfresco images in Docker Hub you need to create some Docker files. While doing this you can include custom AMPs and JARs. We will see how to do that later in the article. Before we do that we will walk through how to start an ACS system with Docker Compose and how to start an ACS system container by container.

Introduction to the Alfresco ACS Community Packaging Project

As mentioned, this is the project that is used to build Alfresco Community Repository artifacts, such as the Docker Image for ACS 6.0 Repo. Clone the ACS Community Packaging project so we can have a look at it:

 

$ git clone https://github.com/Alfresco/acs-community-packaging.git

 

$ cd acs-community-packaging/

 

Now, let’s look at what the different directories contain:

 

$ tree

.

├── CONTRIBUTING.md

├── LICENSE

├── README.md

 

(Contains a build script to create a Distribution ZIP with Repo, Share, and Solr4 etc, so you can install manually or facilitate upgrades)

├── distribution

│   ├── pom.xml

│   └── src

│       ├── assembly

│       │ └── distribution.xml

│       └── main

│           └── resources

│               ├── README.txt

│               ├── bin

│               │ ├── apply_amps.bat

│               │ ├── apply_amps.sh

│               │ ├── clean_tomcat.bat

│               │ └── clean_tomcat.sh

│               ├── licenses

│               │ ├── 3rd-party

...

│               │ ├── license.txt

│               │ └── notice.txt

│               └── web-server

│                   ├── conf-Tomcat7

│                   │   └── Catalina

│                   │       └── localhost

│                   │           └── alfresco.xml

│                   └── conf-Tomcat8

│                       └── Catalina

│                           └── localhost

│                               └── alfresco.xml

 

(Contains the Dockerfile to build the Alfresco Repo Docker image - alfresco/alfresco-content-repository-community)

├── docker-alfresco

│   ├── Dockerfile

│   ├── pom.xml

│   └── test

│       ├── docker-compose.yml

│       └── test.env

  

(Builds the alfresco.war)

├── war

 

As we can see, there’s no Alfresco Share or Search Service docker files. They reside in their own projects:

 

 

Note: We don’t need these projects for this article but it good to know about them to get an idea of how the images are produced.

 

If you are interested in the ACS 6.0 Enterprise packaging, then have a look at the http://github.com/Alfresco/acs-packaging project.

Introduction to the Alfresco ACS Community Deployment Project

This project contains the Docker Compose file that we will use in this article to start up an ASC Community 6.0 environment locally. If you are interested in the Kubernetes Helm charts to be able to deploy ACS Community with Kubernetes, then this is included in this project as well (Note: Kubernetes deployment is not covered in this article).

 

Clone the ACS Community Deployment project so we can have a look at it:

 

$ git clone https://github.com/Alfresco/acs-community-deployment.git 

 

$ cd acs-community-deployment/

 

Now, let’s look at what the different directories contain:

 

acs-community-deployment mbergljung$ tree

.

├── CONTRIBUTING.md

├── LICENSE

├── README.md

 

(Contains the Docker Compose YAML file to be able to start a full ACS 6.0 environment with Repo, Share, Solr, PostgreSQL)

├── docker-compose

│   ├── docker-compose.yml

│   └── test.env

 

(Contains Helm Charts to be able to deploy ACS Kubernetes cluster to AWS or locally via Minikube) 

└── helm

    └── alfresco-content-services-community

        ├── Chart.yaml

        ├── requirements.yaml

        ├── templates

        │   ├── NOTES.txt

        │   ├── _helpers.tpl

        │   ├── config-repository.yaml

        │   ├── config-share.yaml

        │   ├── deployment-repository.yaml

        │   ├── deployment-share.yaml

        │   ├── ingress-repository.yaml

        │   ├── ingress-share.yaml

        │   ├── svc-repository.yaml

        │   ├── svc-share.yaml

        └── values.yaml

 

If you are interested in the ACS 6.0 Enterprise deployment, then have a look at the http://github.com/Alfresco/acs-deployment project.

 

Deploying the ACS system with Docker Compose

Let’s see how easy it is to kick off a demo, test, or PoC ACS 6.0 solution with the supplied Docker Compose file. It will be similar to using the old installer and the shell script, except it will now be a whole lot easier to remove the installation and to keep several installations in parallel.

Using the Docker Compose file to start the ACS solution

After you have cloned the ACS Community Packaging project it’s time to get started.

Make sure the local machine has ports 5432, 8080, 8082, and 8083 free as they are used in the docker-compose.yml file.

Step into the directory where you cloned the acs-community-deployment project, then navigate into the docker-compose sub-directory, followed by command docker-compose up (if on Windows use Windows PowerShell):

 

acs-community-deployment mbergljung$ cd docker-compose/

docker-compose mbergljung$ docker-compose up

 

Creating network "dockercompose_default" with the default driver

Pulling solr6 (alfresco/alfresco-search-services:1.1.1)...

1.1.1: Pulling from alfresco/alfresco-search-services

6fd64836e300: Already exists

8ff6188dadfc: Already exists

d1b16fb40528: Already exists

fed33e3ce39c: Already exists

96f24514a7b3: Pull complete

6f415ea07e70: Pull complete

e2f858f39b3d: Pull complete

Digest: sha256:be7bf1463c55ced0058becdcd9ad952b3f770213e55b82c119d0eca95e70c7d8

Status: Downloaded newer image for alfresco/alfresco-search-services:1.1.1

Pulling alfresco (alfresco/alfresco-content-repository-community:6.0.5-ea)...

6.0.5-ea: Pulling from alfresco/alfresco-content-repository-community

18b8eb7e7f01: Already exists

f9d093c4cd43: Pull complete

05b40fb97183: Pull complete

6afa3ee9ddb6: Pull complete

 

...

Digest: sha256:9ab9496c2e3f6f26877f27db1c003b64d7b3ffe0aefc0ffd123dbfa6cddd8f5a

Status: Downloaded newer image for alfresco/alfresco-content-repository-community:6.0.5-ea

Creating dockercompose_solr6_1    ... done

Creating dockercompose_share_1    ... done

Creating dockercompose_alfresco_1 ... done

Creating dockercompose_postgres_1 ... done

Attaching to dockercompose_share_1, dockercompose_alfresco_1, dockercompose_solr6_1, dockercompose_postgres_1

share_1     | Replace 'REPO_HOST' with 'alfresco' and 'REPO_PORT' with '8080'

share_1     | 23-May-2018 07:15:34.483 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version:        Apache Tomcat/8.5.23

 

...

share_1     | 23-May-2018 07:15:34.850 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]

share_1     | 23-May-2018 07:15:34.897 INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read

share_1     | 23-May-2018 07:15:34.905 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["ajp-nio-8009"]

share_1     | 23-May-2018 07:15:34.911 INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read

share_1     | 23-May-2018 07:15:34.912 INFO [main] org.apache.catalina.startup.Catalina.load Initialization processed in 1286 ms

share_1     | 23-May-2018 07:15:34.976 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]

share_1     | 23-May-2018 07:15:34.977 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.23

share_1     | 23-May-2018 07:15:34.998 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/manager]

postgres_1  | The files belonging to this database system will be owned by user "postgres".

postgres_1  | This user must also own the server process.

postgres_1  |

postgres_1  | The database cluster will be initialized with locale "en_US.utf8".

postgres_1  | The default database encoding has accordingly been set to "UTF8".

postgres_1  | The default text search configuration will be set to "english".

postgres_1  |

postgres_1  | Data page checksums are disabled.

postgres_1  |

postgres_1  | fixing permissions on existing directory /var/lib/postgresql/data ... ok

postgres_1  | creating subdirectories ... ok

postgres_1  | selecting default max_connections ... 100

postgres_1  | selecting default shared_buffers ... 128MB

postgres_1  | selecting dynamic shared memory implementation ... posix

postgres_1  | creating configuration files ... ok

postgres_1  | running bootstrap script ... ok

share_1     | 23-May-2018 07:15:36.158 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/manager] has finished in [1,157] ms

share_1     | 23-May-2018 07:15:36.160 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/docs]

share_1     | 23-May-2018 07:15:36.186 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/docs] has finished in [26] ms

share_1     | 23-May-2018 07:15:36.187 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/examples]

alfresco_1  | 23-May-2018 07:15:36.245 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version:        Apache Tomcat/8.5.28

 

...

 

alfresco_1  | 23-May-2018 07:15:37.284 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]

share_1     | 23-May-2018 07:15:37.320 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/ROOT] has finished in [86] ms

share_1     | 23-May-2018 07:15:37.321 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/share]

 

...

alfresco_1  | 23-May-2018 07:15:37.490 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]

alfresco_1  | 23-May-2018 07:15:37.490 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.28

alfresco_1  | 23-May-2018 07:15:37.586 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/ROOT.war]

alfresco_1  | 23-May-2018 07:15:37.693 WARNING [localhost-startStop-1] org.apache.catalina.startup.SetContextPropertiesRule.begin [SetContextPropertiesRule]{Context} Setting property 'debug' to '100' did not find a matching property.

...

postgres_1  | waiting for server to start....2018-05-23 07:15:37.855 UTC [39] LOG:  listening on IPv4 address "127.0.0.1", port 5432

...

org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/alfresco]

solr6_1     | 2018-05-23 07:15:44.592 INFO  (main) [   ] o.e.j.s.Server jetty-9.3.8.v20160314

solr6_1     | 2018-05-23 07:15:45.800 INFO  (main) [   ] o.a.s.s.SolrDispatchFilter  ___      _       Welcome to Apache Solr? version 6.3.0

solr6_1     | 2018-05-23 07:15:45.812 INFO  (main) [   ] o.a.s.s.SolrDispatchFilter / __| ___| |_ _   Starting in standalone mode on port 8983

solr6_1     | 2018-05-23 07:15:45.813 INFO  (main) [   ] o.a.s.s.SolrDispatchFilter \__ \/ _ \ | '_|  Install dir: /opt/alfresco-search-services/solr

solr6_1     | 2018-05-23 07:15:46.072 INFO  (main) [   ] o.a.s.s.SolrDispatchFilter |___/\___/_|_|    Start time: 2018-05-23T07:15:45.817Z

solr6_1     | 2018-05-23 07:15:48.368 INFO  (main) [   ] o.e.j.s.ServerConnector Started ServerConnector@71687585{HTTP/1.1,[http/1.1]}{0.0.0.0:8983}

solr6_1     | 2018-05-23 07:15:48.382 INFO  (main) [   ] o.e.j.s.Server Started @5374ms

share_1     | 23-May-2018 07:15:49.439 INFO [localhost-startStop-1] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.

share_1     | May 23, 2018 7:15:49 AM org.apache.catalina.core.ApplicationContext log

share_1     | INFO: No Spring WebApplicationInitializer types detected on classpath

share_1     | May 23, 2018 7:15:49 AM org.apache.catalina.core.ApplicationContext log

share_1     | INFO: Initializing Spring root WebApplicationContext

share_1     | 2018-05-23 07:15:56,036  INFO  [config.packaging.ModulePackageManager] [localhost-startStop-1] Found 1 module package(s)

share_1     |  2018-05-23 07:15:56,043  INFO  [config.packaging.ModulePackageManager] [localhost-startStop-1] Alfresco / Google Docs Share Module, 3.0.4.2, The Share side artifacts of the Alfresco / Google Docs Integration.

share_1     |

share_1     |  2018-05-23 07:15:56,735  INFO  [extensions.webscripts.TemplateProcessorRegistry] [localhost-startStop-1] Registered template processor freemarker for extension ftl

share_1     |  2018-05-23 07:15:56,741  INFO  [extensions.webscripts.ScriptProcessorRegistry] [localhost-startStop-1] Registered script processor javascript for extension js

share_1     |  2018-05-23 07:15:56,753  INFO  [extensions.webscripts.TemplateProcessorRegistry] [localhost-startStop-1] Registered template processor freemarker for extension ftl

share_1     |  2018-05-23 07:15:56,755  INFO  [extensions.webscripts.ScriptProcessorRegistry] [localhost-startStop-1] Registered script processor javascript for extension js

alfresco_1  | 23-May-2018 07:15:57.311 INFO [localhost-startStop-1] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.

alfresco_1  | May 23, 2018 7:15:57 AM org.apache.catalina.core.ApplicationContext log

alfresco_1  | INFO: No Spring WebApplicationInitializer types detected on classpath

alfresco_1  | May 23, 2018 7:15:57 AM org.apache.catalina.core.ApplicationContext log

alfresco_1  | INFO: Initializing Spring root WebApplicationContext

share_1     |  2018-05-23 07:16:01,063  INFO  [extensions.webscripts.DeclarativeRegistry] [localhost-startStop-1] Registered 393 Web Scripts (+0 failed), 411 URLs

share_1     |  2018-05-23 07:16:01,063  INFO  [extensions.webscripts.DeclarativeRegistry] [localhost-startStop-1] Registered 8 Package Description Documents (+0 failed)

share_1     |  2018-05-23 07:16:01,064  INFO  [extensions.webscripts.DeclarativeRegistry] [localhost-startStop-1] Registered 0 Schema Description Documents (+0 failed)

share_1     |  2018-05-23 07:16:01,148  INFO  [extensions.webscripts.AbstractRuntimeContainer] [localhost-startStop-1] Initialised Surf Container Web Script Container (in 4380.056ms)

share_1     |  2018-05-23 07:16:01,178  INFO  [extensions.webscripts.TemplateProcessorRegistry] [localhost-startStop-1] Registered template processor freemarker for extension ftl

share_1     |  2018-05-23 07:16:01,185  INFO  [extensions.webscripts.ScriptProcessorRegistry] [localhost-startStop-1] Registered script processor javascript for extension js

share_1     |  May 23, 2018 7:16:02 AM org.apache.catalina.core.ApplicationContext log

share_1     | INFO: org.tuckey.web.filters.urlrewrite.UrlRewriteFilter INFO: loaded (conf ok)

share_1     | May 23, 2018 7:16:02 AM org.apache.catalina.core.ApplicationContext log

share_1     | INFO: Initializing Spring FrameworkServlet 'Spring Surf Dispatcher Servlet'

share_1     | 23-May-2018 07:16:02.147 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/share] has finished in [24,826] ms

share_1     | 23-May-2018 07:16:02.161 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]

share_1     | 23-May-2018 07:16:02.178 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]

share_1     | 23-May-2018 07:16:02.189 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 27277 ms

solr6_1     | 2018-05-23 07:16:02.717 WARN  (Thread-12) [   x:alfresco] o.a.s.h.c.AlfrescoSolrClusteringComponent No default engine for document clustering.

solr6_1     | 2018-05-23 07:16:03.890 WARN  (Thread-12) [   x:archive] o.a.s.h.c.AlfrescoSolrClusteringComponent No default engine for document clustering.

alfresco_1  | 2018-05-23 07:16:10,967  INFO  [domain.schema.SchemaBootstrap] [localhost-startStop-1] Ignoring script patch (post-Hibernate): patch.db-V4.2-metadata-query-indexes

alfresco_1  |  2018-05-23 07:16:10,969  INFO  [domain.schema.SchemaBootstrap] [localhost-startStop-1] Ignoring script patch (post-Hibernate): patch.db-V5.1-metadata-query-indexes

alfresco_1  |  2018-05-23 07:16:10,969  INFO  [domain.schema.SchemaBootstrap] [localhost-startStop-1] Ignoring script patch (post-Hibernate): patch.db-V5.2-remove-jbpm-tables-from-db

alfresco_1  |  2018-05-23 07:16:11,335  INFO  [alfresco.repo.admin] [localhost-startStop-1] Using database URL 'jdbc:postgresql://postgres:5432/alfresco' with user 'alfresco'.

alfresco_1  |  2018-05-23 07:16:11,336  INFO  [alfresco.repo.admin] [localhost-startStop-1] Connected to database PostgreSQL version 10.1

alfresco_1  |  2018-05-23 07:16:18,048  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'Authentication' subsystem, ID: [Authentication, managed, alfrescoNtlm1]

alfresco_1  |  2018-05-23 07:16:18,198  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'Authentication' subsystem, ID: [Authentication, managed, alfrescoNtlm1] complete

alfresco_1  |  2018-05-23 07:16:21,173  INFO  [extensions.webscripts.TemplateProcessorRegistry] [localhost-startStop-1] Registered template processor Repository Template Processor for extension ftl

alfresco_1  |  2018-05-23 07:16:21,179  INFO  [extensions.webscripts.ScriptProcessorRegistry] [localhost-startStop-1] Registered script processor Repository Script Processor for extension js

alfresco_1  |  2018-05-23 07:16:24,280  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'ContentStore' subsystem, ID: [ContentStore, managed, unencrypted]

alfresco_1  |  2018-05-23 07:16:24,315  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'ContentStore' subsystem, ID: [ContentStore, managed, unencrypted] complete

alfresco_1  |  2018-05-23 07:16:24,369  INFO  [domain.schema.SchemaBootstrap] [localhost-startStop-1] Connecting to database: jdbc:postgresql://postgres:5432/alfresco, UserName=alfresco, PostgreSQL JDBC Driver

alfresco_1  |  2018-05-23 07:16:24,370  INFO  [domain.schema.SchemaBootstrap] [localhost-startStop-1] Schema managed by database dialect org.alfresco.repo.domain.dialect.PostgreSQLDialect.

alfresco_1  |  2018-05-23 07:16:24,507  WARN  [domain.schema.SchemaBootstrap] [localhost-startStop-1] Schema validation found 85 potential problems, results written to: /usr/local/tomcat/temp/Alfresco/Alfresco-PostgreSQLDialect-Validation-Pre-Upgrade-alf_-1930649379894062897.txt

 

...

alfresco_1  |  2018-05-23 07:16:33,528  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'Search' subsystem, ID: [Search, managed, solr6]

alfresco_1  |  2018-05-23 07:16:33,902  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'Search' subsystem, ID: [Search, managed, solr6] complete

alfresco_1  |  2018-05-23 07:16:37,234  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'thirdparty' subsystem, ID: [thirdparty, default]

alfresco_1  |  2018-05-23 07:16:37,322  INFO  [transform.pdfrenderer.AlfrescoPdfRendererContentTransformerWorker] [localhost-startStop-1] Using Alfresco PDF Renderer: Alfresco PDF Renderer Version 1.1 [5b0e0b81dt] 2018-02-20 15:34:00 using Pdfium [e53460ff] 2018-02-19 18:34:00 CEST

alfresco_1  |  2018-05-23 07:16:37,410  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'thirdparty' subsystem, ID: [thirdparty, default] complete

alfresco_1  |  2018-05-23 07:16:37,410  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'OOoJodconverter' subsystem, ID: [OOoJodconverter, default]

alfresco_1  |  May 23, 2018 7:16:37 AM org.artofsolving.jodconverter.office.ProcessPoolOfficeManager <init>

alfresco_1  | INFO: ProcessManager implementation is LinuxProcessManager

alfresco_1  | May 23, 2018 7:16:37 AM org.artofsolving.jodconverter.office.OfficeProcess start

alfresco_1  | INFO: Using original OpenOffice command: [/opt/libreoffice5.4/program/soffice.bin, -accept=socket,host=127.0.0.1,port=8100;urp;, -env:UserInstallation=file:///usr/local/tomcat/temp/.jodconverter_socket_host-127.0.0.1_port-8100, -headless, -nocrashreport, -nodefault, -nofirststartwizard, -nolockcheck, -nologo, -norestore]

alfresco_1  | May 23, 2018 7:16:37 AM org.artofsolving.jodconverter.office.OfficeProcess start

alfresco_1  | INFO: starting process with acceptString 'socket,host=127.0.0.1,port=8100,tcpNoDelay=1' and profileDir '/usr/local/tomcat/temp/.jodconverter_socket_host-127.0.0.1_port-8100'

alfresco_1  | May 23, 2018 7:16:37 AM org.artofsolving.jodconverter.office.OfficeProcess start

alfresco_1  | INFO: started process; pid = 81

alfresco_1  | May 23, 2018 7:16:39 AM org.artofsolving.jodconverter.office.ManagedOfficeProcess$6 attempt

alfresco_1  | WARNING: office process died with exit code 81; restarting it

alfresco_1  | May 23, 2018 7:16:39 AM org.artofsolving.jodconverter.office.OfficeProcess start

alfresco_1  | INFO: Using original OpenOffice command: [/opt/libreoffice5.4/program/soffice.bin, -accept=socket,host=127.0.0.1,port=8100;urp;, -env:UserInstallation=file:///usr/local/tomcat/temp/.jodconverter_socket_host-127.0.0.1_port-8100, -headless, -nocrashreport, -nodefault, -nofirststartwizard, -nolockcheck, -nologo, -norestore]

alfresco_1  | May 23, 2018 7:16:39 AM org.artofsolving.jodconverter.office.OfficeProcess start

alfresco_1  | INFO: starting process with acceptString 'socket,host=127.0.0.1,port=8100,tcpNoDelay=1' and profileDir '/usr/local/tomcat/temp/.jodconverter_socket_host-127.0.0.1_port-8100'

alfresco_1  | May 23, 2018 7:16:39 AM org.artofsolving.jodconverter.office.OfficeProcess start

alfresco_1  | INFO: started process; pid = 92

alfresco_1  | May 23, 2018 7:16:39 AM org.artofsolving.jodconverter.office.OfficeConnection connect

alfresco_1  | INFO: connected: 'socket,host=127.0.0.1,port=8100,tcpNoDelay=1'

alfresco_1  | 2018-05-23 07:16:40,021  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'OOoJodconverter' subsystem, ID: [OOoJodconverter, default] complete

alfresco_1  |  2018-05-23 07:16:40,025  WARN  [repo.admin.ConfigurationChecker] [localhost-startStop-1] The 'dir.root' property is set to a relative path './alf_data'.  'dir.root' should be overridden to point to a specific folder.

alfresco_1  |  2018-05-23 07:16:40,026  INFO  [repo.admin.ConfigurationChecker] [localhost-startStop-1] The root data directory ('dir.root') is: ./alf_data

alfresco_1  |  2018-05-23 07:16:40,042  INFO  [admin.patch.PatchExecuter] [localhost-startStop-1] Checking for patches to apply ...

alfresco_1  |  2018-05-23 07:16:40,172  WARN  [admin.patch.PatchExecuter] [localhost-startStop-1] Patch description is not available: Patch[ id=patch.contentFormFolderType, description=patch.contentFormFolderType.description, fixesFromSchema=0, fixesToSchema=36, targetSchema=37, ignored=false]

alfresco_1  |  2018-05-23 07:16:40,199  WARN  [admin.patch.PatchExecuter] [localhost-startStop-1] Patch description is not available: Patch[ id=patch.redeploySubmitProcess, description=patch.redeploySubmitProcess.description, fixesFromSchema=0, fixesToSchema=57, targetSchema=58, ignored=false]

alfresco_1  |  2018-05-23 07:16:40,722  INFO  [admin.patch.PatchExecuter] [localhost-startStop-1] Applying patch 'patch.exampleJavaScript' (Loads sample Javascript file into datadictionary scripts folder).

alfresco_1  |  2018-05-23 07:16:40,764  INFO  [admin.patch.PatchExecuter] [localhost-startStop-1] Applying patch 'patch.siteLoadPatch.swsdp' (Loads a sample site into the repository.).

alfresco_1  |  2018-05-23 07:16:40,840  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'sysAdmin' subsystem, ID: [sysAdmin, default]

alfresco_1  |  2018-05-23 07:16:40,865  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'sysAdmin' subsystem, ID: [sysAdmin, default] complete

 

...

alfresco_1  |  2018-05-23 07:16:44,159  INFO  [repo.module.ModuleServiceImpl] [localhost-startStop-1] Found 4 module package(s).

alfresco_1  |  2018-05-23 07:16:44,178  INFO  [repo.module.ModuleServiceImpl] [localhost-startStop-1] Installing module 'alfresco-aos-module' version 1.2.0-RC2.

alfresco_1  |  2018-05-23 07:16:44,197  INFO  [repo.module.ModuleServiceImpl] [localhost-startStop-1] Installing module 'org.alfresco.integrations.google.docs' version 3.1.0-RC1.

alfresco_1  |  2018-05-23 07:16:44,221  INFO  [repo.module.ModuleServiceImpl] [localhost-startStop-1] Installing module 'alfresco-share-services' version 6.0.0.

alfresco_1  |  2018-05-23 07:16:44,243  INFO  [repo.module.ModuleServiceImpl] [localhost-startStop-1] Installing module 'alfresco-trashcan-cleaner' version 2.3.

alfresco_1  |  2018-05-23 07:16:44,264  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'fileServers' subsystem, ID: [fileServers, default]

alfresco_1  |  2018-05-23 07:16:44,759  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'fileServers' subsystem, ID: [fileServers, default] complete

alfresco_1  |  2018-05-23 07:16:44,760  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'imap' subsystem, ID: [imap, default]

alfresco_1  |  2018-05-23 07:16:44,898  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'imap' subsystem, ID: [imap, default] complete

alfresco_1  |  2018-05-23 07:16:44,898  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'email' subsystem, ID: [email, outbound]

alfresco_1  |  2018-05-23 07:16:45,075  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'email' subsystem, ID: [email, outbound] complete

alfresco_1  |  2018-05-23 07:16:45,075  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'email' subsystem, ID: [email, inbound]

alfresco_1  |  2018-05-23 07:16:45,135  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'email' subsystem, ID: [email, inbound] complete

alfresco_1  |  2018-05-23 07:16:45,135  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'Subscriptions' subsystem, ID: [Subscriptions, default]

alfresco_1  |  2018-05-23 07:16:45,159  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'Subscriptions' subsystem, ID: [Subscriptions, default] complete

alfresco_1  |  2018-05-23 07:16:45,189  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'Synchronization' subsystem, ID: [Synchronization, default]

alfresco_1  |  2018-05-23 07:16:45,336  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'Synchronization' subsystem, ID: [Synchronization, default] complete

alfresco_1  |  2018-05-23 07:16:45,354  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] Alfresco JVM - v1.8.0_161-b12; maximum heap size 878.500MB

alfresco_1  |  2018-05-23 07:16:45,355  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] Server Mode :UNKNOWN

alfresco_1  |  2018-05-23 07:16:45,359  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] Alfresco Content Services started (Community Early Access). Current version: 6.0.5 (r1c848a2d-b73) schema 10,201. Originally installed version: 6.0.5 (r1c848a2d-b73) schema 10,201.

alfresco_1  |  2018-05-23 07:16:45,374  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'ActivitiesFeed' subsystem, ID: [ActivitiesFeed, default]

alfresco_1  |  2018-05-23 07:16:45,733  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'ActivitiesFeed' subsystem, ID: [ActivitiesFeed, default] complete

alfresco_1  |  2018-05-23 07:16:45,734  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'Replication' subsystem, ID: [Replication, default]

alfresco_1  |  2018-05-23 07:16:45,779  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'Replication' subsystem, ID: [Replication, default] complete

alfresco_1  |  2018-05-23 07:16:46,914  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'googledocs' subsystem, ID: [googledocs, drive]

alfresco_1  |  2018-05-23 07:16:47,053  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'googledocs' subsystem, ID: [googledocs, drive] complete

alfresco_1  |  2018-05-23 07:16:50,438  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 396 Web Scripts (+0 failed), 543 URLs

alfresco_1  |  2018-05-23 07:16:50,445  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 1 Package Description Documents (+0 failed)

alfresco_1  |  2018-05-23 07:16:50,445  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 0 Schema Description Documents (+0 failed)

alfresco_1  |  2018-05-23 07:16:51,235  INFO  [extensions.webscripts.DeclarativeRegistry] [localhost-startStop-1] Registered 396 Web Scripts (+0 failed), 543 URLs

alfresco_1  |  2018-05-23 07:16:51,235  INFO  [extensions.webscripts.DeclarativeRegistry] [localhost-startStop-1] Registered 1 Package Description Documents (+0 failed)

alfresco_1  |  2018-05-23 07:16:51,236  INFO  [extensions.webscripts.DeclarativeRegistry] [localhost-startStop-1] Registered 0 Schema Description Documents (+0 failed)

alfresco_1  |  2018-05-23 07:16:51,240  INFO  [extensions.webscripts.AbstractRuntimeContainer] [localhost-startStop-1] Initialised Repository Web Script Container (in 3933.765ms)

alfresco_1  |  2018-05-23 07:16:51,284  INFO  [extensions.webscripts.TemplateProcessorRegistry] [localhost-startStop-1] Registered template processor freemarker for extension ftl

alfresco_1  |  2018-05-23 07:16:51,296  INFO  [extensions.webscripts.ScriptProcessorRegistry] [localhost-startStop-1] Registered script processor javascript for extension js

alfresco_1  |  2018-05-23 07:16:51,833  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 396 Web Scripts (+0 failed), 543 URLs

alfresco_1  |  2018-05-23 07:16:51,833  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 1 Package Description Documents (+0 failed)

alfresco_1  |  2018-05-23 07:16:51,834  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 0 Schema Description Documents (+0 failed)

alfresco_1  |  2018-05-23 07:16:51,914  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 14 Web Scripts (+0 failed), 103 URLs

alfresco_1  |  2018-05-23 07:16:51,914  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 0 Package Description Documents (+0 failed)

alfresco_1  |  2018-05-23 07:16:51,915  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 0 Schema Description Documents (+0 failed)

alfresco_1  |  2018-05-23 07:16:51,967  INFO  [extensions.webscripts.DeclarativeRegistry] [localhost-startStop-1] Registered 14 Web Scripts (+0 failed), 103 URLs

alfresco_1  |  2018-05-23 07:16:51,967  INFO  [extensions.webscripts.DeclarativeRegistry] [localhost-startStop-1] Registered 0 Package Description Documents (+0 failed)

alfresco_1  |  2018-05-23 07:16:51,967  INFO  [extensions.webscripts.DeclarativeRegistry] [localhost-startStop-1] Registered 0 Schema Description Documents (+0 failed)

alfresco_1  |  2018-05-23 07:16:51,969  INFO  [extensions.webscripts.AbstractRuntimeContainer] [localhost-startStop-1] Initialised Public Api Web Script Container (in 631.7979ms)

alfresco_1  |  2018-05-23 07:16:51,993  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 14 Web Scripts (+0 failed), 103 URLs

alfresco_1  |  2018-05-23 07:16:51,993  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 0 Package Description Documents (+0 failed)

alfresco_1  |  2018-05-23 07:16:51,993  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 0 Schema Description Documents (+0 failed)

alfresco_1  |  2018-05-23 07:16:52,105  WARN  [scripts.servlet.X509ServletFilterBase] [localhost-startStop-1] clientAuth does not appear to be set for Tomcat. clientAuth must be set to 'want' for X509 Authentication

alfresco_1  |  2018-05-23 07:16:52,105  WARN  [scripts.servlet.X509ServletFilterBase] [localhost-startStop-1] Attempting to set clientAuth=want through JMX...

alfresco_1  |  2018-05-23 07:16:52,117  WARN  [scripts.servlet.X509ServletFilterBase] [localhost-startStop-1] Unable to set clientAuth=want through JMX.

alfresco_1  |  23-May-2018 07:16:56.806 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/alfresco] has finished in [72,893] ms

alfresco_1  | 23-May-2018 07:16:56.815 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]

alfresco_1  | 23-May-2018 07:16:56.831 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]

alfresco_1  | 23-May-2018 07:16:56.841 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 79493 ms

share_1     | 2018-05-23 07:17:05,651  INFO  [web.site.EditionInterceptor] [http-nio-8080-exec-3] Successfully retrieved license information from Alfresco.

alfresco_1  | 2018-05-23 07:17:20,434  INFO  [management.subsystems.ChildApplicationContextFactory] [http-nio-8080-exec-1] Starting 'Transformers' subsystem, ID: [Transformers, default]

alfresco_1  |  2018-05-23 07:17:20,845  INFO  [management.subsystems.ChildApplicationContextFactory] [http-nio-8080-exec-1] Startup of 'Transformers' subsystem, ID: [Transformers, default] complete

share_1     |  2018-05-23 07:17:29,731  INFO  [web.scripts.ImapServerStatus] [http-nio-8080-exec-10] Successfully retrieved IMAP server status from Alfresco: disabled

As we can see, the logs from each container are available as an aggregated console log so we can follow exactly what is happening. Note the AMPs that are applied by default: Alfresco AOS Service, Google Docs Integration, Alfresco Share Services, and the Trashcan Cleaner.

Accessing the Alfresco Share web application

We can now access the Web UI at http://localhost:8080/share. The login credentials are: admin/admin.

Inspecting the Docker Compose file

We have seen how easy it is to deploy and run the ACS system with Docker Compose, next we will look at the Compose YAML file that made it happen. It’s located in the acs-community-deployment/docker-compose directory and looks like the following:

 

version: "3"

services:
    alfresco:
        image: alfresco/alfresco-content-repository-community:6.0.5-ea
        environment:
            JAVA_OPTS : "
                -Ddb.driver=org.postgresql.Driver
                -Ddb.username=alfresco
                -Ddb.password=alfresco
                -Ddb.url=jdbc:postgresql://postgres:5432/alfresco
                -Dsolr.host=solr6
                -Dsolr.port=8983
                -Dsolr.secureComms=none
                -Dsolr.base.url=/solr
                -Dindex.subsystem.name=solr6
                -Ddeployment.method=DOCKER_COMPOSE
                "
        ports:
            - 8082:8080 #Browser port

    share:
        image: alfresco/alfresco-share:6.0.a
        environment:
            - REPO_HOST=alfresco
            - REPO_PORT=8080
        ports:
            - 8080:8080

    postgres:
        image: postgres:10.1
        environment:
            - POSTGRES_PASSWORD=alfresco
            - POSTGRES_USER=alfresco
            - POSTGRES_DB=alfresco
        ports:
            - 5432:5432

    solr6:
        image: alfresco/alfresco-search-services:1.1.1
        environment:
            #Solr needs to know how to register itself with Alfresco
            - SOLR_ALFRESCO_HOST=alfresco
            - SOLR_ALFRESCO_PORT=8080
            #Alfresco needs to know how to call solr
            - SOLR_SOLR_HOST=solr6
            - SOLR_SOLR_PORT=8983
            #Create the default alfresco and archive cores
            - SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive
        ports:
            - 8083:8983 #Browser port

Image configuration

The image property tells Docker Compose what Docker Image to fetch, what version, and from where. If it just specifies the image name and version, as in the above specification, then the images are assumed to reside in https://hub.docker.com. If the image property value looks something like quay.io/alfresco/alfresco-content-services:latest, then it is most likely an Enterprise Edition image and you will need to login to get that.

 

At the end of the image property value is the version specification. You can update the version to fit your requirements. Browse Docker Hub for available versions. It is quite easy to list available versions for Alfresco images, or tags as Docker Hub calls them, with a URL like https://hub.docker.com/r/<user>/<image name>/tags/. To list the available Alfresco Search Services image versions/tags use https://hub.docker.com/r/alfresco/alfresco-search-services/tags/ :

 

Environment configuration

The environment property is used to configure the container. For example, it can be used to configure the Repository container with the location of the database and where the Solr server is running. It can also be used to tell the Share container about the location of the Repository server. The Solr and Database containers are also configured using this property.

 

We can look at the environment property configuration and see what properties we can use when starting the containers manually, which is what we will be doing in the next section.

Networking

By default Docker Compose sets up a single network for our ACS solution. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name. For example, the Repo container knows about the Database and Solr containers via the following configuration:

 

-Ddb.url=jdbc:postgresql://postgres:5432/alfresco
-Dsolr.host=solr6

 

Where postgres and solr6 are the container names for those services.

Listing Docker images and containers

When you are using Docker for deployment it’s good to know how to list the local images and containers that you are working with.

 

To list images that have been downloaded to your computer:

 

$ docker image ls

REPOSITORY                                       TAG                 IMAGE ID            CREATED             SIZE

alfresco/alfresco-content-repository-community   6.0.5-ea            cacbb9510bfe        4 weeks ago         1.72GB

 

alfresco/alfresco-search-services                1.1.1               d6e6a058b986        6 weeks ago         890MB

alfresco/alfresco-share                          6.0.a               9aaa0425fc95        8 weeks ago         709MB

alfresco/alfresco-search-services                1.1.0               56575d75dd82        3 months ago        884MB

postgres                                         10.1                ec61d13c8566        5 months ago        287MB

Here we can see the Alfresco images that were downloaded from Docker Hub when we kicked off the ACS solution with Docker Compose. 

To list running and stopped containers (if you leave out -a, then you will see only running containers):

mbergljung$ docker container ls -a

CONTAINER ID        IMAGE                                                     COMMAND                  CREATED             STATUS                      PORTS                    NAMES

18d33e6734ac        alfresco/alfresco-share:6.0.a                             "/usr/local/tomcat/s…"   21 minutes ago      Up About a minute           0.0.0.0:8080->8080/tcp   dockercompose_share_1

04e553c18cc6        postgres:10.1                                             "docker-entrypoint.s…"   21 minutes ago      Up About a minute           0.0.0.0:5432->5432/tcp   dockercompose_postgres_1

c7f1baae3b55        alfresco/alfresco-search-services:1.1.1                   "/opt/alfresco-searc…"   21 minutes ago      Up About a minute           0.0.0.0:8083->8983/tcp   dockercompose_solr6_1

556e87db8438        alfresco/alfresco-content-repository-community:6.0.5-ea   "catalina.sh run"        21 minutes ago      Up About a minute           0.0.0.0:8082->8080/tcp   dockercompose_alfresco_1

 

d0b6270afeeb        alfresco/alfresco-search-services:1.1.0                   "/opt/alfresco-searc…"   5 weeks ago         Exited (255) 4 weeks ago    0.0.0.0:8983->8983/tcp   alf-search

64d5c9ac4005        postgres:10.1                                             "docker-entrypoint.s…"   5 weeks ago         Exited (255) 4 weeks ago    0.0.0.0:5432->5432/tcp   alf-postgres

062598c1feab        zeppelin:1.0.0-EA                                         "/usr/bin/tini -- bi…"   2 months ago        Exited (255) 2 months ago   0.0.0.0:80->9090/tcp     zeppelin

4eb93b7a4101        alfresco/process-services:1.7.0                           "/root/entrypoint.sh"    4 months ago        Exited (137) 4 months ago                            aps170

3721d2d8bf0f        sonatype/nexus3                                           "sh -c ${SONATYPE_DI…"   4 months ago        Exited (255) 4 months ago   0.0.0.0:8081->8081/tcp   nexus

 

Note how all containers started by Docker Compose will be named as dockercompose_<docker compose file service name>_<instance number>.

Stopping the ACS solution

You can stop all the containers by pressing Ctrl+C at the console (or from another shell you can do docker-compose down). 

 

Here is how it looks like when doing Ctrl-C:

 

...

alfresco_1  | 05-Apr-2018 07:29:21.043 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]

alfresco_1  | 05-Apr-2018 07:29:21.054 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]

alfresco_1  | 05-Apr-2018 07:29:21.056 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 51634 ms

alfresco_1  | 2018-04-05 07:29:21,209  INFO [management.subsystems.ChildApplicationContextFactory] [http-nio-8080-exec-1] Starting 'Search' subsystem, ID: [Search, managed, solr6]

alfresco_1  | 2018-04-05 07:29:21,573  INFO [management.subsystems.ChildApplicationContextFactory] [http-nio-8080-exec-1] Startup of 'Search' subsystem, ID: [Search, managed, solr6] complete

share_1     | 2018-04-05 07:29:36,290  INFO [web.site.EditionInterceptor] [http-nio-8080-exec-3] Successfully retrieved license information from Alfresco.

share_1     | 2018-04-05 07:29:54,625  INFO [web.scripts.ImapServerStatus] [http-nio-8080-exec-9] Successfully retrieved IMAP server status from Alfresco: disabled

share_1     | 2018-04-05 07:30:11,807  INFO [web.scripts.DictionaryQuery] [http-nio-8080-exec-1] Successfully retrieved Data Dictionary from Alfresco.

 

^CGracefully stopping... (press Ctrl+C again to force)

Stopping dockercompose_alfresco_1 ... done

Stopping dockercompose_postgres_1 ... done

Stopping dockercompose_solr6_1    ... done

Stopping dockercompose_share_1    ... done

There is a big difference between doing Ctrl-C and doing docker-compose down. The latter one also removes the containers and any content created:

$ docker-compose down

Stopping dockercompose_share_1    ... done

Stopping dockercompose_postgres_1 ... done

Stopping dockercompose_solr6_1    ... done

Stopping dockercompose_alfresco_1 ... done

Removing dockercompose_share_1    ... done

Removing dockercompose_postgres_1 ... done

Removing dockercompose_solr6_1    ... done

Removing dockercompose_alfresco_1 ... done

To check there are no containers running:

$ docker container ls

CONTAINER ID        IMAGE COMMAND             CREATED STATUS PORTS               NAMES

To list the stopped containers (you will only see these if you did Ctrl-C to stop):

$ docker container ls -a

CONTAINER ID        IMAGE                                      COMMAND CREATED STATUS                PORTS NAMES

e5a1c8a74a75        alfresco/alfresco-content-repository-community:6.0.5-ea   "catalina.sh run" 41 hours ago Exited (143) 4 minutes ago                            dockercompose_alfresco_1

ae1e982c13d5        postgres:10.1                                      "docker-entrypoint.s…" 41 hours ago Exited (0) 4 minutes ago                              dockercompose_postgres_1

b67a5c11215f        alfresco/alfresco-search-services:1.1.0                   "/opt/alfresco-searc…" 41 hours ago Exited (143) 4 minutes ago                            dockercompose_solr6_1

1c372a4cac98        alfresco/alfresco-share:6.0.a                             "/usr/local/tomcat/s…" 41 hours ago Exited (137) 4 minutes ago                            dockercompose_share_1

Removing/Uninstalling the ACS solution

When we are finished with the demo, test, PoC, or whatever we were doing, then we can remove the ACS solution from the computer in an easy way with the following Docker Compose command (this is not necessary if you did docker-compose down):

 

docker-compose mbergljung$ docker-compose rm

Going to remove dockercompose_alfresco_1, dockercompose_postgres_1, dockercompose_solr6_1, dockercompose_share_1

Are you sure? [yN] y

Removing dockercompose_alfresco_1 ... done

Removing dockercompose_postgres_1 ... done

Removing dockercompose_solr6_1    ... done

Removing dockercompose_share_1    ... done

List the running and stopped containers to make sure they are gone:

$ docker container ls -a

CONTAINER ID        IMAGE              COMMAND CREATED           STATUS PORTS        NAMES

Deploying the ACS system Container by Container

Docker Compose is a convenient way of getting an ACS system up and running quickly for testing and PoC purposes. It does however hide all the details about starting and stopping the Docker container. For our purposes it is useful to be able to configure and deploy each container individually because it allows us to get a bit more detail about how Docker works.

 

We are going to deploy and run the same thing we did via the Docker Compose file. But now we are going to start and configure each container manually.

Create a network for the containers

Before we can start any containers we need to create a network for them to communicate over. We need to do this because you can’t use localhost inside a container to connect to another container. We can then connect to this new network when we create a new container.

 

Create a new network called alf-net as follows:

 

$ docker network create alf-net

3393bff64289dffae0e36fde8c7b32c51160b565afd376598c9d191d91d42b32

The response is the long ID for the new network. But we will refer to it as alf-net.

Deploy and Run the Database container

The Alfresco Repo is going to connect to a PostgreSQL database called ‘alfresco’ where the Repository can store the metadata for the content files. We can easily fire up a PostgreSQL database with images available at https://hub.docker.com/_/postgres/.

 

We know from the Docker Compose file what environment variables we can use to configure the database image. Deploy it as follows and give the new container the name alf-postgres (if you already have a container with this name then pick another name, or you can remove the container with the following command if you don’t need to keep it: $ docker container rm alf-postgres):

 

$ docker run --network alf-net --name alf-postgres -p 5432:5432 -e POSTGRES_USER=alfresco -e POSTGRES_PASSWORD=alfresco -e POSTGRES_DB=alfresco -d postgres:10.1  

0f5394598a21c095784646664244d2edb4a13dcda1c4aecfaf7a62e836f6d4c0

 

The --network option must be specified directly after run. It cannot, for example, be at the end of the command.

 

Here we start a PostgreSQL container with user/pwd alfresco/alfresco and tell it to create the default database with the name alfresco, which is what the repository needs. The database server is available externally on port 5432. We also connect the container to the alf-net network we created earlier on. The command returns the new container’s ID.

 

Test that it all worked by logging into the container and accessing the database (note that we use the short ID for the container):

 

$ docker container ls

CONTAINER ID        IMAGE COMMAND                  CREATED STATUS PORTS                    NAMES

0f5394598a21        postgres:10.1 "docker-entrypoint.s…"   About a minute ago Up About a minute 0.0.0.0:5432->5432/tcp   alf-postgres

 

$ docker container exec -it 0f5394598a21 /bin/bash

root@0f5394598a21:/# psql alfresco alfresco

psql (10.1)

Type "help" for help.

 

alfresco=# \q

root@0f5394598a21:/# exit

exit

Check that the Database container is connected to the network

At this point it might be a good idea to check that the PostgreSQL database container is actually connected to the custom network alf-net that we created.

 

To check the network use the following command:

 

$ docker network inspect alf-net

[

   {

       "Name": "alf-net",

       "Id": "3393bff64289dffae0e36fde8c7b32c51160b565afd376598c9d191d91d42b32",

       "Created": "2018-04-04T14:00:57.557180066Z",

       "Scope": "local",

       "Driver": "bridge",

       "EnableIPv6": false,

       "IPAM": {

           "Driver": "default",

           "Options": {},

           "Config": [

               {

                   "Subnet": "172.21.0.0/16",

                   "Gateway": "172.21.0.1"

               }

           ]

       },

       "Internal": false,

       "Attachable": false,

       "Ingress": false,

       "ConfigFrom": {

           "Network": ""

       },

       "ConfigOnly": false,

       "Containers": {

           "5661dc60a832e7c620842f88d8107d55546fc9a76e63005b73b8c799db562384": {

               "Name": "alf-postgres",

               "EndpointID": "24a246b1007d7f704dab4cf6ab343b9755e5cfda114692b4176e526a756e04d4",

               "MacAddress": "02:42:ac:15:00:02",

               "IPv4Address": "172.21.0.2/16",

               "IPv6Address": ""

           }

       },

       "Options": {},

       "Labels": {}

   }

]

As we can see, the database container is available on the network on IP 172.21.0.2. We will be able to access the database container under a hostname that is the same as the container name alf-postgres.

Deploy and Run the Alfresco Search Services container

The Alfresco Repo is going to use the Search Services with Apache Solr 6.0 for all search related features. The alfresco/alfresco-search-services image is available for us on Docker Hub. Kick it off as follows and give the new container the name alf-search:

 

$ docker run --network alf-net --name alf-search -p 8983:8983 -e SOLR_ALFRESCO_HOST=alf-repo -e SOLR_ALFRESCO_PORT=8080 -e SOLR_SOLR_HOST=alf-search -e SOLR_SOLR_PORT=8983 -e SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive -d alfresco/alfresco-search-services:1.1.1 

2cc7fda1f64385ee028ad486210544ed708900099431574b6e11fba3358cd6e6

 

There are a number of environment variables we need to pass to the container. The first two tells Apache Solr where Alfresco Repo is running so it can call back for text content. The next two just tells Solr itself where it is running. And the last variable tells Solr to create two cores (i.e. indexes) for live content (alfresco) and archived content (archive).

 

The container will run on the standard Solr port 8983.

 

Now review the logs:

 

$ docker container logs 2cc7fda1f64385ee028ad486210544ed708900099431574b6e11fba3358cd6e6

2018-04-04 15:10:17.370 INFO  (main) [ ] o.e.j.s.Server jetty-9.3.8.v20160314

2018-04-04 15:10:17.756 INFO  (main) [ ] o.a.s.s.SolrDispatchFilter  ___ _ Welcome to Apache Solr? version 6.3.0

2018-04-04 15:10:17.757 INFO  (main) [ ] o.a.s.s.SolrDispatchFilter / __| ___| |_ _   Starting in standalone mode on port 8983

2018-04-04 15:10:17.757 INFO  (main) [ ] o.a.s.s.SolrDispatchFilter \__ \/ _ \ | '_|  Install dir: /opt/alfresco-search-services/solr

2018-04-04 15:10:17.841 INFO  (main) [ ] o.a.s.s.SolrDispatchFilter |___/\___/_|_|    Start time: 2018-04-04T15:10:17.759Z

2018-04-04 15:10:18.699 INFO  (main) [ ] o.e.j.s.ServerConnector Started ServerConnector@4608325d{HTTP/1.1,[http/1.1]}{0.0.0.0:8983}

2018-04-04 15:10:18.699 INFO  (main) [ ] o.e.j.s.Server Started @2098ms

2018-04-04 15:10:30.672 WARN  (Thread-12) [ x:alfresco] o.a.s.h.c.AlfrescoSolrClusteringComponent No default engine for document clustering.

2018-04-04 15:10:31.065 WARN  (Thread-12) [ x:archive] o.a.s.h.c.AlfrescoSolrClusteringComponent No default engine for document clustering.

2018-04-04 15:10:31.536 ERROR (searcherExecutor-7-thread-1-processing-x:alfresco) [   x:alfresco] o.a.s.t.AbstractTracker Model tracking failed

java.net.UnknownHostException: alf-repo

We will see an error when the Search Services are trying to connect to the Alfresco Repository as it is not yet up an running. We will start them next.

Check the Solr UI on http://localhost:8983:

 

 

In the UI we can check that the two cores have been created by clicking on the Core Selector drop down to the left.

Deploy and Run the Alfresco Repository container

The standard Alfresco Repository image (i.e. alfresco.war) is available in Docker Hub under the name alfresco/alfresco-content-repository-community. We want to use the same version of it as was specified in the Docker Compose environment, which was 6.0.4-ea. Start the container as follows and call it alf-repo:

 

$ docker run --network alf-net --name alf-repo -p 8080:8080 -e JAVA_OPTS='-Ddb.driver=org.postgresql.Driver -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.url=jdbc:postgresql://alf-postgres:5432/alfresco -Dsolr.host=alf-search -Dsolr.port=8983 -Dsolr.secureComms=none -Dsolr.base.url=/solr -Dindex.subsystem.name=solr6' -d alfresco/alfresco-content-repository-community:6.0.5-ea

0c3819df858273f5ed55e973a8ef5dbdeeb78f024a3e500334d1bc843c2f6886

 

We publish the Repo on port 8080 instead of port 8082 as in the Docker Compose file. The environment configuration is pretty much taken from the Docker Compose file. The hostnames have been updated to match the container names.

 

Review the logs as follows by using the container ID:

 

$ docker container logs 0c3819df858273f5ed55e973a8ef5dbdeeb78f024a3e500334d1bc843c2f6886

. . .

08-Mar-2018 13:55:38.508 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/alfresco] has finished in [73,821] ms

08-Mar-2018 13:55:38.515 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]

08-Mar-2018 13:55:38.529 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]

08-Mar-2018 13:55:38.535 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 74678 ms

If you see the logs above it means the server has started up properly.

If you are experiencing problems and want to stop and remove the container to be able to start over you can do this by running the following command:

 

$ docker container stop alf-repo

alf-repo

$ docker container rm alf-repo

alf-repo

Accessing the Alfresco Repo from a Browser

You should be able to access the Alfresco Repository from a browser. You can test WebDAV access via http://localhost:8080/alfresco/webdav:

 

 

If you are asked to login, use admin/admin.

Deploy and Run the Alfresco Share container

The Alfresco Share container is the last step required for the ACS solution setup and it provides the user interface. The alfresco/alfresco-share image is available for us on Docker Hub. Deploy it as follows and give the new container the name alf-share:

 

$ docker run --network alf-net --name alf-share -p 8081:8080 -e REPO_HOST=alf-repo -e REPO_PORT=8080 -d alfresco/alfresco-share:6.0.a

d9c24489267608d672ff67a30e28d9de5234568be2ea0afe99d9ba037a36674b

 

The only thing we need to tell Share is where the Repo is running. We run Share on port 8081 so it does not clash with the Repo.

 

Now review the logs:

 

$ docker container logs d9c24489267608d672ff67a30e28d9de5234568be2ea0afe99d9ba037a36674b

INFO: Initializing Spring FrameworkServlet 'Spring Surf Dispatcher Servlet'

05-Apr-2018 05:25:15.182 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/share] has finished in [10,485] ms

05-Apr-2018 05:25:15.188 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]

05-Apr-2018 05:25:15.203 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]

05-Apr-2018 05:25:15.207 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 11365 ms

Access the Share UI on http://localhost:8081/share and login with admin/admin:

 

Test the user interface by uploading some files, and searching etc so you can see that it all works properly.

Starting and Stopping the ACS solution

Now we have all the containers that make up the ACS solution running, and we have some new content added to the Repo, let’s stop the containers.

 

To stop the containers, use the following template: docker container stop <name>:

 

$ docker container stop alf-share

alf-share

$ docker container stop alf-repo

alf-repo

$ docker container stop alf-search

alf-search

$ docker container stop alf-postgres

alf-postgres

I stopped them in the opposite order to how they were started.

We can check that they really are stopped by using the following command:

 

$ docker container ls -a

CONTAINER ID        IMAGE                                                     COMMAND                  CREATED              STATUS                        PORTS                    NAMES

6a1b766a01ed        alfresco/alfresco-share:6.0.a                             "/usr/local/tomcat/s…"   About a minute ago   Exited (137) 24 seconds ago                            alf-share

d2d030b10f3f        alfresco/alfresco-content-repository-community:6.0.5-ea   "catalina.sh run"        3 minutes ago        Exited (143) 17 seconds ago                            alf-repo

f95b421ee73c        alfresco/alfresco-search-services:1.1.1                   "/opt/alfresco-searc…"   4 minutes ago        Exited (143) 11 seconds ago                            alf-search

d355deda2b57        postgres:10.1                                             "docker-entrypoint.s…"   5 minutes ago        Exited (0) 6 seconds ago                               alf-postgres

 

Now, let’s start it all up again and see if the content is still there:

$ docker container start alf-postgres

alf-postgres

$ docker container start alf-search

alf-search

$ docker container start alf-repo

alf-repo

$ docker container start alf-share

alf-share

Login to Share and verify that the content is still there. All the content is there and the search index is intact. Next we will look at how this works.

Where is the data stored?

When working with containers there are a couple of ways that data can be persisted. You can just store it inside the container or you can use something called Docker Volumes.

 

Storing it inside a container is a simple approach for demoing, testing, and PoC situations. However, it’s not ideal for a production environment as all content will be inside the container, which will make it very big. This means that there’s no way of having backup containers if something crashes. Also, it would not work if you wanted to cluster ACS. What you would use in production is Docker Volumes, which enable you to store the content outside the container.

 

To look at the Repository content we have to open a shell into the alf-repo container as follows and step into the alf_data directory (note, the container need to be started for this to work):

 

$ docker container exec -it alf-repo /bin/bash

[root@0c3819df8582 tomcat]# ls -l

total 184

-rw-r----- 1 root root 57092 Feb  6 23:12 LICENSE

-rw-r----- 1 root root  1723 Feb 6 23:12 NOTICE

-rw-r----- 1 root root  7138 Feb 6 23:12 RELEASE-NOTES

-rw-r----- 1 root root 16246 Feb  6 23:12 RUNNING.txt

drwxr-x--- 4 root root  4096 Apr 4 15:21 alf_data

drwxr-xr-x 1 root root  4096 Mar 27 13:28 alfresco-mmt

-rw-r----- 1 root root 22382 Apr  5 05:42 alfresco.log

-rw-r----- 1 root root 23311 Apr  4 15:22 alfresco.log.2018-04-04

drwxr-xr-x 1 root root  4096 Mar 27 13:28 amps

drwxr-x--- 2 root root  4096 Mar 26 11:14 bin

drwx------ 1 root root  4096 Apr 4 15:20 conf

drwxr-xr-x 3 root root  4096 Mar 26 11:14 include

drwxr-x--- 1 root root  4096 Mar 27 13:28 lib

drwxr-x--- 1 root root  4096 Apr 5 05:41 logs

drwxr-xr-x 3 root root  4096 Mar 26 11:14 native-jni-lib

drwxr-xr-x 1 root root  4096 Mar 27 13:28 shared

drwxr-x--- 1 root root  4096 Apr 5 05:42 temp

drwxr-x--- 1 root root  4096 Apr 4 15:20 webapps

drwxr-x--- 1 root root  4096 Apr 4 15:20 work

[root@0c3819df8582 tomcat]# cd alf_data/

[root@0c3819df8582 alf_data]# ls -l

total 8

drwxr-x--- 3 root root 4096 Apr  4 15:21 contentstore

drwxr-x--- 2 root root 4096 Apr  4 15:20 contentstore.deleted

[root@0c3819df8582 alf_data]# cd contentstore

[root@0c3819df8582 contentstore]# cd 2018/4/5/5/33/

[root@0c3819df8582 33]# ls -l

total 8

-rw-r----- 1 root root 3732 Apr  5 05:33 1d41a201-ad12-42f9-9f44-3e70597b5fa4.bin

-rw-r----- 1 root root   61 Apr 5 05:33 b1ba1f0f-db04-49fd-9e11-aa57d2ffc6e6.bin

[root@0c3819df8582 33]# exit

Note that when you do this you will have a different directory structure under contentstore as you will have uploaded content after this article was written.

Removing/Uninstalling the ACS solution

To remove everything from our computer make sure each container is stopped as discussed above. Then use the following template - docker container rm <name> (note, all data will be permanently deleted):

$ docker container rm alf-share

alf-share

$ docker container rm alf-repo

alf-repo

$ docker container rm alf-search

alf-search

$ docker container rm alf-postgres

alf-postgres

I removed them in the opposite order to how they were started.

Summary

Deploying and running an ACS solution by starting each container individually is a bit more work. But we were able to learn much more about how things work in a Docker container, and we got to know how to set up a network for the containers to communicate over.

 

However, when you want to get an ACS environment up a running for testing or a PoC project, it is probably more efficient to use Docker Compose.

Building and Deploying custom ACS Images

So far we have looked at how to run the standard ACS solution without any customizations. I’m sure you have customizations that you want to include in your ACS solution, such as a custom domain specific content model. Next we will look at how you build customizations for ACS 6.0.

 

The source code for this section can be downloaded and cloned from here.

Prerequisites

In order to build the projects discussed in this section you will need to have Java and Maven installed. See the instructions at the beginning of this page.

 

You will also need to update your Maven settings file (located at ~/.m2/settings.xml) with the location of the public Alfresco Nexus Repository:

 

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                         https://maven.apache.org/xsd/settings-1.0.0.xsd"
>

   <profiles>
       <profile>
           <id>alfresco.default</id>
           <activation>
               <activeByDefault>true</activeByDefault>
           </activation>
           <repositories>
               <repository>
                   <id>alfresco-public</id>
                   <url>https://artifacts.alfresco.com/nexus/content/groups/public</url>
               </repository>
             </repositories>
           <pluginRepositories>
               <pluginRepository>
                   <id>alfresco-public</id>
                   <name>Alfresco</name>
                 <url>http://artifacts.alfresco.com/nexus/content/repositories/releases</url>
               </pluginRepository>
           </pluginRepositories>
       </profile>
   </profiles>
</settings>

 

Building Repository extensions for ACS 6.0

At the moment there is no support for ACS 6.0 in the Alfresco SDK but we can still build extensions. We just have to do a bit of “engineering”. Assuming you have downloaded the source code for this section you will find as part of it a maven project called custom-repo-extension, which is laid out as a standard Alfresco Platform JAR extension.

 

This project contains a simple content model definition and the bootstrapping for it. It also contains a repository action so we can check that it works to compile against the Alfresco classes. This article is not primarily about building Alfresco extensions so I will not explain that code here.

 

The POM file for the project is the important part as it tells us how we can build against ACS 6.0, it looks like this:

 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <parent>
      <groupId>org.alfresco</groupId>
      <artifactId>acs-community-packaging</artifactId>
      <version>6.0.5-ea</version>
      <relativePath></relativePath>
  </parent>

  <groupId>org.alfresco.training</groupId>
  <artifactId>custom-repo-extension</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>Custom repository extension JAR</name>
  <packaging>jar</packaging>

  <dependencies>
      <dependency>
          <groupId>org.alfresco</groupId>
          <artifactId>alfresco-repository</artifactId>
      </dependency>
  </dependencies>

  <build>
      <resources>
          <resource>
              <directory>src/main/resources</directory>
              <filtering>true</filtering>
          </resource>
      </resources>
  </build>
</project>

 

The Maven POM file starts off with a definition of a Parent POM. This parent project is part of the acs-community-packaging project that we we cloned in the beginning of this article. If you open it up you will find all kinds of useful property definitions and dependency management declarations, for example:

 

 


<properties>
...
  <dependency.alfresco-core.version>7.1</dependency.alfresco-core.version>
  <dependency.alfresco-data-model.version>8.3</dependency.alfresco-data-model.version>
  <dependency.alfresco-repository.version>6.41</dependency.alfresco-repository.version>
  <dependency.alfresco-remote-api.version>6.27</dependency.alfresco-remote-api.version>
  ...
<dependencyManagement>
  <dependencies>
      <dependency>
          <groupId>org.alfresco</groupId>
          <artifactId>alfresco-core</artifactId>
          <version>${dependency.alfresco-core.version}</version>
      </dependency>
      <dependency>
          <groupId>org.alfresco</groupId>
          <artifactId>alfresco-core</artifactId>
          <version>${dependency.alfresco-core.version}</version>
          <classifier>tests</classifier>
      </dependency>
      <dependency>
          <groupId>org.alfresco</groupId>
          <artifactId>alfresco-data-model</artifactId>
          <version>${dependency.alfresco-data-model.version}</version>
      </dependency>
      <dependency>
          <groupId>org.alfresco</groupId>
          <artifactId>alfresco-jlan-embed</artifactId>
          <version>${dependency.alfresco-jlan.version}</version>
      </dependency>
      <dependency>
          <groupId>org.alfresco</groupId>
          <artifactId>alfresco-remote-api</artifactId>
          <version>${dependency.alfresco-remote-api.version}</version>
      </dependency>
      <dependency>
          <groupId>org.alfresco</groupId>
          <artifactId>alfresco-remote-api</artifactId>
          <version>${dependency.alfresco-remote-api.version}</version>
          <classifier>tests</classifier>
      </dependency>
      <dependency>
          <groupId>org.alfresco</groupId>
          <artifactId>alfresco-repository</artifactId>
          <version>${dependency.alfresco-repository.version}</version>
      </dependency>
...

 

This file contains version properties for the different libraries that are part of ACS 6.0.4-ea. So we don’t have to figure this out. It also contains dependencyManagement configurations for the different libraries that we might depend on when building, so we don’t have to specify versions for those in our project.

 

Our project depends on the alfresco-repository library so we can build the custom repository action. We also filter the resource directory so we can use property substitution variables like this: module.id=${project.artifactId} and have them converted to module.id=custom-repo-extension during the build.

 

Now build the extension:

 

custom-repo-extension mbergljung$ mvn clean install

[INFO] Scanning for projects...

[INFO]

[INFO] ------------------------------------------------------------------------

[INFO] Building Custom repository extension JAR 1.0-SNAPSHOT

[INFO] ------------------------------------------------------------------------

[INFO]

[INFO] --- maven-clean-plugin:3.0.0:clean (default-clean) @ custom-repo-extension ---

[INFO] Deleting /Users/mbergljung/DeployProjects/acs-community-packaging-custom/custom-repo-extension/target

[INFO]

[INFO] --- maven-resources-plugin:3.0.1:resources (default-resources) @ custom-repo-extension ---

[INFO] Using 'UTF-8' encoding to copy filtered resources.

[INFO] Copying 6 resources

[INFO]

[INFO] --- maven-compiler-plugin:3.6.0:compile (default-compile) @ custom-repo-extension ---

[INFO] Changes detected - recompiling the module!

[INFO] Compiling 1 source file to /Users/mbergljung/DeployProjects/acs-community-packaging-custom/custom-repo-extension/target/classes

[INFO]

[INFO] --- maven-resources-plugin:3.0.1:testResources (default-testResources) @ custom-repo-extension ---

[INFO] Using 'UTF-8' encoding to copy filtered resources.

[INFO] skip non existing resourceDirectory /Users/mbergljung/DeployProjects/acs-community-packaging-custom/custom-repo-extension/src/test/resources

[INFO]

[INFO] --- maven-compiler-plugin:3.6.0:testCompile (default-testCompile) @ custom-repo-extension ---

[INFO] No sources to compile

[INFO]

[INFO] --- maven-surefire-plugin:2.19.1:test (default-test) @ custom-repo-extension ---

[INFO] No tests to run.

[INFO]

[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ custom-repo-extension ---

[INFO] Building jar: /Users/mbergljung/DeployProjects/acs-community-packaging-custom/custom-repo-extension/target/custom-repo-extension-1.0-SNAPSHOT.jar

[INFO]

[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ custom-repo-extension ---

[INFO] Installing /Users/mbergljung/DeployProjects/acs-community-packaging-custom/custom-repo-extension/target/custom-repo-extension-1.0-SNAPSHOT.jar to /Users/mbergljung/.m2/repository/org/alfresco/training/custom-repo-extension/1.0-SNAPSHOT/custom-repo-extension-1.0-SNAPSHOT.jar

[INFO] Installing /Users/mbergljung/DeployProjects/acs-community-packaging-custom/custom-repo-extension/pom.xml to /Users/mbergljung/.m2/repository/org/alfresco/training/custom-repo-extension/1.0-SNAPSHOT/custom-repo-extension-1.0-SNAPSHOT.pom

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 3.264 s

[INFO] Finished at: 2018-04-06T06:52:08+01:00

[INFO] Final Memory: 42M/339M

[INFO] ------------------------------------------------------------------------

We now have the platform/repo JAR extension in our local Maven repository, ready to be included in a custom Alfresco Repo Image.

Building a custom Repository Image

To build a custom image based on the standard alfresco/alfresco-content-repository-community image we have to create a Dockerfile. We will use a Maven project to bring together all the extensions (both JARs and AMPs) that we want to include in the custom image.

Maven project to assemble all Repository extensions

This project is part of the source code for this article and is called docker-alfresco-custom. It’s used to bring together all the repository extensions that we want to include in the custom Repository image (this Maven project could potentially be used to build the custom image with a plugin such as fabric8io, but this is not covered in this article):

 

The POM looks like this:

 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.alfresco.training</groupId>
  <artifactId>docker-alfresco-custom</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>JAR and AMP assembly under /target for use by Dockerfile</name>
  <packaging>pom</packaging>

  <dependencies>
      <dependency>
          <groupId>org.alfresco.training</groupId>
          <artifactId>custom-repo-extension</artifactId>
          <version>1.0-SNAPSHOT</version>
      </dependency>
      <dependency>
          <groupId>com.softwareloop</groupId>
          <artifactId>uploader-plus-repo</artifactId>
          <version>1.6</version>
          <type>amp</type>
      </dependency>
  </dependencies>

  <build>
      <plugins>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-dependency-plugin</artifactId>
              <version>3.0.2</version>
              <executions>
                  <execution>
                      <id>copy-repo-extensions</id>
                      <phase>process-resources</phase>
                      <goals>
                          <goal>copy</goal>
                      </goals>
                      <configuration>
                          <artifactItems>
                              <artifactItem>
                                  <groupId>org.alfresco.training</groupId>
                                  <artifactId>custom-repo-extension</artifactId>
                                  <version>1.0-SNAPSHOT</version>
                                  <overWrite>false</overWrite>
                           <outputDirectory>${project.build.directory}/jars</outputDirectory>
                              </artifactItem>
                              <artifactItem>
                                  <groupId>com.softwareloop</groupId>
                                  <artifactId>uploader-plus-repo</artifactId>
                                  <version>1.6</version>
                                  <type>amp</type>
                                  <overWrite>false</overWrite>
                        <outputDirectory>${project.build.directory}/amps</outputDirectory>
                              </artifactItem>
                          </artifactItems>
                      </configuration>
                  </execution>
              </executions>
          </plugin>
      </plugins>
  </build>
</project>

 

In the dependencies section we define all the extensions that should be part of our custom repository image. In this case we define a dependency to the custom extension that we built in the previous section, and a dependency to an open source extension that customizes the upload functionality in Alfresco, so you can attach metadata while uploading.

 

The maven-dependency-plugin plugin is used to copy the extensions in under the /target directory. We can then pick them up from there when building the custom repository image.

 

Now build the project:

 

docker-alfresco-custom mbergljung$ mvn clean install

[INFO] Scanning for projects...

[INFO]

[INFO] ------------------------------------------------------------------------

[INFO] Building JAR and AMP assembly under /target for use by Dockerfile 1.0-SNAPSHOT

[INFO] ------------------------------------------------------------------------

[INFO]

[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ docker-alfresco-custom ---

[INFO] Deleting /Users/mbergljung/DeployProjects/acs-community-packaging-custom/docker-alfresco-custom/target

[INFO]

[INFO] --- maven-dependency-plugin:3.0.2:copy (copy-repo-extensions) @ docker-alfresco-custom ---

[INFO] Configured Artifact: org.alfresco.training:custom-repo-extension:1.0-SNAPSHOT:jar

[INFO] Configured Artifact: com.softwareloop:uploader-plus-repo:1.6:amp

[INFO] Copying custom-repo-extension-1.0-SNAPSHOT.jar to /Users/mbergljung/DeployProjects/acs-community-packaging-custom/docker-alfresco-custom/target/jars/custom-repo-extension-1.0-SNAPSHOT.jar

[INFO] Copying uploader-plus-repo-1.6.amp to /Users/mbergljung/DeployProjects/acs-community-packaging-custom/docker-alfresco-custom/target/amps/uploader-plus-repo-1.6.amp

[INFO]

[INFO] --- maven-install-plugin:2.4:install (default-install) @ docker-alfresco-custom ---

[INFO] Installing /Users/mbergljung/DeployProjects/acs-community-packaging-custom/docker-alfresco-custom/pom.xml to /Users/mbergljung/.m2/repository/org/alfresco/training/docker-alfresco-custom/1.0-SNAPSHOT/docker-alfresco-custom-1.0-SNAPSHOT.pom

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 1.271 s

[INFO] Finished at: 2018-04-06T07:45:33+01:00

[INFO] Final Memory: 12M/309M

[INFO] ------------------------------------------------------------------------

What you end up with is a target directory looking like this:

 

docker-alfresco-custom mbergljung$ tree

.

├── Dockerfile

├── pom.xml

└── target

   ├── amps

   │ └── uploader-plus-repo-1.6.amp

   └── jars

       └── custom-repo-extension-1.0-SNAPSHOT.jar

We can now code the Dockerfile to pick up the extensions from this location.

Create the Dockerfile for custom Repository image build

The Dockerfile that we will use to build our custom Repository is located in the same directory as the POM file that assembles the extensions. It looks like the following:

 

FROM alfresco/alfresco-content-repository-community:6.0.5-ea

ARG TOMCAT_DIR=/usr/local/tomcat

RUN mkdir -p $TOMCAT_DIR/amps

COPY target/amps $TOMCAT_DIR/amps
COPY target/jars $TOMCAT_DIR/webapps/alfresco/WEB-INF/lib

RUN java -jar $TOMCAT_DIR/alfresco-mmt/alfresco-mmt*.jar install \
            $TOMCAT_DIR/amps $TOMCAT_DIR/webapps/alfresco -directory -nobackup -force

 

The first thing it does is define that the new image will be based on the standard alfresco/alfresco-content-repository-community image version 6.0.5-ea that is available in Docker Hub. Then it defines a local variable called TOMCAT_DIR, which points to where in the standard image the Apache Tomcat installation is located. We then make sure that the amps directory exists in the image.

 

The next command in the file is to copy AMPs and JARs into the image. JAR extensions are copied directly into the exploded webapp. AMP extensions are copied into the /amps directory from where they will be picked up by the Module Management Tool (MMT).

 

The last step is to use the MMT tool to apply the AMPs to the exploded webapp.

Currently it does not work to put stuff in the {TOMCAT_DIR}/modules/platform directory. JAR extensions are not picked up from this location at the moment.

Build the custom Repository Docker Image

Now the Dockerfile is ready and the AMP and JAR extensions are available, we can build the custom repository image as follows:

 

docker-alfresco-custom mbergljung$ docker build . --tag my-acs-repo:6.0

Sending build context to Docker daemon  41.98kB

Step 1/6 : FROM alfresco/alfresco-content-repository-community:6.0.5-ea

---> df0b08d0d3a3

Step 2/6 : ARG TOMCAT_DIR=/usr/local/tomcat

---> Running in b9da89b41cd7

Removing intermediate container b9da89b41cd7

---> c3379ffbd749

Step 3/6 : RUN mkdir -p $TOMCAT_DIR/amps

---> Running in d5081fd4216c

Removing intermediate container d5081fd4216c

---> b64f819c98f6

Step 4/6 : COPY target/amps $TOMCAT_DIR/amps

---> 69e4c78b184c

Step 5/6 : COPY target/jars $TOMCAT_DIR/webapps/alfresco/WEB-INF/lib

---> 493379108de1

Step 6/6 : RUN java -jar $TOMCAT_DIR/alfresco-mmt/alfresco-mmt*.jar install               $TOMCAT_DIR/amps $TOMCAT_DIR/webapps/alfresco -directory -nobackup -force

---> Running in e5ed4cb90501

Removing intermediate container e5ed4cb90501

---> 3f4a2d48d03a

Successfully built 3f4a2d48d03a

Successfully tagged my-acs-repo:6.0

We call the custom image my-acs-repo and give it a version tag 6.0.

Verify that we have the new image locally:

$ docker image ls

REPOSITORY                                       TAG IMAGE ID CREATED           SIZE

my-acs-repo                                      6.0 b282286605cb 2 minutes ago       1.74GB

alfresco/alfresco-content-repository-community   6.0.5-ea df0b08d0d3a3 8 days ago          1.72GB

alfresco/alfresco-share                          6.0.a 9aaa0425fc95 9 days ago          709MB

alfresco/alfresco-search-services                1.1.1 56575d75dd82 2 months ago        884MB

We can see our image called my-acs-repo and we also have the Docker Hub image that it is based on.

Running a container based on the custom Repository image

We now need to get a container running that is based on our new my-acs-repo image.

The new custom repo image will need a database and search engine so let’s create those first using the standard images as before. We assume here that the alf-net network is still available.

 

Starting with a PostgreSQL container (you might have to stop and remove the container first):

 

$ docker run --network alf-net --name alf-postgres -p 5432:5432 -e POSTGRES_USER=alfresco -e POSTGRES_PASSWORD=alfresco -e POSTGRES_DB=alfresco -d postgres:10.1  

 

And the Alfresco Search Services container (you might have to stop and remove the container first):

 

$ docker run --network alf-net --name alf-search -p 8983:8983 -e SOLR_ALFRESCO_HOST=alf-repo -e SOLR_ALFRESCO_PORT=8080 -e SOLR_SOLR_HOST=alf-search -e SOLR_SOLR_PORT=8983 -e SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive -d alfresco/alfresco-search-services:1.1.1

 

Now let’s start the custom Repo container (you might have to stop and remove the container first):

 

$ docker run --network alf-net --name alf-repo -p 8080:8080 -e JAVA_OPTS='-Ddb.driver=org.postgresql.Driver -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.url=jdbc:postgresql://alf-postgres:5432/alfresco -Dsolr.host=alf-search -Dsolr.port=8983 -Dsolr.secureComms=none -Dsolr.base.url=/solr -Dindex.subsystem.name=solr6' -d my-acs-repo:6.0

d52d18c57d366967f17425771bdc87f5931c2d5b5a6670052ac96b5434152c4a

 

Make sure to use the my-acs-repo:6.0 custom image that we just created. In the logs we should see the new AMP and JAR extension applied:

 

$ docker container logs d52d18c57d366967f17425771bdc87f5931c2d5b5a6670052ac96b5434152c4a

2018-04-06 05:19:31,016  INFO [repo.module.ModuleServiceImpl] [localhost-startStop-1] Found 6 module package(s).

2018-04-06 05:19:31,036  INFO [repo.module.ModuleServiceImpl] [localhost-startStop-1] Installing module 'alfresco-aos-module' version 1.1.7.

2018-04-06 05:19:31,065  INFO [repo.module.ModuleServiceImpl] [localhost-startStop-1] Installing module 'custom-repo-extension' version 1.0-SNAPSHOT.

2018-04-06 05:19:31,090  INFO [repo.module.ModuleServiceImpl] [localhost-startStop-1] Installing module 'org.alfresco.integrations.google.docs' version 3.0.4.2.

2018-04-06 05:19:31,102  INFO [repo.module.ModuleServiceImpl] [localhost-startStop-1] Installing module 'uploader-plus-repo' version 1.6.1801311724.

2018-04-06 05:19:31,121  INFO [repo.module.ModuleServiceImpl] [localhost-startStop-1] Installing module 'alfresco-share-services' version 6.0.0.

2018-04-06 05:19:31,141  INFO [repo.module.ModuleServiceImpl] [localhost-startStop-1] Installing module 'alfresco-trashcan-cleaner' version 2.3.

...

 

In the log above we can verify that the two extensions (i.e. custom-repo-extension and uploader-plus-repo) we added have been installed successfully.

 

Check that you can access the Repository with http://localhost:8080/alfresco/webdav

Re-Building an Alfresco Repo Image

At some point you have to rebuild a custom image. You might have made a mistake in the first build, or you just want to add more extensions.

 

Start by listing your containers to find out which one is based on the custom image:

 

$ docker container ls

CONTAINER ID        IMAGE                      COMMAND CREATED   STATUS PORTS NAMES

d776612160c3        my-acs-repo:6.0                      "catalina.sh run" 5 minutes ago   Up 5 minutes 0.0.0.0:8080->8080/tcp alf-repo

c6e57ff6ca96        alfresco/alfresco-search-services:1.1.0   "/opt/alfresco-searc…" 17 hours ago   Up 17 hours 0.0.0.0:8983->8983/tcp alf-search

dcf89cd04192        postgres:10.1                      "docker-entrypoint.s…" 17 hours ago   Up 17 hours 0.0.0.0:5432->5432/tcp alf-postgres

Stop and remove the relevant containers:

 

$ docker container stop alf-repo alf-search alf-postgres

alf-repo

alf-search

alf-postgres

$ docker container rm alf-repo alf-search alf-postgres

alf-repo

alf-search

alf-postgres

Here we also remove the database and search containers as they are not in sync when restarting a container based on a new image. Any new content that was previously created will be gone when a new container is created based on a rebuilt image. The search service would still have an index for previous content and the database would still have metadata for previous new content. When developing solutions for ACS 6.0 it is a good idea to work with Docker Volumes as you are likely to have to rebuild the repository image a lot.

List all the images:

 

$ docker image ls

REPOSITORY                                       TAG IMAGE ID CREATED           SIZE

my-acs-repo                                      6.0 c133631019ac 7 minutes ago       1.74GB

alfresco/alfresco-content-repository-community   6.0.4-ea df0b08d0d3a3 9 days ago          1.72GB

alfresco/alfresco-share                          6.0.a 9aaa0425fc95 9 days ago          709MB

alfresco/alfresco-search-services                1.1.0 56575d75dd82 2 months ago        884MB

And remove the image that you plan to update:

 

$ docker image rm my-acs-repo:6.0

After this you will have to build the custom image again and restart the database, search, and repo containers.

Building Share extensions for ACS 6.0

At the moment there is no support for ACS 6.0 in the Alfresco SDK but we can still build extensions. We just have to do a bit of “engineering”. Assuming you have downloaded the source code for this section you will find as part of it a maven project called custom-share-extension, which is laid out as a standard Alfresco Share JAR extension.

This Share extension contains the UI labels, forms, and Advanced search configuration for the Repo extension we developed in the previous section. This article is not primarily about building Alfresco extensions so I will not explain that code here.

 

The POM file for the project is the important part as it tells us how we can build against ACS 6.0, it looks like this:

 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.alfresco.training</groupId>
  <artifactId>custom-share-extension</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>Custom share extension JAR</name>
  <packaging>jar</packaging>

  <build>
      <resources>
          <resource>
              <directory>src/main/resources</directory>
              <filtering>true</filtering>
          </resource>
      </resources>
  </build>
</project>

 

The Maven POM file is very straight forward in this case as we just need to package up the files in the src directory. There is no need for any Java file compilation. At the end we also filter the resource directory so we can use property substitution variables like this module.id=${project.artifactId} and have them converted to module.id=custom-share-extension during the build.

 

To build the extension:

 

custom-share-extension mbergljung$ mvn clean install

[INFO] Scanning for projects...

[INFO]

[INFO] ------------------------------------------------------------------------

[INFO] Building Custom share extension JAR 1.0-SNAPSHOT

[INFO] ------------------------------------------------------------------------

[INFO]

[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ custom-share-extension ---

[INFO]

[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ custom-share-extension ---

[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!

[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!

[INFO] Copying 5 resources

[INFO]

[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ custom-share-extension ---

[INFO] No sources to compile

[INFO]

[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ custom-share-extension ---

[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!

[INFO] skip non existing resourceDirectory /Users/mbergljung/DeployProjects/acs-community-packaging-custom/custom-share-extension/src/test/resources

[INFO]

[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ custom-share-extension ---

[INFO] No sources to compile

[INFO]

[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ custom-share-extension ---

[INFO] No tests to run.

[INFO]

[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ custom-share-extension ---

[INFO] Building jar: /Users/mbergljung/DeployProjects/acs-community-packaging-custom/custom-share-extension/target/custom-share-extension-1.0-SNAPSHOT.jar

[INFO]

[INFO] --- maven-install-plugin:2.4:install (default-install) @ custom-share-extension ---

[INFO] Installing /Users/mbergljung/DeployProjects/acs-community-packaging-custom/custom-share-extension/target/custom-share-extension-1.0-SNAPSHOT.jar to /Users/mbergljung/.m2/repository/org/alfresco/training/custom-share-extension/1.0-SNAPSHOT/custom-share-extension-1.0-SNAPSHOT.jar

[INFO] Installing /Users/mbergljung/DeployProjects/acs-community-packaging-custom/custom-share-extension/pom.xml to /Users/mbergljung/.m2/repository/org/alfresco/training/custom-share-extension/1.0-SNAPSHOT/custom-share-extension-1.0-SNAPSHOT.pom

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 1.160 s

[INFO] Finished at: 2018-04-06T14:56:59+01:00

[INFO] Final Memory: 11M/245M

[INFO] ------------------------------------------------------------------------

We now have a Share JAR extension in our local Maven repository, which is ready to be included in a custom Alfresco Share Image.

Building a custom Share Image

To build a custom image based on the standard alfresco/alfresco-share image we have to create a Dockerfile. But we also have to figure out a way to bring together all the extensions (both JARs and AMPs) that we want to include in the custom image. We can do that with a new Maven project.

Maven project to assemble all Share extensions

This project is part of the source code for this article and is called docker-share-custom. It is used to bring together all the Share extensions that we want to include in the custom Share image (this Maven project could potentially also be used to build the custom image with a plugin such as fabric8io, but this is not covered in this article):.

The POM looks like this:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.alfresco.training</groupId>
  <artifactId>docker-share-custom</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>JAR and AMP assembly under /target for use by Dockerfile</name>
  <packaging>pom</packaging>

  <dependencies>
      <dependency>
          <groupId>org.alfresco.training</groupId>
          <artifactId>custom-share-extension</artifactId>
          <version>1.0-SNAPSHOT</version>
      </dependency>
      <dependency>
          <groupId>com.softwareloop</groupId>
          <artifactId>uploader-plus-surf</artifactId>
          <version>1.6</version>
          <type>amp</type>
      </dependency>
  </dependencies>

  <build>
      <plugins>
         <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-dependency-plugin</artifactId>
              <version>3.0.2</version>
              <executions>
                  <execution>
                      <id>copy-share-extensions</id>
                      <phase>process-resources</phase>
                      <goals>
                          <goal>copy</goal>
                      </goals>
                      <configuration>
                          <artifactItems>
                              <artifactItem>
                                  <groupId>org.alfresco.training</groupId>
                                  <artifactId>custom-share-extension</artifactId>
                                  <version>1.0-SNAPSHOT</version>
                                  <overWrite>false</overWrite>
                <outputDirectory>${project.build.directory}/jars</outputDirectory>
                              </artifactItem>
                              <artifactItem>
                                  <groupId>com.softwareloop</groupId>
                                  <artifactId>uploader-plus-surf</artifactId>
                                  <version>1.6</version>
                                  <type>amp</type>
                                  <overWrite>false</overWrite>
                <outputDirectory>${project.build.directory}/amps_share</outputDirectory>
                              </artifactItem>
                          </artifactItems>
                      </configuration>
                  </execution>
              </executions>
          </plugin>
      </plugins>
  </build>
</project>

 

In the dependencies section we define all the extensions that should be part of our custom Share image. In this case we define a dependency to the custom extension that we built in the previous section, and a dependency to an open source extension that customizes the upload functionality in Alfresco so you can attach metadata while uploading.

 

The maven-dependency-plugin plugin is used to copy the extensions in under the /target directory. We can then pick them up from here when building the custom Share image.

 

To build the project:

 

docker-share-custom mbergljung$ mvn clean install

[INFO] Scanning for projects...

[INFO]

[INFO] ------------------------------------------------------------------------

[INFO] Building JAR and AMP assembly under /target for use by Dockerfile 1.0-SNAPSHOT

[INFO] ------------------------------------------------------------------------

[INFO]

[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ docker-share-custom ---

[INFO] Deleting /Users/mbergljung/DeployProjects/acs-community-packaging-custom/docker-share-custom/target

[INFO]

[INFO] --- maven-dependency-plugin:3.0.2:copy (copy-share-extensions) @ docker-share-custom ---

[INFO] Configured Artifact: org.alfresco.training:custom-share-extension:1.0-SNAPSHOT:jar

[INFO] Configured Artifact: com.softwareloop:uploader-plus-surf:1.6:amp

[INFO] Copying custom-share-extension-1.0-SNAPSHOT.jar to /Users/mbergljung/DeployProjects/acs-community-packaging-custom/docker-share-custom/target/jars/custom-share-extension-1.0-SNAPSHOT.jar

[INFO] Copying uploader-plus-surf-1.6.amp to /Users/mbergljung/DeployProjects/acs-community-packaging-custom/docker-share-custom/target/amps/uploader-plus-surf-1.6.amp

[INFO]

[INFO] --- maven-install-plugin:2.4:install (default-install) @ docker-share-custom ---

[INFO] Installing /Users/mbergljung/DeployProjects/acs-community-packaging-custom/docker-share-custom/pom.xml to /Users/mbergljung/.m2/repository/org/alfresco/training/docker-share-custom/1.0-SNAPSHOT/docker-share-custom-1.0-SNAPSHOT.pom

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 0.966 s

[INFO] Finished at: 2018-04-06T15:19:06+01:00

[INFO] Final Memory: 12M/309M

[INFO] ------------------------------------------------------------------------

You now have a target directory that looks like this:

docker-share-custom mbergljung$ tree

.

├── Dockerfile

├── pom.xml

└── target

   ├── amps_share

   │ └── uploader-plus-surf-1.6.amp

   └── jars

       └── custom-share-extension-1.0-SNAPSHOT.jar

We can now code the Dockerfile to pick these extensions up from here.

Create the Dockerfile for custom Share image build

The Dockerfile we will use to build our custom Share image will be located in the same directory as the POM file that assembles the extensions. Here is what it looks like:

 

FROM alfresco/alfresco-share:6.0.a

ARG TOMCAT_DIR=/usr/local/tomcat

RUN mkdir -p $TOMCAT_DIR/amps_share

COPY target/amps_share $TOMCAT_DIR/amps_share
COPY target/jars $TOMCAT_DIR/webapps/share/WEB-INF/lib

RUN java -jar $TOMCAT_DIR/alfresco-mmt/alfresco-mmt*.jar install \
            $TOMCAT_DIR/amps_share $TOMCAT_DIR/webapps/share -directory -nobackup -force

 

The first thing it does is to define that the new image will be based on the standard alfresco/alfresco-share image version 6.0.a that is available in Docker Hub. Then it defines a local variable called TOMCAT_DIR, which points to where in the standard image the Apache Tomcat installation is located. We then make sure that the amps_share directory exists in the image.

 

The next command in the file is to copy AMPs and JARs into the image. JAR extensions are copied directly into the exploded webapp. AMP extensions are copied into the /amps_share directory from where they will be picked up by the Module Management Tool (MMT).

 

The last step is to use the MMT tool to apply the AMPs to the exploded webapp.

Currently it does not work to put stuff in the {TOMCAT_DIR}/modules/share directory. JAR extensions are not picked up from this location at the moment.

Build the custom Share Docker Image

Now when the Dockerfile is ready and the AMP and JAR extensions are available, we can build the custom repository image as follows:

 

docker-share-custom mbergljung$ docker build . --tag my-acs-share:6.0

Sending build context to Docker daemon    108kB

Step 1/6 : FROM alfresco/alfresco-share:6.0.a

---> 9aaa0425fc95

Step 2/6 : ARG TOMCAT_DIR=/usr/local/tomcat

---> Running in 56271fc4b1ff

Removing intermediate container 56271fc4b1ff

---> 91c88b57b1b2

Step 3/6 : RUN mkdir -p $TOMCAT_DIR/amps_share

---> Running in 5287e9a5e61d

Removing intermediate container 5287e9a5e61d

---> 14a48b64c760

Step 4/6 : COPY target/amps_share $TOMCAT_DIR/amps_share

---> 64d5ff319179

Step 5/6 : COPY target/jars $TOMCAT_DIR/webapps/share/WEB-INF/lib

---> 7cf792efec42

Step 6/6 : RUN java -jar $TOMCAT_DIR/alfresco-mmt/alfresco-mmt*.jar install               $TOMCAT_DIR/amps_share $TOMCAT_DIR/webapps/share -directory -nobackup -force

---> Running in 7a3bbefcaf59

Removing intermediate container 7a3bbefcaf59

---> e760d22a715a

Successfully built e760d22a715a

Successfully tagged my-acs-share:6.0

We call the custom image my-acs-share and give it a version tag 6.0.

Verify that you have the new image locally:

 

$ docker image ls

REPOSITORY                                       TAG IMAGE ID CREATED           SIZE

my-acs-share                                     6.0 e760d22a715a 34 seconds ago      709MB

my-acs-repo                                      6.0 c133631019ac 9 hours ago         1.74GB

alfresco/alfresco-content-repository-community   6.0.4-ea df0b08d0d3a3 10 days ago         1.72GB

alfresco/alfresco-share                          6.0.a 9aaa0425fc95 10 days ago         709MB

alfresco/alfresco-search-services                1.1.0 56575d75dd82 2 months ago        884MB

We can see our image called my-acs-share and we also have the Docker Hub image that it is based on.

Running a container based on the custom Share image

Now we can start a container that is based on our new my-acs-share image. It will depend on the Repository, Search, and Database containers, so make sure they are running. The alf-net network must also still be available.

 

To start the custom Share container:

 

$ docker run --network alf-net --name alf-share -p 8081:8080 -e REPO_HOST=alf-repo -e REPO_PORT=8080 -d my-acs-share:6.0

245ee746cb2d5c28183ab67d97e176ffbe57775cfd13a9237791e53254d19429

 

In the logs we should see the new AMP and JAR extension applied:

 

$ docker container logs 245ee746cb2d5c28183ab67d97e176ffbe57775cfd13a9237791e53254d19429

2018-04-06 14:35:54,268  INFO [config.packaging.ModulePackageManager] [localhost-startStop-1] Found 3 module package(s)

2018-04-06 14:35:54,270  INFO [config.packaging.ModulePackageManager] [localhost-startStop-1] Alfresco / Google Docs Share Module, 3.0.4.2, The Share side artifacts of the Alfresco / Google Docs Integration.

uploader-plus-surf, 1.6.1801311724, uploader-plus AMP for Alfresco Share

Custom share extension JAR, 1.0-SNAPSHOT, ${project.description}

...

 

In the log above we can verify that the two extensions (i.e. Custom share extension JAR and uploader-plus-surf) we added have been installed successfully.

 

Check that you can access the Repository with Alfresco Share at http://localhost:8081/share.

 

Login with admin/admin and upload a document to a folder. Execute the Change Type action and you should see the new content type we added:

 

 

After changing the type you should see a new ACME Doc Information property section:

 

 

You can set the ACME Doc ID by clicking the Edit Properties action:

 

Let’s also test the custom uploader functionality to make sure the extension has been applied properly. The custom upload functionality will not be enabled unless you first make some configurations. Start by configuring a so called “Upload folder” under Admin Tools | Uploader Plus:



 

In this case I have selected a custom folder called Test that is a subfolder of Guest Home. I have then said that only ACME Document type is allowed this folder. It’s then just a matter of uploading something to this folder and the custom Upload Plus dialog will appear:



 

So that seems to work nicely, pretty cool!

Building and Running an Alfresco Repo Image with a data Volume

When we run a container based on the Repository image the Alfresco Data (i.e. alf_data) is stored inside the container. The way this works is that an image is made up of a number of read-only layers. When you start a container based on the Repository image an extra read-write layer will be created on top of it. Then when a file is updated, for example in the tomcat/alf_data directory inside the container, it will automatically be copied into the read-write layer (copy-on-write). A container is Ephemeral (lasts a very short time) and when you remove it the Alfresco data will also be gone as the read-write layer is not persisted outside the container.

 

This presents some problems for us as Alfresco Developers as we would be likely to create new images quite frequently as we keep updating different types of extensions. Every time we build a new custom Repository image with new versions of our extensions, and then start a container based on it, we will see that the Alfresco Data we had when testing the previous image is gone. This scenario may be sufficient for some developer scenarios. However, when you start this new container with a fresh content repository the database and search services will still have metadata and an index that matches when the previous content was added. To solve this you need to remove and restart the database and search services containers too.

 

We can get around this problem by connecting a Docker Volume to the Repository Container. The volume would then persists the Alfresco Data (alf_data) outside of the container life cycle.

Types of Docker Volumes

There are many different types of Docker Volumes with different characteristics. We need to choose one that fits our needs:

 

    • Host: A host volume lives on the Docker host's filesystem and can be accessed from within the container. To create a host volume do:
      • docker run -v /path/on/host:/path/in/container ...
    • Anonymous: An anonymous volume is useful for when you would rather have Docker handle where the files are stored. It can be difficult, however, to refer to the same volume over time when it is an anonymous volumes. To create an anonymous volume:
      • docker run -v /path/in/container …
      • Or in a Dockerfile: VOLUME /path/in/container
    • Named: A named volume is similar to an anonymous volume. Docker manages where on disk the volume is created, but you give it a name. To create a named volume use the following commands:
      • docker volume create somevolumename
      • docker run -v somevolumename:/path/in/container ...

 

The type of volume we will use is the Named. We will not use anonymous because it is difficult to find the volume associated with the data we are storing as the volume ID would look something like 08a2eb76f59faebe30ea972a683914f6011f4fe7fd0468152bfd4ff918f6709b. And an anonymous volume created from a Dockerfile would also not be useful as a new anonymous volume would be created every time we create a new container instance. A hosted volume would be very coupled to the operating system we use.

Creating a Named Repo Data Volume  

A named data volume would live its own life completely outside of container instances lifecycles. We can create it as follows for the Repository Data (i.e. alf_data):

 

$ docker volume create alf-repo-data
alf-repo-data


List the available volumes:

 

$ docker volume ls
DRIVER              VOLUME NAME
local               08a2eb76f59faebe30ea972a683914f6011f4fe7fd0468152bfd4ff918f6709b
local               8f5df54fcf77f5f5f8c740218c8a755aa3b18f7fa880631bc1f59d49e7ecbd72
local               alf-repo-data
local               c4b516ba67c1f9bfef106093db054d9388bdf0316f00e8ee2d7e69fcb9e01ee0
local               cecaf0c49f5e2c9fce247ef9ba9b48704707e6674e40f44545dcdc8a0a1e5809
local               de9fde85ca1ae2d60b79dff7386b11e7c6a289eff24bda3aa0ce6e3a01fc05f0
local               e39dacf1af8f1cc0451b2345ac43b5ea471e52f90d99ce92399eb17125d4df37


It’s very easy to spot the named volumes in the listing.

You might see a few volumes here as the PostgreSQL container uses anonymous volumes. We can remove unused volumes as follows:

 

$ docker volume prune
WARNING! This will remove all volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
e39dacf1af8f1cc0451b2345ac43b5ea471e52f90d99ce92399eb17125d4df37
cecaf0c49f5e2c9fce247ef9ba9b48704707e6674e40f44545dcdc8a0a1e5809
8f5df54fcf77f5f5f8c740218c8a755aa3b18f7fa880631bc1f59d49e7ecbd72
de9fde85ca1ae2d60b79dff7386b11e7c6a289eff24bda3aa0ce6e3a01fc05f0
c4b516ba67c1f9bfef106093db054d9388bdf0316f00e8ee2d7e69fcb9e01ee0
alf-repo-data

Total reclaimed space: 112.7MB

Running the Alfresco Repository Container with a Volume

We can now restart the custom Repository container and have it use the named alf-repo-data volume. Before we continue stop and remove all the running containers:

 

$ docker container stop alf-postgres alf-search alf-repo alf-share

$ docker container rm alf-postgres alf-search alf-repo alf-share

 

Now let’s kick off the PostgreSQL and Alfresco Search Services containers so we have  them running when we start the Repository (we assume the Docker network alf-net still exists):

 

$ docker run --network alf-net --name alf-postgres -p 5432:5432 -e POSTGRES_USER=alfresco -e POSTGRES_PASSWORD=alfresco -e POSTGRES_DB=alfresco -d postgres:10.1  

95ba7abc8e62ca912cd8afa87bc4d6e3ac5756a0f3daf854587127fd7e5f31ce

$ docker run --network alf-net --name alf-search -p 8983:8983 -e SOLR_ALFRESCO_HOST=alf-repo -e SOLR_ALFRESCO_PORT=8080 -e SOLR_SOLR_HOST=alf-search -e SOLR_SOLR_PORT=8983 -e SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive -d alfresco/alfresco-search-services:1.1.1 

a9f19ec0e3cc5134db42791fd1247fd85532cf3737f55d9f5aff1bd7f361048c

And now start the repository container based on the my-acs-repo image:

$ docker run -v alf-repo-data:/usr/local/tomcat/alf_data --network alf-net --name alf-repo -p 8080:8080 -e JAVA_OPTS='-Ddb.driver=org.postgresql.Driver -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.url=jdbc:postgresql://alf-postgres:5432/alfresco -Dsolr.host=alf-search -Dsolr.port=8983 -Dsolr.secureComms=none -Dsolr.base.url=/solr -Dindex.subsystem.name=solr6' -d my-acs-repo:6.0

2c601b2e8ec9bf06df877e21e9d60d9e3f9bf67b77c802ae574394ed0571c285

Note here how we attach the container to the alf-repo-data volume and map it to the container directory /usr/local/tomcat/alf-data. As soon as the container is started up all the content under /usr/local/tomcat/alf-data will be copied to the volume.

Review the logs and make sure the Repository container starts successfully:

 

$ docker container logs 2c601b2e8ec9bf06df877e21e9d60d9e3f9bf67b77c802ae574394ed0571c285

11-Apr-2018 12:07:13.058 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]

11-Apr-2018 12:07:13.093 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]

11-Apr-2018 12:07:13.104 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 64455 ms

Inspecting the Repository Data Volume

To see which volume is used by the alf-repo container we can list the volumes (mounts) associated with a container:

 

$ docker container inspect -f "{{ .Mounts }}" alf-repo

[

{

volume alf-repo-data /var/lib/docker/volumes/alf-repo-data/_data /usr/local/tomcat/alf_data

local

z

true

}

]

 

As expected the alf-repo container is associated with the alf-repo-data volume.

 

If we were on a Linux box, such as Ubuntu, we could just list the contents of the /var/lib/docker/volumes/alf-repo-data/_data directory. But on a Mac or Windows machine that does not work as Docker runs inside a Virtual Machine (VM).

 

To see persistent volumes created by Docker for Mac (or Docker for Windows) you need to login to that hidden VM first.

 

To do this, we need to use a serial terminal on a Mac. There's a terminal application called "screen" that we can use:

  1. Open a new terminal window
  2. Use the screen tool to get into the Docker driver by executing command: screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty
  3. You should see a blank screen, just press Enter, and after a while, you should see a command line prompt
  4. Now you're inside Docker's VM and you can cd into the volumes dir by typing: cd /var/lib/docker/volumes/alf-repo-data/_data

Add some content and then re-build the image

Let’s now try and see if we can re-build the custom Alfresco Repository image and still retain the content we have created so far.

Start a Share container and Add some content

Before we rebuild the Repo image we first need to add some content that we can verify with. Start the Alfresco Share container so we can add content:

 

$ docker run --network alf-net --name alf-share -p 8081:8080 -e REPO_HOST=alf-repo -e REPO_PORT=8080 -d alfresco/alfresco-share:6.0.a

160fe60f064515648acbd71fb82b69ec24de33841124943c17b0708ae049acf8

Login to Share and add a folder and file under Guest Home (use admin/admin when login):

Update and Build the Repo Extension

We will now make a small change to the custom-repo-extension/src/main/java/com/acme/alfresco/action/CustomRepoAction.java file to simulate that we have developed a new version of our Repo extension:

 

public class CustomRepoAction extends ActionExecuterAbstractBase {
  private static final Logger LOG = LoggerFactory.getLogger(CustomRepoAction.class);

  @Override
  protected void addParameterDefinitions(List<ParameterDefinition> paramList) {
      // No parameters are passed to action
  }

  @Override
  protected void executeImpl(Action action, NodeRef actionedUponNodeRef) {
      System.out.println("Now, do something ... UPDATED");
  }
}

 

In this case I just updated the println statement.

 

Now build the project to create a new extension version:

 

custom-repo-extension mbergljung$ mvn clean install

[INFO] Scanning for projects...

[INFO]

[INFO] ------------------------------------------------------------------------

[INFO] Building Custom repository extension JAR 1.0-SNAPSHOT

[INFO] ------------------------------------------------------------------------

[INFO]

....

[INFO] Installing /Users/mbergljung/DeployProjects/acs-community-packaging-custom/custom-repo-extension/pom.xml to /Users/mbergljung/.m2/repository/org/alfresco/training/custom-repo-extension/1.0-SNAPSHOT/custom-repo-extension-1.0-SNAPSHOT.pom

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 3.463 s

[INFO] Finished at: 2018-04-12T08:29:30+01:00

[INFO] Final Memory: 42M/324M

[INFO] ------------------------------------------------------------------------

Rebuild the Repo image and restart Repo container

With the new extension version ready we can rebuild the Repo Image:

 

docker-alfresco-custom mbergljung$ docker build .  --tag my-acs-repo:6.1

Sending build context to Docker daemon  44.03kB

Step 1/6 : FROM alfresco/alfresco-content-repository-community:6.0.4-ea

---> df0b08d0d3a3

Step 2/6 : ARG TOMCAT_DIR=/usr/local/tomcat

---> Using cache

---> 1b0322f285fb

Step 3/6 : RUN mkdir -p $TOMCAT_DIR/amps

---> Using cache

---> 393c1f52691f

Step 4/6 : COPY target/amps $TOMCAT_DIR/amps

---> Using cache

---> 56260db9a225

Step 5/6 : COPY target/jars $TOMCAT_DIR/webapps/alfresco/WEB-INF/lib

---> Using cache

---> 09f8f701f2a2

Step 6/6 : RUN java -jar $TOMCAT_DIR/alfresco-mmt/alfresco-mmt*.jar install               $TOMCAT_DIR/amps $TOMCAT_DIR/webapps/alfresco -directory -nobackup -force

---> Using cache

---> fd4bb88fe25d

Successfully built fd4bb88fe25d

Successfully tagged my-acs-repo:6.1

We give the new image the name my-acs-repo, which is the same name as we used before. But we use version 6.1 to denote a newer build with newer versions of the extensions (we could remove version 6.0 of the image and use the same version number if we wanted to).

Now list the images to verify that we got version 6.1:

 

docker-alfresco-custom mbergljung$ docker image ls

REPOSITORY                                       TAG IMAGE ID CREATED           SIZE

my-acs-repo                                      6.1 fd4bb88fe25d 26 hours ago        1.74GB

my-acs-repo                                      6.0 8816690d43e7 2 days ago          1.72GB

my-acs-share                                     6.0 e760d22a715a 6 days ago          709MB

...

With the new 6.1 image available we can stop, remove, and restart the Repo container:

$ docker container stop alf-repo

alf-repo

$ docker container rm alf-repo

alf-repo

 

Make sure the named volume is still there:

$ docker volume ls

DRIVER              VOLUME NAME

local               08a2eb76f59faebe30ea972a683914f6011f4fe7fd0468152bfd4ff918f6709b

local               alf-repo-data

...

Start the repository container based on version 6.1 of the my-acs-repo image:

$ docker run -v alf-repo-data:/usr/local/tomcat/alf_data --network alf-net --name alf-repo -p 8080:8080 -e JAVA_OPTS='-Ddb.driver=org.postgresql.Driver -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.url=jdbc:postgresql://alf-postgres:5432/alfresco -Dsolr.host=alf-search -Dsolr.port=8983 -Dsolr.secureComms=none -Dsolr.base.url=/solr -Dindex.subsystem.name=solr6' -d my-acs-repo:6.1

1c5b74efa499f3624ece7b995bddc81e53548b3b4047bf238156c2b693cce471

 

Review the logs and make sure it is up and running.

Make sure content is intact

And now to the fun part. Login to Share, if needed, and make sure the folder and file previously uploaded is still there. They are kept in the external named volume, which should be independent of container life cycle.

Building and Running an Alfresco Repo Image with MySQL

Event though this article focuses a lot on the development environment you might still want to run it with a different database than the out-of-the-box PostgreSQL alternative. Maybe you like MySQL more, or have more experience with it.

 

In this section we will have a look at how to run a MySQL container instead of the PostgreSQL container. We will also have to figure out how to install the MySQL Connector JDBC driver into the Repository container.

Running a MySQL container with the Alfresco Database

The Alfresco Repo is going to connect to a MySQL database called ‘alfresco’ where the Repository can store the metadata for the content files. We can easily fire up a MySQL database with images available at https://hub.docker.com/_/mysql/.

 

We can look at the Docker Hub page for MySQL to see what environment variables we need to use to configure the database image. Kick off a new MySQL container as follows and give the new container the name alf-mysql (we assume that the alf-net network still exists):

 

$ docker run --network alf-net --name alf-mysql -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=alfresco -e MYSQL_USER=alfresco -e MYSQL_PASSWORD=alfresco -d mysql:5.7.17 --character-set-server=utf8 --collation-server=utf8_general_ci --max_connections=1024

7921db488804459ebfa84dd6f5ff89d33bd4412f0fa690d4dda38f88394f6b50

 

The --network option must be specified directly after run. It cannot, for example, be at the end of the command.

 

Here we start a MySQL container with user/pwd alfresco/alfresco and configure it to create the default database with the name alfresco, which is what the repository needs. The database server is available externally on port 3306. We also connect the container to the alf-net network we created earlier on. The command returns the new container’s ID.

 

Test that it all worked by logging into the container and accessing the database (note that we use the short ID for the container):

 

$ docker container ls

CONTAINER ID        IMAGE COMMAND                  CREATED STATUS PORTS                    NAMES

7921db488804        mysql:5.7.17 "docker-entrypoint.s…"   19 seconds ago Up 20 seconds 0.0.0.0:3306->3306/tcp   alf-mysql

 

$ docker container exec -it 7921db488804 /bin/bash

root@7921db488804:/# mysql -u alfresco -p

Enter password:

Welcome to the MySQL monitor.  Commands end with ; or \g.

Your MySQL connection id is 3

Server version: 5.7.17 MySQL Community Server (GPL)

 

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

 

Oracle is a registered trademark of Oracle Corporation and/or its

affiliates. Other names may be trademarks of their respective

owners.

 

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

 

mysql> show tables;

Empty set (0.00 sec)

 

mysql> exit;

Bye

root@7921db488804:/# exit

exit

Building and Running an Alfresco Repo Container connecting to MySQL

The Alfresco database is now ready in the MySQL container. We need to build a Repository image containing the mysql-connector-java-5.1.42.jar JDBC driver.

Create and run a POM file that brings in the MySQL connector

First we will create a Maven POM that defines a dependency to the MySQL Connector and then copies it into the target/libs directory when we run the build. This POM is part of the acs-community-packaging-custom project that you downloaded earlier on. If you look into the docker-alfresco-custom-mysql sub-project you will find the POM file, which looks like this:

 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.alfresco.training</groupId>
  <artifactId>docker-alfresco-custom-mysql</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>LIB assembly under /target for use by Dockerfile</name>
  <packaging>pom</packaging>

  <dependencies>
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>5.1.42</version>
      </dependency>
  </dependencies>

  <build>
      <plugins>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-dependency-plugin</artifactId>
              <version>3.0.2</version>
              <executions>
                  <execution>
                      <id>copy-libs</id>
                      <phase>process-resources</phase>
                      <goals>
                          <goal>copy</goal>
                      </goals>
                      <configuration>
                          <artifactItems>
                              <artifactItem>
                                  <groupId>mysql</groupId>
                                  <artifactId>mysql-connector-java</artifactId>
                                  <version>5.1.42</version>
                                  <overWrite>false</overWrite>
                    <outputDirectory>${project.build.directory}/libs</outputDirectory>
                               </artifactItem>
                          </artifactItems>
                      </configuration>
                  </execution>
              </executions>
          </plugin>
      </plugins>
  </build>
</project>

 

This POM file defines a dependency to the correct version (i.e. the supported one) of the MySQL JDBC connector and then we use the maven-dependency-plugin to copy the jar into the target/libs directory, where it will be ready to be picked up by the Dockerfile.

 

Now run the build:

 

docker-alfresco-custom-mysql mbergljung$ mvn clean install

[INFO] Scanning for projects...

[INFO]

[INFO] ------------------------------------------------------------------------

[INFO] Building LIB assembly under /target for use by Dockerfile 1.0-SNAPSHOT

[INFO] ------------------------------------------------------------------------

[INFO]

[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ docker-alfresco-custom-mysql ---

[INFO] Deleting /Users/mbergljung/DeployProjects/acs-community-packaging-custom/docker-alfresco-custom-mysql/target

[INFO]

[INFO] --- maven-dependency-plugin:3.0.2:copy (copy-libs) @ docker-alfresco-custom-mysql ---

[INFO] Configured Artifact: mysql:mysql-connector-java:5.1.42:jar

[INFO] Copying mysql-connector-java-5.1.42.jar to /Users/mbergljung/DeployProjects/acs-community-packaging-custom/docker-alfresco-custom-mysql/target/libs/mysql-connector-java-5.1.42.jar

[INFO]

[INFO] --- maven-install-plugin:2.4:install (default-install) @ docker-alfresco-custom-mysql ---

[INFO] Installing /Users/mbergljung/DeployProjects/acs-community-packaging-custom/docker-alfresco-custom-mysql/pom.xml to /Users/mbergljung/.m2/repository/org/alfresco/training/docker-alfresco-custom-mysql/1.0-SNAPSHOT/docker-alfresco-custom-mysql-1.0-SNAPSHOT.pom

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 0.916 s

[INFO] Finished at: 2018-04-10T15:14:22+01:00

[INFO] Final Memory: 12M/309M

[INFO] ------------------------------------------------------------------------

Looking in the target/libs directory we should now see the following:

docker-alfresco-custom-mysql mbergljung$ tree

.

├── Dockerfile

├── pom.xml

└── target

   └── libs

       └── mysql-connector-java-5.1.42.jar

Create and build a Dockerfile that injects the MySQL Connector

We are now ready to create the Dockerfile that injects the MySQL JDBC driver into the Repository image. The Dockerfile looks as follows and is also located in the docker-alfresco-custom-mysql directory:

 

FROM alfresco/alfresco-content-repository-community:6.0.5-ea

ARG TOMCAT_LIB_DIR=/usr/local/tomcat/lib

COPY target/libs $TOMCAT_LIB_DIR

 

The file is very simple, it just takes the standard Repository image as a starting point and then copies the JDBC driver into it. Building the image looks like this:

 

docker-alfresco-custom-mysql mbergljung$ docker build . --tag my-acs-repo-mysql:6.0

Sending build context to Docker daemon  1.004MB

Step 1/3 : FROM alfresco/alfresco-content-repository-community:6.0.5-ea

---> df0b08d0d3a3

Step 2/3 : ARG TOMCAT_LIB_DIR=/usr/local/tomcat/lib

---> Using cache

---> e14ed38cfbe5

Step 3/3 : COPY target/libs $TOMCAT_LIB_DIR

---> Using cache

---> 8816690d43e7

Successfully built 8816690d43e7

Successfully tagged my-acs-repo-mysql:6.0

We give the new image the name my-acs-repo-mysql and version 6.0. List the images so we see that it worked:

$ docker image ls

REPOSITORY                                       TAG IMAGE ID CREATED            SIZE

my-acs-repo-mysql                                6.0 8816690d43e7 About a minute ago   1.72GB

my-acs-repo                                      6.0 8816690d43e7 About a minute ago   1.72GB

...

Run the Alfresco Repository Container with MySQL

We are now ready to kick off the custom Repository container with the MySQL JDBC driver and connect to the MySQL container. But let’s first kick off the Alfresco Search Services container so we have that running when the repo starts up:

 

$ docker run --network alf-net --name alf-search -p 8983:8983 -e SOLR_ALFRESCO_HOST=alf-repo -e SOLR_ALFRESCO_PORT=8080 -e SOLR_SOLR_HOST=alf-search -e SOLR_SOLR_PORT=8983 -e SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive -d alfresco/alfresco-search-services:1.1.1 

0b4ca7a949adb2d8b2f07cb1d5ec95a51b350c54c762a577b3f275742d1b95d1

And now the repository container based on the my-acs-repo-mysql image:

$ docker run --network alf-net --name alf-repo -p 8080:8080 -e JAVA_OPTS='-Ddb.driver=org.gjt.mm.mysql.Driver -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.url="jdbc:mysql://alf-mysql:3306/alfresco?useUnicode=yes&characterEncoding=UTF-8" -Dsolr.host=alf-search -Dsolr.port=8983 -Dsolr.secureComms=none -Dsolr.base.url=/solr -Dindex.subsystem.name=solr6' -d my-acs-repo-mysql:6.0

cdad9c60dd0e46bad24c7e5ff96a2c76b964616905e5effa2664a6b51e8c1af3

Review the logs and make sure it connects to MySQL successfully:

$ docker container logs cdad9c60dd0e46bad24c7e5ff96a2c76b964616905e5effa2664a6b51e8c1af3

10-Apr-2018 15:30:06.292 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version:        Apache Tomcat/8.5.28

.

org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Ddb.driver=org.gjt.mm.mysql.Driver

10-Apr-2018 15:30:06.298 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Ddb.username=alfresco

10-Apr-2018 15:30:06.298 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Ddb.password=alfresco

10-Apr-2018 15:30:06.298 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Ddb.url=jdbc:mysql://alf-mysql:3306/alfresco?useUnicode=yes&characterEncoding=UTF-8

...

2018-04-10 15:30:28,393  INFO [alfresco.repo.admin] [localhost-startStop-1] Using database URL 'jdbc:mysql://alf-mysql:3306/alfresco?useUnicode=yes&characterEncoding=UTF-8' with user 'alfresco'.

2018-04-10 15:30:28,394  INFO [alfresco.repo.admin] [localhost-startStop-1] Connected to database MySQL version 5.7.17

...

2018-04-10 15:30:42,972  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Connecting to database: jdbc:mysql://alf-mysql:3306/alfresco?useUnicode=yes&characterEncoding=UTF-8, UserName=alfresco@172.21.0.4, MySQL Connector Java

2018-04-10 15:30:42,972  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Schema managed by database dialect org.alfresco.repo.domain.dialect.MySQLInnoDBDialect.

2018-04-10 15:30:43,118  WARN [domain.schema.SchemaBootstrap] [localhost-startStop-1] Schema validation found 46 potential problems, results written to: /usr/local/tomcat/temp/Alfresco/Alfresco-MySQLInnoDBDialect-Validation-Pre-Upgrade-alf_-1005770665855180801.txt

2018-04-10 15:30:43,133  WARN [domain.schema.SchemaBootstrap] [localhost-startStop-1] Schema validation found 25 potential problems, results written to: /usr/local/tomcat/temp/Alfresco/Alfresco-MySQLInnoDBDialect-Validation-Pre-Upgrade-act_-2723159380226551365.txt

2018-04-10 15:30:43,214  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Normalized schema dumped to file /usr/local/tomcat/temp/Alfresco/Alfresco-schema-MySQLInnoDBDialect-pre-upgrade-alf_-7824608645271764904.xml.

2018-04-10 15:30:43,214  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Normalized schema dumped to file /usr/local/tomcat/temp/Alfresco/Alfresco-schema-MySQLInnoDBDialect-pre-upgrade-act_-1758568877658060149.xml.

2018-04-10 15:30:43,278  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Executing database script /usr/local/tomcat/temp/Alfresco/AlfrescoSchema-MySQLInnoDBDialect-Update-4701688511608734693.sql (Copied from classpath:alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-RepoTables.sql).

2018-04-10 15:30:43,728  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Executing database script /usr/local/tomcat/temp/Alfresco/AlfrescoSchema-MySQLInnoDBDialect-Update-1660864257659333372.sql (Copied from classpath:alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-LockTables.sql).

2018-04-10 15:30:43,765  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Executing database script /usr/local/tomcat/temp/Alfresco/AlfrescoSchema-MySQLInnoDBDialect-Update-8147065905659118747.sql (Copied from classpath:alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-ContentTables.sql).

2018-04-10 15:30:43,843  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Executing database script /usr/local/tomcat/temp/Alfresco/AlfrescoSchema-MySQLInnoDBDialect-Update-2319822585342629214.sql (Copied from classpath:alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-PropertyValueTables.sql).

2018-04-10 15:30:43,982  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Executing database script /usr/local/tomcat/temp/Alfresco/AlfrescoSchema-MySQLInnoDBDialect-Update-7958840531865558083.sql (Copied from classpath:alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-ContentUrlEncryptionTables.sql).

2018-04-10 15:30:44,014  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Executing database script /usr/local/tomcat/temp/Alfresco/AlfrescoSchema-MySQLInnoDBDialect-Update-1493698802374057751.sql (Copied from classpath:alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-AuditTables.sql).

2018-04-10 15:30:44,071  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Executing database script /usr/local/tomcat/temp/Alfresco/AlfrescoSchema-MySQLInnoDBDialect-Update-3935710904755261199.sql (Copied from classpath:alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-ActivityTables.sql).

2018-04-10 15:30:44,121  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Executing database script /usr/local/tomcat/temp/Alfresco/AlfrescoSchema-MySQLInnoDBDialect-Update-2654492923882306612.sql (Copied from classpath:alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-UsageTables.sql).

2018-04-10 15:30:44,147  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Executing database script /usr/local/tomcat/temp/Alfresco/AlfrescoSchema-MySQLInnoDBDialect-Update-481654729795371565.sql (Copied from classpath:alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-SubscriptionTables.sql).

2018-04-10 15:30:44,162  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Executing database script /usr/local/tomcat/temp/Alfresco/AlfrescoSchema-MySQLInnoDBDialect-Update-7428379169648063519.sql (Copied from classpath:alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-TenantTables.sql).

2018-04-10 15:30:44,184  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Executing database script /usr/local/tomcat/temp/Alfresco/AlfrescoSchema-MySQLInnoDBDialect-Update-4157934858382764547.sql (Copied from classpath:alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-AuthorizationTables.sql).

2018-04-10 15:30:44,215  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Create scripts executed in 1209 ms

2018-04-10 15:30:46,029  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] All executed statements:  /usr/local/tomcat/temp/Alfresco/AlfrescoSchema-MySQLInnoDBDialect-All_Statements-638494183242731673.sql.

2018-04-10 15:30:46,317  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Compared database schema with reference schema (all OK): class path resource [alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/Schema-Reference-ALF.xml]

2018-04-10 15:30:46,507  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Compared database schema with reference schema (all OK): class path resource [alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/Schema-Reference-ACT.xml]

2018-04-10 15:30:46,870  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Normalized schema dumped to file /usr/local/tomcat/temp/Alfresco/Alfresco-schema-MySQLInnoDBDialect-post-upgrade-alf_-1249302916559560216.xml.

2018-04-10 15:30:46,870  INFO [domain.schema.SchemaBootstrap] [localhost-startStop-1] Normalized schema dumped to file /usr/local/tomcat/temp/Alfresco/Alfresco-schema-MySQLInnoDBDialect-post-upgrade-act_-1757141603492957245.xml.

[localhost-startStop-1] Alfresco Content Services started (Community Early Access). Current version: 6.0.4 (re493fa84-b38) schema 10,201. Originally installed version: 6.0.4 (re493fa84-b38) schema 10,201.

...

Check access via WebDAV

Verify that the Repository container is up and running successfully with the MySQL database. Connect to WebDAV via http://localhost:8080/alfresco/webdav.

If you are interested to migrate contents into your Alfresco repository and you have to get contents from different data sources, you may be interested to see my session held with my friend Luis Cabaceira during the last Alfresco DevCon 2018 in Lisbon.

 

The title of our session is Smart Content Migration using Apache ManifoldCF and we have described two different scenarios based on a pretty new capability that we are adding: content migration!

 

This will make easier content migration needs for any ECM architect or developer involved in migration for federating different silos / repositories into an Alfresco platform. We have implemented these two new connectors:

  • CMIS Output Connector (presented by me)
  • Alfresco BFSI Output Connector (presented by Luis)

 

CMIS Output Connector allows to migrate contents from any repositories supported by ManifoldCF: from SharePoint, Documentum to FileNet and so on to any CMIS-compliant repo such as Alfresco 

 

Alfresco BFSI Output Connector allows to get contents from any repo and it will create the standard structure on file system to allow Alfresco importing contents using the BFSI tool. This is absolutely amazing in terms of performance!

 

Migration architecture of the new Content Migration included in Apache ManifoldCF

 

 

Try by yourself the new connectors for Content Migration (beta)

Please consider that all the material shown during the session is related to a development sprint that we have to complete and you will not find yet this new features inside the stable release of ManifoldCF.

 

Anyway you can try these new connectors building from the related branch:

 

CMIS Output Connector

JIRA issue: https://issues.apache.org/jira/browse/CONNECTORS-1356
Source code: https://svn.apache.org/repos/asf/manifoldcf/branches/CONNECTORS-1356-2.7.1/


Alfresco BFSI Output Connector

JIRA issue: https://issues.apache.org/jira/projects/CONNECTORS/issues/CONNECTORS-1442
Source code: https://svn.apache.org/repos/asf/manifoldcf/branches/CONNECTORS-1442/

 

Stay in touch with us in the ManifoldCF Community

If you are interested in our work, also if you want to contribute , please consider to stay in touch with us subscribing our mailing lists or entering in our chatroom to follow the development of Apache ManifoldCF, below all the references:

 

Web Forums / Mailing lists

https://lists.apache.org/list.html?dev@manifoldcf.apache.org

https://lists.apache.org/list.html?user@manifoldcf.apache.org

 

Classic Mailing list

http://manifoldcf.apache.org/en_US/mail.html

 

HipChat Public Room

https://www.hipchat.com/gOSgu3lH8

 

 

A complete article about my involvement during Alfresco DevCon 2018 can be found on my website.

 

If you need a quote about design and implementation of migration projects, please contact us.

We are looking forward to talk with you to understand how we can help you here in TAI Solutions.

We are excited to announce our latest release of Community RM, following 2.6.c from November last year.
Community release 2.7.a is now available here and provides support for Alfresco Community 201711. In this release we

have improved our patching system and included some important bug fixes.

 

What's new in 2.7.a?

 

We've updated our patching system that will run accordingly to the versions that we have in the upgrade.
The change avoids running unnecessary patches, see RM-5927 for details.

 

We added a validation test for yaml files. We now validate them against Swagger 2.0 standard which allows us to detect problems earlier(RM-5875).

 

In this release we fixed a couple of retention schedule bugs for record level retentions. While in the previous version we experienced problems when (re-)calculating disposition date, now the time periods are properly set (RM-4248, RM-5733). Retention schedule is an important feature in GS that define how records are managed in the system. A retention schedule is associated to a record category and can contain one or more steps. Each step has an action that will be triggered after a period of time (e.g  the creation date, completion date or the date of the last retention action) or when a specified event occurs.

 

 

A quick overview about other issues we fixed can be found below.

RM-1503: A security fix against XSS attacks was added.

RM-5878: An issue for RM Saved Search which was reproducing randomly. 

RM-5987: For performance considerations we replaced the "View full log" button and its functionality and made it configurable.

 

 

What's coming up next?

 

As we promised we will continue to have frequent community releases that will keep you up to date.
New features and compatiblity with 6.0.x will be adressed starting from AGS 3.0.a.
We'd be happy to hear any feedback from you or any eventual issues you encounter on this release.

 

Thanks!

 

Links

Later in the year we will be launching a new enterprise analytics product for Alfresco built on top of Search Services and Solr.

 

One of the capabilities it will bring is the ability to write SQL queries against the Solr datastore and so I wanted to share where we are with that SQL support. Below we have documented how the SQL works and also listed what isn't yet supported at the end.

 

I'd love to know what you think about the level of support so do comment or message with any feedback or questions.

 

 

 

SELECT statements

 

The basic syntax of the SQL select is as follows:

Select DBID, cm_creator as creator, `cm_content.size`  as size from alfresco where `cm_content.size` > 1000 order by  `cm_content.size` desc limit 100

In the sections below we’ll explain and expand on the different aspects of this SQL statement.

 

Table

 

For the EA release the only table that can be specified is the alfresco table. The alfresco table contains the documents and fields that have been indexed within the Alfresco Indexing Server’s main alfresco index.

 


Fields

 

Standard Fields

 

Alfresco has a set of standard fields, which can be referred to by name in the SQL field list. The DBID field in the example SELECT statement is an example of a standard field.

 

The most useful ones are: PARENT, PATH, ANCESTOR, TYPE, ASPECT, PROPERTIES, NULLPROPERTIES, FIELDS, LID and  DBID.

 

 

Fields from Content Models

 

Fields from Alfresco’s out of-the-box content models as well as fields from custom content models can be referred to using the content model property qname, as in AFTS and the CMIS query language. The cm_creator field in the example SQL statement refers to the creator field in the out-of-the-box cm content model. Fields that have a unique local name over all prefixes do not need to use the prefix. Note that we use "_" to separate the prefix and the locale name as ":" would have to be escaped.

 

Escaping Fields

 

Fields that include reserved words or special characters will need to be escaped using the back tick character (`). The `cm_content.size` field in the example SQL statement is an example of back tick escaping. The only non-word character that can be used without escaping is the underscore “_”. 

 

Under the covers the implementation uses Apache Calcite which has a list of reserved words that would also need to be escaped. You are most likely to hit reserved keywords picking aliases for fields.

 

Field Aliases

 

SQL field aliases are supported in the field list. Field aliases cannot be used in the WHERE, ORDER BY or HAVING clauses. Field aliases that contain special characters or reserved words will need to be escaped with the back tick.

 

Predicate

 

Alfresco’s SQL predicate is designed to take advantage of the rich search capabilities available in the Alfresco Search Service.

 

Predicates on Text Fields

 

The basic predicate on a text field performs a phrase search. Below is the syntax of a basic predicate on a text field:

select DBID from alfresco where cm_content = ‘hello world’

This will search for the phrase ‘hello world’ in the cm_content field.

 

To gain full control of the search predicate for a specific field you can wrap the predicate in parenthesis and enter the query using Alfresco full text search syntax. For example to search for (hello OR world) in the cm_content field the following search predicate can be used:

select DBID from alfresco where cm_content = ‘(hello OR world)’

 

Predicates on String Identifier Fields

 

Predicates on string identifier fields will perform an exact match on the field.  For example:

select DBID, LID from alfresco where LID = ‘value’

The SQL statement above will perform an exact match on the LID field.

 

Most fields from the content models will perform full text search matches unless the property is defined as tokenised false in the model.
This may not be what you expect.

 

Predicates on Numeric Fields

 

The predicate on numeric fields can perform =, >=, <= and Alfresco Solr range queries.

 

Below are some examples using the =, >=, <=

select DBID, LID from alfresco where DBID = 123

select DBID, LID from alfresco where DBID >= 123

select DBID, LID from alfresco where DBID <= 123

select DBID, LID from alfresco where DBID >= 100 AND DBID <=123

 

Below are examples of Alfresco Solr range queries:

select DBID, LID from alfresco where DBID =’[* TO 123]’

This will select all DBIDs below 123, with inclusive ranges. The square brackets are inclusive ranges.

 

select DBID, LID from alfresco where DBID =’[* TO 123>’

This will select all DBIDs below 123, with an exclusive top range. < and > are exclusive ranges.

 

select DBID, LID from alfresco where DBID =’[123 TO *]’

This will select all DBIDs  above 123, with inclusive ranges.

 

select DBID, LID from alfresco where DBID =’<123 TO *]’

This will select all DBIDs above 123, with an exclusive bottom range.

 

select DBID, LID from alfresco where DBID =’<100 TO 123>’

This will select all DBIDs above 100 and below 123, with an exclusive top and bottom range.

 

Nested Boolean Predicates

 

SQL predicates can be combined with Boolean operators AND, OR and NOT and nested with parenthesis.

select DBID from alfresco where (cm_content = ‘hello world’ AND (DBID >= 100 AND DBID < 200))

 

Order By

 

SQL SELECT statements can contain an ORDER  BY clause with one or more order by fields. String identifiers and numeric fields can be specific in the ORDER BY clause.

 

Below is an example of  an ORDER BY on a numeric field:

select cm_creator, cm_name, exif_manufacturer, audio_trackNumber from alfresco order by audio_trackNumber asc

 

Limit

 

SQL SELECT statements can contain a LIMIT clause. If no limit is specified a default limit of 1000 is set. Caution should be used when increasing the default limit as performance and memory consumption increase as the limit increases.

 

SELECT DISTINCT statements

 

The basic syntax for SELECT DISTINCT syntax is as follows:

select distinct cm_name from alfresco where cm_content = 'world' order by cm_name asc

 

SELECT DISTINCT queries can also have multiple fields and multiple order by fields.

Aggregations Without GROUP BY

 

SQL aggregations without a GROUP BY clause return a single result tuple with the aggregation results. Below is an example:

 

select count(*) as count, avg(`cm_content.size`) as content_size from alfresco where cm_owner = 'xyz'

Aggregate functions

 

Alfresco SQL supports the following aggregation functions:

 

count(*)

sum(numeric_field)

avg(numeric_field)

min(numeric_field)

max(numeric_field)

 

Aggregate Fields

 

 

Any numeric field can be used within the aggregations sum, avg, min and max. As with the basic SELECT statements, aggregation fields defined by content models can be referenced using the content model prefix. Fields that are reserved words or contain special characters will need to be escaped with the back tick character.

 

Aggregate Result Tuple

 

 

If a field alias is specified for an aggregate function then the field alias will appear in the result tuple. If field aliases are not used then the field name for the aggregate functions will appear as follows: EXPR$1, EXPR$2. These values refer to the function expression by the order they appear in the field list, starting from 1. For example the first function that appears in the query will be named EXPR$1 in the result tuples.

 

Aggregations With GROUP BY

 

SQL aggregations with a GROUP BY clause are also supported and take the following form:

 

select `cm_content.mimetype`, count(*) as total_count from alfresco group by `cm_content.mimetype` having count(*) < 4 order by count(*) asc

 

Aggregate functions

 

Alfresco SQL supports the following aggregation functions: count(*), sum(numeric_field), avg(numeric_field), min(numeric_field), max(numeric_field).

 

Aggregation Fields

 

Any numeric field can be used within the aggregations sum, avg, min and max. As with the basic SELECT statements fields defined by content models can be referenced using the content model prefix. Fields that are reserved words or contain special characters will need to be escaped with the back tick character.

 

Group By Fields

 

One or more fields can be specified as group by fields. Fields that are designated as facetable in a content model will provide the best aggregation results.

Aggregate Result Tuples

 

 

If a field alias is specified for an aggregate function then the field alias will appear in the result tuple. If field aliases are not used then the field name for the aggregate functions will appear as follows: EXPR$1, EXPR$2. These values refer to the function expression by the order they appear in the query, starting from 1. For example the first function that appears in the query will be named EXPR$1 in the result tuples.

Order by

 

One or more fields may used in the ORDER BY clause. The ORDER BY clause can include both fields from the field list and aggregate functions. Field aliases cannot be used in the ORDER BY clause. When referring to an aggregate function in the ORDER BY clause the function call as it appears in the field list should be used.

Having

 

 

The HAVING clause is supported for aggregation functions only. Boolean logic and nested HAVING clauses are supported. The following comparison operations are supported in the HAVING clause: =, >=, <=, !=.

 

Limit

A LIMIT clause can be used to limit the number of aggregations results. If no LIMIT clause is provided a default limit of 1000 is applied. 

Time Series Aggregations

 

There is specific support for SQL time series reporting through the use of virtual time dimensions. The section below describes how virtual time dimensions are used.

 

Virtual Time Dimensions

 

Virtual time dimensions for every datetime field are automatically created and stored in the Alfresco Search Service. The three virtual time dimensions supported for the EA release are: _day, _month, _year. To use the virtual time dimensions you simply append the virtual time dimension to any datetime field and use it in the GROUP BY clause.  Below is an example where the _day dimension is appended to the cm_created datetime field.

 

select cm_created_day, count(*) as total from alfresco where cm_created >= 'NOW/DAY' group by cm_created_day

The query above creates a daily time series report using the cm_created_day virtual time dimension.

 

Datetime Predicates

 

A datetime predicate can be used in the WHERE clause to control the datetime range of the time series report. Notice in the example query the where clause:

 

where cm_created >= 'NOW/DAY'

 

This is a datetime predicate on the cm_created field. Its important to note that the virtual time dimension field is only used in the field list and GROUP BY clause. The predicate is applied to the non-virtual datetime field in the index.

 

The example above is using a date math expression to specify a lower boundary for the time series report. The sections below describe how to set lower and upper boundaries using both fixed date and date math predicates.

 

Unbounded Time Series Reports

 

If no datetime predicate is supplied, the following default lower and upper boundaries for the different time dimensions will be used:

 

day

lower: current day minus 1 month

upper: current full day

 

month

lower: current month minus 24 months

upper: current full month

 

year

lower: current year minus 5 years

upper: current full year

 

Fixed Datetime Predicates

 

Fixed datetime predicates are formatted according to a subset of ISO 8601. The SQL statement below shows an example of the fixed date predicate formatting:

 

select cm_created_day, count(*) from alfresco where cm_created >= '2010-02-01T01:01:01Z' and cm_created <= '2010-02-14T23:59:59Z' group by cm_created_day

 

Note that fixed datetime predicates require the full precision shown in the example above. 

 

Date Math Predicates

 

There is also support for a rich set of date math expressions. Below is an example of a time series aggregation using date math predicates:

 

select cm_created_month, count(*) from alfresco where cm_created >= 'NOW/MONTH-6MONTHS' and cm_created <= 'NOW' group by cm_created_month

 

In the example above NOW signifies the current point in time with milli-second precision. NOW/MONTH rounds the current point in time down to the current MONTH. The -6MONTHS subtracts 6 months from the current month. 

 

See the Solr date math guide for more details on date math syntax.

 

Single Dimension Group By

 

Time series aggregations that group by virtual time dimensions are currently limited to using a single group by field. 

 

Order By

 

By default time series aggregation results are sorted in datetime ascending order. An ORDER BY clause can be used to change the direction of the datatime sort or sort by an aggregate result. 

 

Having

A HAVING clause can be used to filter time series aggregations results.

 

JDBC Driver
 

The product includes a JDBC thin client that can be used with Apache Zeppelin and other SQL clients. The JDBC driver can also be used directly from a Java application. Below is sample code for using the JDBC driver:

 

String sql = "select DBID, LID from alfresco where cm_content = 'world' order by DBID limit 10 ";
String alfrescoJson = "{\"tenants\":[\"\"],\"locales\":[\"en_US\"],\"defaultNamespace\":\"http://www.alfresco.org/model/content/1.0\",\"textAttributes\":[],\"defaultFTSOperator\":\"OR\",\"defaultFTSFieldOperator\":\"OR\",\"anyDenyDenies\":true,\"query\":\"name:*\",\"templates\":[],\"allAttributes\":[],\"queryConsistency\":\"DEFAULT\",\"authorities\":[\"GROUP_EVERYONE\",\"ROLE_ADMINISTRATOR\",\"ROLE_AUTHENTICATED\",\"admin\"]}";

Properties props = new Properties();
props.put("alfresco.shards", "http://localhost:8983/solr/alfresco")
props.put("json", alfrescoJson);

String connectionString = "jdbc:alfresco://localhost:8983?collection=alfresco";
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
   
try {
        con = DriverManager.getConnection(connectionString, props);
        stmt = con.createStatement();
        rs = stmt.executeQuery(sql);
        int i=0;
        while (rs.next()) {
            System.out.println(rs.getString("DBID"));
        }
    } finally {
        try { rs.close(); } catch(Exception e) {}
        try { stmt.close();} catch(Exception e) {}
        try { con.close();} catch(Exception e) {}
    }
}

Currently Unsupported SQL Constructs

Below are some commonly used SQL features that are not yet supported, some of these we are working at closing at the moment but we'd love to know which you would find most valuable. Leave a comment below or send me a message to give us your feedback. 

 

  • SELECT * : currently specific fields must be listed in the field list
  • SELECT COUNT(DISTINCT field): Currently count(distinct field) queries are not supported
  • HAVING limitations: currently the HAVING clause can only be applied to aggregation functions
  • JOINS : currently this no support for joins
  • SUB-QUERIES: currently there is no support for sub-queries
  • UNION: currently there is no support for union queries
  • IS NULL
  • IS NOT NULL
  • LIKE
  • CMIS QL functions IN_TREE, IN_FOLDER, SCORE, CONTAINS
  • IN

A few years ago Samuel wrote a blog post entitled “So, when is Alfresco moving to GitHub?” In it he presented a number of reasons why it was difficult to move our code from SVN to Git. Given the recent move of Share to GitHub, I thought it would be worth writing an update on the situation.

 

The vast majority of our production code is now in Git. ACS Repository, Activiti, Search Services, Records Management, Google Docs Module, Android App, iOS App, Share, ADF Components, … and that’s not including our enterprise code which is primarily within our hosted GitLab.

 

Some of this code has always been in Git, but much of it has been migrated from SVN. I migrated the Records Management codebase in 2015, and since then we’ve had a fairly continuous stream of migrations.* The obvious question is "What’s changed since Samuel’s post?"

 

The answer is that not very much has changed. The team decided not to leave older releases in SVN for exactly the reasons mentioned by Samuel. Cherry-picking changes from SVN to Git can be done with svn diff --git and git apply, but it’s a pain, and we make a lot of service pack changes in our products. The ACS repository codebase is large and although we’ve split out several modules into smaller Git repositories, there is still over 2Gb of history in the Git repo.

 

The primary reason for migrating to Git is the popularity - Git is seven times more popular than any other version control system. Some of the reasons for this are Git’s local and lightweight branches (leading to cleaner workflows), faster access to history (since it’s all stored locally) and smaller overall repository size (leading to faster access to remote commits). Some other reasons are historical – SVN has greatly improved its merging and has got rid of the need for a .svn directory per folder. However since GitHub is the most popular and largest open source host in the world we want to use Git to make it easy for users to access our code.

 

 

* We’ve had migrations in the past too, e.g. Share extras in 2012, but the last year has seen a concerted effort to migrate projects.