Friday, November 9, 2012

EventSystem - Components/Pages Publish and Unpublish

This is a code sample which shows how to subscribe to the following Tridion EventSystems:

  • Component Publish
  • Component Unpublish
  • Page Publish
  • Page Unpublish

Nested OR Criteria on the CD

A few months ago during an onsite assignment, I was asked by a customer to advise them about how to get all the latest updated content on their wrbsite. 

I had what to me looked like a simple requirement: “Show all the latest updated content on the site”. There could be up to 10 content types. I was working on a query object to retrieve all the components of type X,Y,Z… sorted by latest modified date.

Everything worked fine until I added a fourth ItemSchemaCriteria, I wondered if I was building the query in the wrong way (less efficient), if I removed the lines I highlighted below then everything worked fine. Here is the code I used:

            Criteria onlyComponents = new ItemTypeCriteria(16);

            Criteria productSpecs = new ItemSchemaCriteria(2448);
            Criteria events = new ItemSchemaCriteria(6258);
            Criteria madeUp1 = new ItemSchemaCriteria(1234);
            Criteria madeUp2 = new ItemSchemaCriteria(1235);

            Criteria cOr1 = new OrCriteria(productSpecs, events);
            Criteria cOr2 = new OrCriteria(cOr1, madeUp1);
            Criteria cOr3 = new OrCriteria(cOr2, madeUp2);

            Criteria criteria = new AndCriteria(onlyComponents, cOr3);

            Query latestUpdatesQuery = new Query(criteria);

Then a colleague (Jeremy Grand-Scrutton) told me that maybe the way I was creating the several OR criteria wasn't the most efficient way to use the API, and suggested to create an OR criteria array instead. 

       Criteria onlyComponents = new ItemTypeCriteria(16);

            Criteria productSpecs = new ItemSchemaCriteria(2448);
            Criteria events = new ItemSchemaCriteria(6258);
            Criteria madeUp1 = new ItemSchemaCriteria(1234);
            Criteria madeUp2 = new ItemSchemaCriteria(1235);

            Criteria[] itemSchemas = { productSpecs, events, madeUp1, madeUp2 };
            Criteria orCrit = new OrCriteria(itemSchemas);

            Criteria criteria = new AndCriteria(onlyComponents, orCrit);

            Query latestUpdatesQuery = new Query(criteria);

I was very happy when I actually confirmed that it worked out with no issues. In fact, I tested the same logic with up to 30 schemas and surprisingly it still was lighting fast!

Wednesday, May 30, 2012

Adding Parameter Schemas in the .NET TBB Code

For those of you who don't know, a parameter schema is a special type of schema which allow developers to pass parameters to the Template Building Blocks (TBBs). The main purpose (if not the only) of this type of schemas is to make TBBs more flexible so that these can be reused across multiple environments and implementations.

Problem

Sometimes after setting the parameter schema in the TBB, somehow it seems to disappear after uploading a newer version of the assembly or after using Content Porter to import the TBBs. 

Solution

The parameter schema can be set programatically inside the TBB itself, the way to do this is simply by adding an attribute to the class as follows: 


