Skip to main content

Syntax Validation for Java Fragment TBB

This little post explains how to perform "Content Validation" of a Java Fragment TBB as part of the Tridion Java Mediator I am currently working on. If you want more information about the "Yet Another Java Mediator" for Tridion templating, have a look at my previous post.

Content validation for TBBs, or in Tridion terms, a Template Content Handler, is a piece of code that runs when a TBB is read (open) or written (saved) and it serves two purposes:
  • perform any validation of the TBB content;
  • replace any references to other Tridion items (either by TCM URI or WebDAV URL, or some kind of reference) with some kind of substitution;
I have not implemented any replacement logic yet (it is to come in the near future when I'll write the logic to upload JARs and execute classes from it). So far my goal was to perform a compile of the TBB Java source fragment at the moment of saving the TBB, and in case of errors, show the errors in the GUI and prevent saving. This is the same behaviour the C# Fragment TBBs have in OOTB Tridion.

In .NET things are simple -- all I had to do was create a class that extends abstract Tridion.ContentManager.Templating.AbstractTemplateContentHandler and implement method PerformValidateContent. From this method I called the Java Fragment compile logic (written in Java, over JNI proxy, as described in my previous post).

C#:
public class JavaFragmentContentHandler : AbstractTemplateContentHandler {

public override void PerformValidateContent() {
    JavaTemplateHandler handler = new JavaTemplateHandler();
    handler.compile(base.Content);
}

Java:
public class JavaTemplateHandler {

public void compile(String javaFragmentSource) {
    String javaSource = String.format(JAVA_FRAGMENT_SKELETON_SOURCE, javaFragmentSource);
    SourceStringCompiler compiler = new SourceStringCompiler(CLASSES_DIR);
    compiler.compile(JAVA_FRAGMENT_SKELETON_CLASS_NAME, javaSource);
}

On the Java side, I am simply intercepting the messages coming from the Compiler API and, in case of an error, throw an exception with the compiler message formatted a bit. I do some formatting on the line numbers only, so that the line number reported is actually relative to the Java Fragment that is shown in Tridion and not the line number relative to the entire compilation unit. The thrown exception is propagated all the way back into .NET and eventually ends up being displayed in the CME.

I hit a few roadblocks, of course:
  • Content handlers need to be registered in the GAC. This is unfortunately inconsistent with the mechanism of registering mediators, where you can specify the actual assembly path. As a Java head, I really dislike the GAC -- it is the root of all evil. This meant I had to sign all my referenced DLLs (including Tom.Java, jni4net). This meant a lot of trouble with the JAR loading mechanism from jni4net etc). In the end I opted for reflection, just to keep the 'referenced' DLLs out of GAC and unsigned;
  • 32bit vs 64bit trouble -- some parts of Tridion CM run as 32bit applications and some as 64bit. This poses a huge problem to jni4net Bridge, which has to use the appropriate 32 vs 64 bit Java Development Kit based on the calling .NET CLR it runs it;
Finally, everything worked and the validation looks something like that:
Notice the variable "a" declared without a type and the Date class not being resolvable.

A detail error message looks like this, if expanded:
So far I have the entire Java Fragment TBB done, including validation/compilation. Next, I I'll focus on the JSP/JSTL TBBs that I intend to use as replacement of Dreamweaver TBBs.


Comments

Popular posts from this blog

Toolkit - Dynamic Content Queries

This post if part of a series about the  File System Toolkit  - a custom content delivery API for SDL Tridion. This post presents the Dynamic Content Query capability. The requirements for the Toolkit API are that it should be able to provide CustomMeta queries, pagination, and sorting -- all on the file system, without the use third party tools (database, search engines, indexers, etc). Therefore I had to implement a simple database engine and indexer -- which is described in more detail in post Writing My Own Database Engine . The querying logic does not make use of cache. This means the query logic is executed every time. When models are requested, the models are however retrieved using the ModelFactory and those are cached. Query Class This is the main class for dynamic content queries. It is the entry point into the execution logic of a query. The class takes as parameter a Criterion (presented below) which triggers the execution of query in all sub-criteria of a Criterio

A DD4T.net Implementation - Custom Binary Publisher

The default way to publish binaries in DD4T is implemented in class DD4T.Templates.Base.Utils.BinaryPublisher and uses method RenderedItem.AddBinary(Component) . This produces binaries that have their TCM URI as suffix in their filename. In my recent project, we had a requirement that binary file names should be clean (without the TCM URI suffix). Therefore, it was time to modify the way DD4T was publishing binaries. The method in charge with publishing binaries is called PublishItem and is defined in class BinaryPublisher . I therefore extended the BinaryPublisher and overrode method PublishItem. public class CustomBinaryPublisher : BinaryPublisher { private Template currentTemplate; private TcmUri structureGroupUri; In its simplest form, method PublishItem just takes the item and passes it to the AddBinary. In order to accomplish the requirement, we must specify a filename while publishing. This is the file name part of the binary path of Component.BinaryConten

Scaling Policies

This post is part of a bigger topic Autoscaling Publishers in AWS . In a previous post we talked about the Auto Scaling Groups , but we didn't go into details on the Scaling Policies. This is the purpose of this blog post. As defined earlier, the Scaling Policies define the rules according to which the group size is increased or decreased. These rules are based on instance metrics (e.g. CPU), CloudWatch custom metrics, or even CloudWatch alarms and their states and values. We defined a Scaling Policy with Steps, called 'increase_group_size', which is triggered first by the CloudWatch Alarm 'Publish_Alarm' defined earlier. Also depending on the size of the monitored CloudWatch custom metric 'Waiting for Publish', the Scaling Policy with Steps can add a difference number of instances to the group. The scaling policy sets the number of instances in group to 1 if there are between 1000 and 2000 items Waiting for Publish in the queue. It also sets the