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.


Friday, March 23, 2012

Retrieving Related Content in the CD side

The example below shows how to retrieve the latest 5 news of type sport, then these are sorted descending. These news are classified using taxonomies.


        protected override void Render(HtmlTextWriter writer)

        {  

            string[] sportNews;

            Query query = null;            
            Criteria criteria = new ItemTypeCriteria(16);
            ComponentPresentationFactory _cpf = new ComponentPresentationFactory(PublicationId); 

            CustomMetaKeyCriteria keyCriteria = new CustomMetaKeyCriteria("news");
            CustomMetaValueCriteria valueCriteria = new CustomMetaValueCriteria(keyCriteria, "Sport");

            List<Criteria> queryItems = new List<Criteria>();
           
            queryItems.Add(valueCriteria);            
            query = new Query(new AndCriteria(queryItems.ToArray()));

            //Set a limit on number of items                        
            query.SetResultFilter(new LimitFilter(5));

            //Add sorting
            SortParameter sort = new SortParameter(SortParameter.ItemLastPublishedDate, SortParameter.Descending);
            query.AddSorting(sort);

            sportNews = query.ExecuteQuery();

            foreach (string news in sportNews)
            {
                ComponentPresentation cp = _cpf.GetComponentPresentationWithOutputFormat(news, "XML Fragment");
                if (cp != null)
                {
                    DisplaySportNewsItem(news, cp, writer);
                }
            }
        }

Wednesday, March 14, 2012

NetBiscuits - HelloWorld with a Custom .NET Application

As far as I am aware this will be the first step by step tutorial to get up and running a NetBiscuit app feed from a .NET app. Otherwise I should have known where that tutorial was yesterday! I had some problems getting my first NetBiscuit app to work.

I intend to provide great detail so that absolutely anyone can get it done, I'll show screenshots of every step.

The steps are as follows:

  1. Crete an empty Website using Visual Studio
  2. Download a Sample NetBiscuit app from www.netbiscuits.com
  3. Copy the bml and images to your website
  4. Create a Custom Application in NetBiscuit
  5. Test it!

Wednesday, March 7, 2012

UGC - User Generated Content - Part 1

A few months ago I was named UGC SME thus I had to prepare a presentation to be given to my colleagues at SDL WCM as part of a bootcamp. I had just two or three days to prepare it all (myself + UGC working environment + presentation), despite two/three days is a short time to prepare a matter that I hadn't even heard of, it was actually enough.

I got much help from Daniel (Romania) who is part of the Content Delivery team in R&D, without him likely I wouldn't be writing these lines. Daniel, I want to take the opportunity to say thank you for your support and understanding.

Last week in a great 2012 kickoff/bootcamp in Orlando I intended to expand the work I did around UGC together with another two colleagues, Taras (Ukraine) and Fredy (USA). We tried to get to work a SpamFilter with no luck, you might be wondering what a SpamFilter is, be water my friend. Did you realise how international our team is?

In this post I will explain the following:
  • What is UGC
  • What can we do with UGC and where can be found in the CME
  • UGC History in SDL WCM
  • Where you can find documentation
In my next post I will write about the following:
  • UGC Architecture in SDL WCM
  • Installation on Content Manager and Content Delivery
  • Security - WhiteList and SpamFilter
  • Creating a SpamFilter, getting a fully working .NET solution.

Sunday, March 4, 2012

Keeping up to date with the Tridion Community using Netvibes


I had three main motivations to start this blog:

  • Share as much useful information as possible from TechLink.  Failed
  • Organize community posts by category. Failed
  • Contribute to the community my two cents. Succeed

Obviously I failed to achieve the first two goals. I underestimated the fast growing community and overestimated my free time to keep up to date with both tasks.


That said, I found the way to keep up with the community myself. First I used google reader, then Mark (a colleague from UK) told the team about netvibes. Since I found out about netvibes (and spent sometime playing around with it) it is being the main way in which I keep up with the community.


Somethings you should know about netvibes:

  • It is mainly a custom dashboard
  • You can create public and private pages
  • You can add RSS, Twitter, Facebook and all your email accounts
  • I won't give you any more reasons to make you think that I am working as sales at netvibes!

I hope you like it as much as I do.


I still miss a way to perform a cross site search amoghts some preset sites. This is to be able to search throughout the entire community efficiently in one go. If you are thinking of google, I have already heard about it ;o)


If you know of _something_ that can help me to do that I'd appreciate you let me know!

Wednesday, February 22, 2012

Upgrading SearchFilter Queries from 5.X to 2011 SP1


In this post I will not explain very basic concepts about Tridion Content Delivery, I will assume that you are familiar with it and that you wrote code using the Query and/or SearchFilter class included in one of the following namespaces:

·         Tridion.ContentDelivery.Broker (5.X)
·         Tridion.ContentDelivery.DynamicContent.Filters (20XX)

Monday, February 20, 2012

My first recipe: Paella!




Ingredients
  • 1/2 red peper
  • 1/2 green pepper
  • 1 onion
  • 4 garlics
  • 1 tomato
  • 2 soup spoons of fried tomato
  • 1/2 kg of rice. Make sure this is rice for paella, so if possible go to the closest Spanish food store.
  • 8 king prawns
  • 400 grams of clams
  • 3 squids
  • 4 Chicken drumsticks
  • 1 bouillon cube
  • 1 One leaf of laurel
  • Azafran or Coloring (azafran pulverized). If you want the rice to be really yellow, get coloring. Go to the closest Spanish food store to buy it.
  • Salt
  • Black pepper
  • Olive oil

Thursday, February 16, 2012

Prince 2

I am writing this post because a good friend of mine, Oscar, told me a few weeks ago that was considering to get enroll in a course to get certified in Prince 2.


A couple of months ago or so I became certified on Prince 2, I will share some thoughts about my experience while learning this project management methodology. It has not been the first time I have studied a PM methodology, although it has been the first time that I have got an official PM certification.