[TcmTemplateTitle("Add page properties")]    [TcmTemplateParameterSchema("/webdav/02D%20_Design%20Parent/Building%20Blocks/System/Schemas/Parameters%20Schemas/Publish%20files%20Parameter%20Schema.xsd")]

    public class AddPageProperties : ITemplate
    {
        public void Transform(Engine engine, Package package)
        {
            // The place for the wizard to do the magic :)


The only thing you need to add is the attribute TcmTemplateParameterSchema to the class.

Wednesday, April 25, 2012

Custom Application Path in Tomcat

How to configure different paths for each web application running in Tomcat?


This was a question that came up in TechLink and I thought that it'd be nice to share the answer with you and also to write it here as a reminder to myself.


All what is necessary is to edit the server.xml to add a Host section per site inside the Engine tag, see an example below:


<!-- Preview host -->
<Host name="tomcatpreviewdeployer.local"  appBase="C:\workarea\websites\preview\java\deployer" unpackWARs="true" autoDeploy="true">
            <Context path="" docBase="" debug="0" reloadable="true"/>
            <Valve className="org.apache.catalina.valves.AccessLogValve" directory="C:\Tridion\log\preview\java"
               prefix="tomcatpreview_deployer_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>
<Host name="tomcatpreviewsite.local"  appBase="C:\workarea\websites\preview\java\site" unpackWARs="true" autoDeploy="true">
            <Context path="" docBase="" debug="0" reloadable="true"/>
            <Valve className="org.apache.catalina.valves.AccessLogValve" directory="C:\Tridion\log\preview\java"
               prefix="tomcatpreview_site_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>
     
<!-- Live host -->
<Host name="tomcatlivedeployer.local"  appBase="C:\workarea\websites\live\java\deployer" unpackWARs="true" autoDeploy="true">
            <Context path="" docBase="" debug="0" reloadable="true"/>
            <Valve className="org.apache.catalina.valves.AccessLogValve" directory="C:\Tridion\log\live\java"
               prefix="tomcatlive_deployer_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>
<Host name="tomcatlivesite.local"  appBase="C:\workarea\websites\preview\java\site" unpackWARs="true" autoDeploy="true">
            <Context path="" docBase="" debug="0" reloadable="true"/>
            <Valve className="org.apache.catalina.valves.AccessLogValve" directory="C:\Tridion\log\preview\java"
               prefix="tomcatlive_site_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>             

Tuesday, April 24, 2012

Tridion Development - Some Of My Good Practices

Say that you live in Miami and you want to travel to New Delhi, how would you do it? You wouldn't probably walk, neither go by bicycle nor swimming. I am not sure what you would do but I know what I would do, I would buy on the internet the best value for money ticket available to go to the destination desire. 

By now you must be thinking, what the heck is this guy talking about? Well, I am talking about the so unpopular common sense.

I will NOT be talking about anything very advance but instead about some basic things that should always be considered before starting and during a software development life cycle.

In this post I am going to be using .NET terms but these can be easily translated into Java argot. I just want to share some of what I would think of as best practices :)

Naming Solutions and Projects

Getting the right names for your solutions and projects is very simple, although based on my experience often in real implementations the names chosen are quite bad or simply terrifying! These are usually not complete, inconsistent and/or meaningless.

Before creating a solution think upfront which projects will be part of the one you are creating at the moment. Despite there is quite a lot of information about naming conventions for classes, methods, properties, variables etc. there is almost no information about naming conventions for Solutions and Projects, thus I will provide some guidance on this. Given that I haven't found official information about this topic I will share some simple steps I follow to chose the names. 

Customer.Partner.MyCompany.ProjectName.ProjectType.ProjectSubType

In case you are not happy with the names you gave to a solution and/or project some time ago, you could always go back and change them. In fact it is probably about time to do it, so take 5 minutes and go ahead! 

Organizing Solutions and Projects

Completely different areas of development such as Content Manager and Content Delivery should never be together in the same VS solution. Topics of large size within these areas can also go into different solutions. Separate parts of these topics can go into projects inside the same solutions. 

What does this mean in real life?

This means that in a project you could have a folder structure that would look like this:

  • References. Containing all the references needed for any project, this is to avoid storing together source code with project dependencies. 
  • Custom Pages
  • GUI Extensions
  • Workflow
  • Event System
  • Templating
  • Web Application

Next I will elaborate a bit the content of some of these folders.

The folder References could look like this. 



The Templating folder could contain a Templating solution which would have several projects. In this case, each folder in the image has a VS project inside. Please ignore the TcmUploadAssembly, it should not be there ;)




The Web Application folder contains everything related to the web application. There is no need to say that controls or other parts of the web application for the same web application should not be part of different projects for no reason. This is an image of how the Web Application folder could look like.


And this is how the Customer.Web folder could look like with its controls, framework etc.




Usings and References


It does not really matter what programming language you work with, you must always remember to clean up what you have done. The simpler your solution is the easier it will be to maintain in the future. From the development perspective it means time, and from the business perspective it means money, some times a lot money. 

It is obvious, but most of us forget (or don't want to remember) to clean up that painful project in which we have been working on for a while.

So, how do you clean your mess? Easy.

Firstly, remove unused namespaces.




Secondly remove any unused references. There isn't any benefits on having unused references, however chances are that one or more of these will give you some head aches in the long run.

Often I can see at customers Content Manager code with references  to Content Delivery assemblies, that is wrong. On the other hand, I also see Content Delivery code with references to Content Manager assemblies, again this is simply wrong. There is not a single good reason for you do this, and there is not a good reason for you not to remove these references that are clearly wrong the next time you stumble with them.

Version Control Software

If you are developing software you MUST use some kind of version control software. In my opinion the worse version control system in the market is much better than not using any. No, there is not excuse to not use a version control software.

If you want a recommendation, a colleague of mine would have no doubts: GIT is your friend. I'd give it a go!

Learning curve might be a bit steep but advantages of GIT compared with similar software seem to be great.

Dreamweaver

Store all the DWTs inside a code repository, at the end of the day Tridion should not be used for this purpose. Among other things using a code repository for this will allow you to be able to roll back all the DWTs very quickly.

Storing Assemblies in Tridion

I don't like to treat assemblies as normal content. I have seen Tridion implementations in which for each dll used by the Web App the following is done:
  • Rename *.dll to *.exe
  • Create a component in tridion with the *.exe
  • Create a page
  • Add component presentation to page
  • Publish page
To me this does not make sense at all. A Content Manager is not a Web Application Manager and therefore it should be used to mange content not the Web Application dependencies.

Please feel free to contradict me and provide some arguments, I would like to know why this has been done in some implementations. 

Storing C# TBBs in Tridion

Store all your TBBs in one assembly or group the TBBs per topic inside different assemblies. However, DO NOT create one assembly for every C# TBB! Some of you might be wondering why I am saying this, well the reason is that I have found this in real implementations.

Schemas

From my point of view in 99% of the cases creating common schemas among different content types does not make any sense. 

Firstly from the functional perspective this is very confusing to the Editors, depending on the content type editors will have to fill in one field or other, therefore it is not intuitive nor user friendly.

Secondly, from a technical perspective you are creating unneeded dependencies between the different content types, meaning that in the future you'd have to work a lot more to get around this.

All these problems could have been avoided by creating a few more schemas even though these had a good set of fields in common, for those fields in common you can just use an embedded schema.

Debugging in .NET

On the Content Manager side you have a great IDE Visual Studio (it is great at least for me), make good use of it! 

One directory to rule all the Web Apps

If all your Web Apps have the same configuration, I would strongly recommend you having a unique directory from which the Content Delivery configuration and libs are picked up. The way to do this is as follows:
  • Remove the config and lib folder from MyWebApp\bin
  • If doesn't exist already create an environment variable TRIDION_HOME, set this variable to the path where you want to store the config and lib folders.
  • Create config and lib folders under TRIDION_HOME
Now your content delivery is ready to be updated efficiently. For instance, if you need to change where you want to store an item type (DB or file system), you only need to change one config file instead of one config file per Web App.

Saturday, April 7, 2012

Cross-domain Searching


Some weeks ago I wrote this post about how to keep up with the Tridion community, in the last part of the post I mentioned that I was still missing a way of doing cross-domain search ONLY through the entire community efficiently in one go. It is very important to search only in the community to increase dramatically the relevancy of the results. 

Well, last week I found out about a beta version of a new google service that allows you to create your own custom search. You can do it from this page, I have already created my own Custom Search Engine (CSE) with all the Tridion related sites I follow. Furthermore I have added to my blog my CSE so that you can play around and even use it yourself to perform real searches, it is placed just to the right of these lines.



I am very enthusiastic about this service because from now on we'll be able to search efficiently for any thing within a tiny group of websites in which we are interested. what does this really mean? Let's compare the search results for the phrase "content delivery" using www.google.com and my CSE.

From a Tridion perspective, searching for "content delivery" in www.google.com returns 0 relevant results in the first page.


From a Tridion perspective, searching for "content delivery" in my custom search engine returns only relevant results.