Mp3tag to batch process/edit MP3 tags

It’s always good to keep things organized even more when it comes to MP3 files. If you use to listen to MP3 music you know what I’m talking about.

I keep a timeline of music I listen to at Last.fm. Last.fm tries to help us correcting wrong MP3 tags, but corrections are only visible online and they don’t change MP3 metadata, that is, you still have wrongly tagged MP3 residing in your music library.

To overcome such situation I started looking for a piece of software that could resolve this misinformation. I got to know a free yet powerful small application called Mp3tag that allows the execution of various commands against MP3 metadata.

Excerpting from the official site:

Mp3tag is a powerful and yet easy-to-use tool to edit metadata of common audio formats where it supports ID3v1, ID3v2.3, ID3v2.4, iTunes MP4, WMA, Vorbis Comments and APE Tags.

It can rename files based on the tag information, replace characters or words in tags and filenames, import/export tag information, create playlists and more.

Mp3tag supports online database lookups from, e.g., Amazon, discogs, or freedb, allowing you to automatically gather proper tags and cover art for your music library.

One of the best features of Mp3tag is the Actions menu button that let’s you replace text within any MP3 tag field using simple find and replace or more advanced regular expressions. The following figure shows the options available:

Figure 1 – Options available through the Actions menu button
Figure 1 – Options available through the Actions menu button

I’ll briefly show how to edit the Title of some files all at once - what is known as batch processing.

I’ll remove with only one command (action) the text “ - TO BE REMOVED” that is part of the Title tag of 10 MP3 files:

Figure 2 – Mp3tag listing 10 MP3 files before the batch processing
Figure 2 – Mp3tag listing 10 MP3 files before the batch processing

Click on the Action menu button (mouse pointer is over it in the following picture) and select the action type as Replace and click OK:

Figure 3 – Mp3tag action type selection
Figure 3 – Mp3tag action type selection

Now select the MP3 tag field you’d like to change. In this case I’m going to modify the content of the Title tag field. Enter the text “ - TO BE REMOVED” inside the Original field. As I want to remove the text I’ll let the Replace with field blank/empty.

Figure 4 – Mp3tag Replace action window
Figure 4 – Mp3tag Replace action window

Click OK and voila:

Figure 5 – Mp3tag listing 10 MP3 files after the batch processing
Figure 5 – Mp3tag listing 10 MP3 files after the batch processing

Now you know where to look for a versatile MP3 tag editor. It comes to the rescue allowing you to avoid spending your time editing MP3 by MP3. You can do lots of things related to MP3 metadata. You can batch process all your MP3 with only one action easy as pie.

It would be good if popular media players as Windows Media Player, iTunes, etc could let us do things like this simple task I demonstrated in this post. Maybe someday they will. I hope.

References
Mp3tag online Help
Mp3tag group at Last.fm
Mp3tag at Twitter

Oracle NLS_LANG for language/territory/character set

Recently I had an Oracle problem at work.
I kept postponing to look with care at this problem till today.

Problem
All accented characters as à, á, é, í, ó, ú, â, ê, î, ô, û, ã, õ, etc and other ones as ç (cedilla), º, ª (ordinal indicators), were being replaced by erroneous characters as this example in the header of a stored procedure:

=================================================================
-- Revis¿o : 'N¡ã 0
-- Descri¿¿o: // description here
-- Data   : 03/29/2010
-- Autor  : CHEMTECH
=================================================================

This problem gets worse if you have something as

SELECT CONTRACT.NUM_CONTRACT,
           'N¡ã' || TO_CHAR(CONTRACT.NUM_CONTRACT) || ' - ' ||

The result of the above SQL query is used in the UI, that is, the user will see the wrong characters ¡ã instead of º. If you commit this thing in the repository you mess everything up. You see what I mean…

Questioning
At first I thought the problem was the database encoding settings.

I and only I was getting crazy characters. My development group has more 3 people and no one was having this problem. This clearly should be a UI configuration, that is, how the data is shown on my machine.

A little bit of research on the net took me to Oracle’s NLS_LANG FAQ.

This is what NLS_LANG stands for/does:

A locale is a set of information addressing linguistic and cultural requirements that corresponds to a given language and country. Traditionally, the data associated with a locale provides support for formatting and parsing of dates, times, numbers, and currencies, etc. Providing current and correct locale data has historically been the responsibility of each platform owner or vendor, leading to inconsistencies and errors in locale data.

Setting the NLS_LANG environment parameter is the simplest way to specify locale behavior for Oracle software. It sets the language and territory used by the client application and the database server. It also indicates the client's character set, which corresponds to the character set for data to be entered or displayed by a client program.

I started reading the FAQ (top bottom approach) and tried the following query:

SELECT * FROM NLS_SESSION_PARAMETERS;

which gave me this result:

NLS_SESSION_PARAMETERS on my development machine
Figure 1 - NLS_SESSION_PARAMETERS on my development machine

As you see NLS_LANGUAGE and NLS_TERRITORY are set to AMERICAN and AMERICA respectively on my machine.

I asked Thiago Arakaki a coworker of mine to execute the same SQL query on his dev box. To my surprise and delight this was the screen he got:

NLS_SESSION_PARAMETERS on Thiago's development machine
Figure 2 - NLS_SESSION_PARAMETERS on Thiago Arakaki’s development machine 

As you see NLS_LANGUAGE and NLS_TERRITORY are set to BRAZILIAN PORTUGUESE and BRAZIL respectively on his machine.

This clearly pointed what could be the cause of the problem I was having.

I couldn’t understand why my machine had a different NLS_LANGUAGE and NLS_TERRITORY.

I read the FAQ a little bit more and got to this part Where to set the NLS_LANG in Windows.

I checked Windows registry to make sure the NLS_LANG subkey was set correctly on Oracle home. I got this:

NLS_LANG subkey on Windows RegistryFigure 3 - NLS_LANG subkey on Windows Registry

For my surprise it was correct. Look at NLS_LANG. It has BRAZILIAN PORTUGUESE_BRAZIL.WE8MSWIN1252 just like Thiago Arakaki’s dev box.

So why do I still was getting wrong characters inside Allround Automations PL/SQL Developer when working on the same database that Thiago also uses? Aha, that’s the question this post tries to clarify if you come to get in this same situation.

Reading the FAQ a little bit more… :o) I saw that you could also set NLS_LANG as a System or User Environment Variable, in System properties. So I went there to check if I already had such a thingy set on my machine. Again for my surprise this thingy was there. I don’t remember if/when I created this variable.

The only thing I thought at the moment was the interference that some previous installations of Oracle could’ve caused on my machine. Today I’m using Oracle express but in the past I installed the full Oracle server. I can’t state for sure what created the NLS_LANG var on my Windows System variables.

The screen I got was something like this:

 NLS_LANG variable on Windows System variables
Figure 4 - NLS_LANG variable on Windows System variables

I had AMERICAN set for the NLS_LANG variable.

Solution
I then changed the system variable NLS_LANG to BRAZILIAN PORTUGUESE_BRAZIL.WE8MSWIN1252. Clicked OK. Closed PL/SQL. Opened PL/SQL and issued the SQL query described on the beginning of this post and could see that the NLS_LANGUAGE and NLS_TERRITORY rows had changed appropriately to BRAZILIAN PORTUGUESE and BRAZIL respectively. After that I started to get the right characters throughout the database.

Great! Problem solved.

Upload/Import Download/Export a File to/from Oracle DB

What motivated me to write this post is that this is a really interesting task.

The general idea one have about databases is that they only serve the purpose of storing plain values as numbers, dates and text. A database does not do just that but even more allowing you to store a whole file as an Excel spreadsheet or an MP3 file in a column you define in your table.

To illustrate that, let’s suppose you were assigned the task of saving a spreadsheet in the database. This spreadsheet contains valuable data (as taxes values for each federal state) that’ll be used throughout your application. A user will upload that spreadsheet to the database and when someone else want to see the content of that spreadsheet it’s just a matter of clicking a download button to get it back. Pretty simple, isn’t it?

To accomplish that I’ll use Oracle database, more specifically Oracle Database 10g Express Edition (free to use).

The SQL code I used to create the database objects is as follows:

----------------------------------------------------------
-- Export file for user ORACLETEST                      --
-- Created by Leniel Macaferi on 3/13/2010, 11:43:17 PM --
----------------------------------------------------------

-- Create database tablespace
create tablespace oracletest datafile 'C:\oracletest.dbf'
size                                  20M
autoextend on maxsize                 unlimited
extent management local uniform size  64K;

-- Create user and Grant permissions
create user oracletest identified by oracletest default tablespace oracletest;
grant connect, resource to oracletest;
grant create session to oracletest;
grant unlimited tablespace to oracletest;
grant dba to oracletest;

-- Create table
create table FILES
(
  ID          NUMBER not null,
  UPLOAD_DATE DATE not null,
  CONTENT     BLOB not null,
  TYPE        VARCHAR2(64) not null,
  NAME        VARCHAR2(128) not null,
LENGTH NUMBER not null
);
alter table oracletest.FILES
  add constraint ID primary key (ID);

-- Create sequence
create sequence oracletest.SEQ_FILES
minvalue 1
maxvalue 999999999999999999999999999
start with 1
increment by 1
nocache;
-- Create import/upload procedure
create or replace procedure sp_import_file(
upload_date
in varchar2, content files.content%type, type in varchar2, name in varchar2,
length in number, id
out number) is begin select seq_files.nextval into id from dual; insert into files (id, upload_date, content, type, name, length) values (id, to_date(upload_date, 'mm/dd/yyyy hh:mi:ss pm'), content, type, name,
length
); end sp_import_file;

I’ll use an ASP.NET MVC application to show the process of uploading/importing downloading/exporting a file to/from an Oracle database.

The app has a tab called Import/Export File. Clicking on this tab takes you to a View that contains a file upload control and two buttons. When the user clicks the Import button the file will be uploaded/imported/saved to/in the database. When the user clicks the Export button the last file saved in the database will be downloaded/exported to the user’s computer.

The following is a screenshot of the application:

Oracle Import Export File ASP.NET MVC Application
Figure 1 - ASP.NET MVC Application UI

The following is a screenshot of the Files table which already has some files:

Oracle Import Export Files Table
Figure 2 - Oracle Files Table

As you can see the thing that makes it possible to import a whole file to a table is the type of the column that’ll hold the file; in this case the type is BLOB.

In the lines that follow I’ll present the source code I used to implement this sample ASP.NET MVC application.

It’s always good to view the Solution Explorer inside Visual Studio so that I can highlight the files I have created:

Oracle Import Export File Visual Studio Solution Explorer Figure 3 - Solution Explorer in Visual Studio

This is the C# code used in the upload/import process (inside OracleFileModel.cs):

/// <summary>
/// Imports any file to an Oracle database table that has a column of type BLOB.
/// </summary>
/// <param name="uploadDate">Date of upload/importation</param>
/// <param name="fileName">File name</param>
/// <param name="filePath">File path on the server</param>
/// <param name="fileType">File type</param>
/// <param name="fileSize">File size in bytes</param> /// <returns>Id of Row just inserted</returns> public static int Import(string uploadDate, string fileName, string filePath, string fileType, int fileSize) { OracleConnection connection = GetOracleConnection(); connection.Open(); OracleTransaction transaction; transaction = connection.BeginTransaction(); OracleCommand cmd; cmd = connection.CreateCommand(); cmd.Transaction = transaction; // Creates a temporary blob object on the database. This object will store the file content. cmd.CommandText = "declare xx blob; begin dbms_lob.createtemporary(xx, false, 0); :tempblob := xx; end;"; cmd.Parameters.Add(new OracleParameter("tempblob", OracleType.Blob)).Direction = ParameterDirection.Output; cmd.ExecuteNonQuery(); // Getting the content of the file... byte[] buffer = GetFileContent(filePath); // Oracle object responsible for storing the File content. OracleLob tempLob; // Assigning tempLob the blob object created on the database. tempLob = (OracleLob)cmd.Parameters[0].Value; tempLob.BeginBatch(OracleLobOpenMode.ReadWrite); // Writing the file content to tempLob. tempLob.Write(buffer, 0, buffer.Length); tempLob.EndBatch(); cmd.Parameters.Clear(); // The name of the Procedure responsible for inserting the data in the table. cmd.CommandText = "SP_IMPORT_FILE"; cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add(new OracleParameter("upload_date", OracleType.VarChar)).Value = uploadDate; cmd.Parameters.Add(new OracleParameter("content", OracleType.Blob)).Value = tempLob; cmd.Parameters.Add(new OracleParameter("type", OracleType.VarChar)).Value = fileType; cmd.Parameters.Add(new OracleParameter("name", OracleType.VarChar)).Value = fileName;
cmd.Parameters.Add(new OracleParameter("length", OracleType.Number)).Value = fileSize; cmd.Parameters.Add(new OracleParameter("id", OracleType.Number)).Direction = ParameterDirection.Output; try { cmd.ExecuteNonQuery(); } catch (Exception ex) { transaction.Rollback(); throw new Exception(ex.Message); } transaction.Commit(); connection.Close(); // Returning the Id of the row just inserted in table FILES. // This Id could be used to associate the file inserted with another table, for example, // if you had to parse the content of a spreadsheet and save each line in other table. return int.Parse(cmd.Parameters[4].Value.ToString()); }
This is the C# code used in the download/export process (inside OracleFileModel.cs)::
/// <summary>
/// Exports the last file imported to an Oracle database table that has a column of type BLOB.
/// </summary>
/// <returns>File</returns>
public static MyFileModel Export()
{
    MyFileModel file = new MyFileModel();

    OracleConnection connection = GetOracleConnection();
    connection.Open();

    OracleCommand cmd;
    cmd = connection.CreateCommand();

    // Gets the last File imported.
    cmd.CommandText = "select content, name, type from (select content, name, type from files f order by f.upload_date desc) where rownum = 1";

    byte[] fileContent;

    try
    {
        OracleDataReader reader = cmd.ExecuteReader();

        using (reader)
        {
            reader.Read();

            if (!reader.HasRows)
            {
                return file;
            }

            OracleLob blob = reader.GetOracleLob(0);
            OracleString fileName = reader.GetOracleString(1);
            OracleString fileType = reader.GetOracleString(2);

            fileContent = new byte[blob.Length];

            blob.Read(fileContent, 0, (int)blob.Length);

            file.Content = fileContent;
            file.Name = fileName.Value;
            file.Type = fileType.Value;
        }
    }
    catch (Exception ex)
    {
        throw new Exception(ex.Message);
    }

    connection.Close();

    return file;
}
/// <summary>
/// Gets an Oracle connection to the database.
/// </summary>
/// <returns>OracleConnection</returns>
private static OracleConnection GetOracleConnection()
{
    string user = ConfigurationManager.AppSettings["user"];
    string password = ConfigurationManager.AppSettings["password"];
    string dataSource = ConfigurationManager.AppSettings["dataSource"];

   return new OracleConnection("Data Source=" + dataSource + ";User Id=" + user + ";Password=" + password + ";");
}

/// <summary>
/// Get the content of the file in byte array buffer.
/// </summary>
/// <param name="path">File path on the server</param>
/// <returns>File content</returns>
private static byte[] GetFileContent(string path)
{
    Stream fs = File.OpenRead(path);
    
    byte[] buffer = new byte[fs.Length];

    int q = fs.Read(buffer, 0, Convert.ToInt32(fs.Length));

    fs.Close();

    return buffer;
}

This is the code implemented for the OracleFileController:

public class OracleFileController : Controller
{
    //
    // GET: /OracleFile/

    public ActionResult OracleFile(FormCollection formCollection)
    {
// Handles the button that posted to the server...
// OracleFile.aspx has 2 submit buttons.


if (formCollection["Import"] != null) { Import(); } else if (formCollection["Export"] != null) { return Export(); } return View(); } /// <summary> /// Imports a file from the user computer to the database. /// </summary> /// <returns></returns> private void Import() { foreach (string fileName in Request.Files) {
// Gets the file the user selected. HttpPostedFileBase file = Request.Files[fileName];
if (file.ContentLength > 0) {
// Getting the name of the folder in which the file will be saved on the server. string saveFolder = ConfigurationManager.AppSettings["saveFolder"];
                // Creating the path for the file on the server.

string filePath = Path.Combine(Request.ServerVariables["APPL_PHYSICAL_PATH"] + saveFolder, Path.GetFileName(file.FileName));
                // Saving a copy of the user's posted file on the server.
file.SaveAs(filePath);
                // Save the file in the database.
                // Although id isn't being used, this shows you how to get the id of the file just inserted in the database.
                int id = OracleFileModel.Import(DateTime.Now.ToString(), file.FileName, filePath, file.ContentType, file.ContentLength);
                // Deleting the file just imported so that the server disk does not get full.
                System.IO.File.Delete(filePath);

                TempData["message"] = "File imported with sucess.";
            }
        }
    }

    /// <summary>
    /// Exports a file from the database to the user's computer.
    /// </summary>
    /// <returns></returns>
    public ActionResult Export()
    {
        // Get the file from the database.
        MyFileModel file = OracleFileModel.Export();

        if (file.Content != null)
        {
            TempData["message"] = "File exported with success.";

            // Return the file to the user's computer.
            return File(file.Content, file.Type, file.Name);
        }
        else
        {
            TempData["message"] = "There's nothing to download.";

            return View("OracleFile");
        }
    }
}

This is a really big post full of code. I think the code has sufficient comments that should shed some light on how to accomplish the task.

Important note
All properties read in the form of ConfigurationManager.AppSettings["property"]; including the database name and password are stored in the Web.config file under the appSettings section.

<appSettings>
   <add key="user" value="oracletest"/>
   <add key="password" value="oracletest"/>
   <add key="dataSource" value="localhost"/>
   <add key="saveFolder" value="Files"/>
</appSettings>

Hope you make good use of it.

Visual Studio 2010 C# ASP.NET MVC Application
You can get the Microsoft Visual Studio Project at:

http://sites.google.com/site/leniel/blog/OracleImportExportFile.zip

To try out the code you can use the free Microsoft Visual Studio 2010 Professional Release Candidate (ISO file) that you can get at: http://www.microsoft.com/downloads/details.aspx?FamilyID=f9c0b89b-4964-4906-94c6-60ad8a429690&displaylang=en

Although I’ve used the 2010 version of Visual Studio I think the code presented in this post works just fine with previous versions of Visual Studio and ASP.NET MVC framework. You shouldn’t have problems while copying/pasting the code in previous versions. Maybe you’ll have to change DLL references or something like that.

Translation @ a click with Babylon

As a form of gratitude to Babylon I decided to write this post. A post is worth a thousand words almost literally in this case.

When it comes to computer translation, don’t think twice. Take a look at Babylon. Babylon is a Windows client application that resides in you taskbar. It offers translation from/to a varied set of language pairs.

If you are not a native English speaker as is my case and if you work in the software world, chances are that you had to resort to any online dictionary to find the meaning of some word. English reigns when it comes to programming languages and any other sort of computer related stuff. With Babylon the translation from/to English to a varied set of languages is just @ a click of the mouse. This amazing software product has helped me a lot since I started the computer engineering course in 2003 and I think it'll continue to play a big role in my English learning process during the years to come.

Nowadays it's practically impossible to work in the software industry without a grasp of English grammar, so that if you want to know a software product that can help you, read on.

Being a Brazilian speaking Portuguese and an avid user of Babylon since 2002 I can tell you that Babylon played and plays a big part in my English language learning. Despite having a 4.5 years course of English background, it’s always not enough. Learning is an infinite process.

Much of my contributions to ProZ comes from Babylon. At the same time I help others I learn a little bit more of English each day.
I just can’t express in words how much Babylon has helped me during these past years. At least this is an attempt.

Below is a screenshot of Babylon 8 with word auto-completion (auto-suggestion):

Babylon 8 - Main Window

When I get to a word that I don’t know yet I just select it with "Ctrl + Right Mouse Button" or copy/paste it inside Babylon’s text box to get instant translation that comes from a number of online dictionaries including Wikipedia, which is the world’s largest encyclopedia/source of information.

Babylon has its native dictionaries/glossaries but the community also develop custom ones making them free to use. Such dictionaries/glossaries are in most cases specialized ones, that is, they refer to specific fields as computer networks, software, electronics, etc. In contrast with free content, there is also premium content which you pay for.

Behind the curtains Babylon uses built-in browser functionalities as is the case of translated data returned in the form of a webpage and history navigation.

Besides translation to and from any language, full web page translation, full document translation (Word, PDF, Text), integration into Microsoft office spellers, leading dictionary packs - Oxford, Britannica, Merriam-Webster, etc, Babylon also does currency, measurements and time conversions. With that all, Babylon can be called a killer app.

I’d like to remember when exactly I started using Babylon and in which version it was, but that is a difficult task… Sometimes you get a little bit nostalgic.

Babylon has been evolving and in each new version new features get added and existing ones are refined. Version 8 in my humble opinion is fantastic!

Watch this video demo to see Babylon in action.

With Babylon there’s no more language barriers when it comes to read/written words. Take it with you and you can rest assured that you’ll have that word translated as fast as a mouse click.

Model View Presenter pattern with Castle in ASP.NET

This post shows how to implement the Model View Presenter (MVP) architectural pattern using Castle Project, which is an Inversion of Control Container framework. Castle Project has two IoC containers: MicroKernel and the Windsor Container.

Employing Castle Project containers and ASP.NET it turns out to be a simple task to have a Web App that takes advantage of the MVP pattern.

The simple approach I describe here is of great utility when you need a powerful and proven framework to develop your web applications based on Web Forms.

Let’s start with Solution Explorer inside Visual Studio 2008:

 MVP Web App Castle Project - Visual Studio Solution Explorer

In the following sections I’ll describe what role each file of the project plays…

Inversion of Control (IoC)
To implement the Inversion of Control principle, we define a static class called IoC as follows:

using System;
using Castle.Windsor;

namespace MvpWebAppCastleProject
{
    public static class IoC
    {
        private static IWindsorContainer container;

        public static void Initialize(IWindsorContainer aContainer)
        {
            container = aContainer;
        }

        public static T Resolve<T>()
        {
            try
            {
                return container.Resolve<T>();
            }
            catch(Exception e)
            {
                throw e;
            }
        }
    }
}

The container has a generic method Resolve<T> responsible for resolving at runtime the right component of your project to use.

Global.asax
In the Global.asax.cs code-behind file we initialize the IoC contatiner inside the Application_Start method:

using System;
using System.Web;

namespace MvpWebAppCastleProject
{
    public class Global : HttpApplication
    {
        protected void Application_Start(object sender, EventArgs e)
        {
            IoC.Initialize(new BusinessContainer());
        }
    }
}

As you see, a new instance of the class BusinessContainer is passed to the IoC.Initialize method. BusinessContainer is a custom made container that inherits from WindsorContainer:

using Castle.Core;
using Castle.Windsor;
using MvpWebAppCastleProject.Presenters;

namespace MvpWebAppCastleProject
{
    public class BusinessContainer : WindsorContainer
    {
        public BusinessContainer()
        {
            RegisterComponents();
        }

        private void RegisterComponents()
        {
            // Presenters
            AddComponentWithLifestyle("HelloWorld.presenter", typeof(HelloWorldPresenter), LifestyleType.Transient);
        }
    }
}

Inside the business container we register the components that are part of the web application. In this case, I’m registering only one component. I’m giving it the name HelloWorld.presenter and am also specifying its type as HelloWorldPresenter.

Defining a Base Presenter
Let’s define a base presenter to make things as generic as possible with the intent of avoiding code repetition and to keep code reuse throughout the app as follows:

using System;
using MvpWebAppCastleProject.Interfaces;

namespace MvpWebAppCastleProject.Presenters
{
    /// <summary>
    /// Base Presenter Typed
    /// All the Presenters should inherit from this one and implement the methods
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class BasePresenter<V>
        where V : IBaseView
    {
        /// <summary>
        /// Typed View
        /// </summary>
        protected static V view;

        protected BasePresenter()
        {

        }

        /// <summary>
        /// Registers the View to the Presenter
        /// </summary>
        /// <param name="myView">View type</param>
        public void RegisterView(V myView)
        {
            if(myView == null)
            {
                throw new ArgumentNullException("View cannot be null.");
            }

            view = myView;

            SubscribePresenterToViewEvents();
        }

        /// <summary>
        /// Subscribe the Presenter to View events
        /// </summary>
        protected abstract void SubscribePresenterToViewEvents();

        /// <summary>
        /// Specific FirstLoading implemented by each inheritor
        /// </summary>
        protected abstract void FirstLoading();

        /// <summary>
        /// Run when the page is loaded for the first time
        /// </summary>
        protected void FirstLoading(object source, EventArgs eventArgs)
        {
            FirstLoading();
        }
    }
}

BasePresenter is an abstract class that uses generics concepts. Looking at the class definition we have that when an object type inherits from the base presenter it must specify a view to which it’ll be linked. BasePresenter accepts any view that directly inherits from IBaseView.

BasePresenter also has abstract methods that’ll be materialized (overridden) inside each Presenter that inherits from it.

Defining a Base View
To keep things simple here, I haven’t done any work in the IBaseView interface, but you can make things generic inside your base view just as was done inside the base presenter:

namespace MvpWebAppCastleProject.Interfaces
{
    public interface IBaseView
    {

    }
}

Implementing a View Interface
Let’s now implement a view interface that inherits from the base interface IBaseView:

using System;

namespace MvpWebAppCastleProject.Interfaces
{
    public interface IHelloWorldView : IBaseView
    {
        event EventHandler FirstLoading;

        void HelloWorld();
    }
}

This view interface (contract) implies that a real view that inherits from it must implement an event handler called FirstLoading and a void method called HelloWorld().

Implementing a View that inherits from the View Interface
A view is nothing more than an .aspx page with its controls, events, methods and everything else.

This is the view’s code:

using System;
using System.Web.UI;
using MvpWebAppCastleProject.Interfaces;
using MvpWebAppCastleProject.Presenters;

namespace MvpWebAppCastleProject.Views
{
    public partial class HelloWorldView : Page, IHelloWorldView
    {
        private HelloWorldPresenter presenter;

        protected void Page_Load(object sender, EventArgs e)
        {
            // Inversion of Control
            presenter = IoC.Resolve<HelloWorldPresenter>();
            presenter.RegisterView(this);

            if(!IsPostBack)
            {
                if(FirstLoading != null)
                {
                    FirstLoading(this, EventArgs.Empty);
                }
            }
        }

        #region Implementation of IHelloWorldView

        public event EventHandler FirstLoading;

        public void HelloWorld()
        {
            Response.Write("Hello World from ASP.NET Web App that implements the MVP pattern!");
        }

        #endregion
    }
}

Here is where the components of the MVP pattern start to fit each other.

As you see the view inherits from the ASP.NET Page object and from its respective interface IHelloWorldView.

HellowWorldView has a reference to its respective presenter HelloWorldPresenter. This object (the presenter) is the one responsible for the business logic. It’s the incarnation of other programming pattern called Delegation.

Inside the view’s Page_Load method we use the IoC contatiner to resolve the presenter we want to bind to the view. Remember the Resolve<T> method inside the IoC class? This method will search the list of components registered in the method RegisterComponents() inside the BusinessContainer class defined above.

After having an instance of the presenter we’re ready to call its method RegisterView() passing to it this (the view/.aspx page).

Note that the view implements the event FirstLoading and the method HelloWorld() defined in its interface IHelloWorldView.

Implementing the Presenter
HelloWorldPresenter is the last piece of code to complete the MVP pattern. Here is its code:

using MvpWebAppCastleProject.Interfaces;

namespace MvpWebAppCastleProject.Presenters
{
    public class HelloWorldPresenter : BasePresenter<IHelloWorldView>
    {
        public HelloWorldPresenter()
        {

        }

        #region Overrides of BasePresenter<IHellowWorldView>

        /// <summary>
        /// Subscribe the Presenter to View events
        /// </summary>
        protected override void SubscribePresenterToViewEvents()
        {
            view.FirstLoading += FirstLoading;
        }

        /// <summary>
        /// Specific FirstLoading implemented by each inheritor
        /// </summary>
        protected override void FirstLoading()
        {
            view.HelloWorld();
        }

        #endregion
    }
}

The presenter class definition shows that it inherits from BasePresenter that takes an interface (IHelloWorld) as parameter. IHelloWorld is a valid interface because it inherits from IBaseView.

Now take a look at the overridden methods SubscribePresenterToViewEvents() and FirstLoading().

When the presenter first loads it’ll call its view method HelloWorld().

This is the output you get when you run the web app:

MVP Web App Castle Project - Hello World View

Summary
This post shows in a short and to the point way how you can implement the Model/View/Presenter pattern in your ASP.NET web applications.

Using the Model/View/Presenter pattern you’ll have more control over your code. It allows you to decouple responsibilities in your project in such way that you can delegate responsibilities to the right object in a clear fashion.

You keep the files that compose your solution in a folder structure that allows for fast maintenance and organization.

If you want to learn more about the subject discussed in this post, I advise you to read Wikipedia’s articles listed in the References section below.

Hope you make good use of it!

Notes
Although I do not present in this post the Model part of MVP, it’s straightforward to implement it. You’d have a new folder called Model in your project where you’d put the files related to your data model. You could employ LINQ to SQL to represent your model. Again you could use abstraction defining a base repository forcing repository classes to implement the base default methods.

You may have heard about the Model-View-Controller (MVC) pattern. MVP is in contrast with MVC. If you want to know the slight differences between these two patterns take a look at this excellent discussion on StackOverflow titled: What are MVP and MVC and what is the difference?

Visual Studio 2008 C# ASP.NET Web Application
You can get the Microsoft Visual Studio Project at:

http://sites.google.com/site/leniel/blog/MvpWebAppCastleProject.zip

To try out the code you can use the free Microsoft Visual Web Developer 2008 Express Edition that you can get at: http://www.microsoft.com/express/vwd/Default.aspx

References
Castle Project
http://www.castleproject.org/container/index.html

Windsor and MicroKernel documentation
http://www.castleproject.org/container/documentation/index.html

Architectural pattern
http://en.wikipedia.org/wiki/Architectural_pattern

Model View Presenter (MVP) article on Wikipedia
http://en.wikipedia.org/wiki/Model_View_Presenter

Model View Controller (MVC) article on Wikipedia
http://en.wikipedia.org/wiki/Model_View_Controller

Inversion of Control (IoC) article on Wikipedia
http://en.wikipedia.org/wiki/Inversion_of_control

Abstract Type article on Wikipedia
http://en.wikipedia.org/wiki/Abstract_type

Generic Programming article on Wikipedia
http://en.wikipedia.org/wiki/Generic_programming

Method overriding article on Wikipedia
http://en.wikipedia.org/wiki/Method_overriding

Interface article on Wikipedia
http://en.wikipedia.org/wiki/Interface_Computer_Science

Delegation pattern article on Wikipedia
http://en.wikipedia.org/wiki/Delegation_pattern

XHQ from IndX to Chemtech - A Siemens Company

During the past 7 business days I took part in a training about SIMATIC IT XHQ 4.0 software.
I participated in the Basic (21-22 Jan) and Advanced (25-29 Jan) training.

This training was given by the engineer Fabio Terasaka who’s a team lead at Chemtech having over 3 years of experience using and deploying XHQ in Brazil and internationally.

I decided to write this post so that people can get an overview of XHQ from a consultant/developer perspective.

I’m also excited about the endless possibilities XHQ has to offer when it comes to optimizing and applying intelligence to an enterprise.

What is XHQ?
For those who don’t know or who have never heard of XHQ, here goes a succinct description of it extracted from its official site:

SIMATIC IT XHQ Operations Intelligence product line aggregates, relates and presents operational and business data in real-time to improve enterprise performance. Through SIMATIC IT XHQ, you have a single coherent view of information, enabling a variety of solutions in real-time performance management and decision support. [1]

XQH extracts data from a variety of systems - as the production (PIMS), laboratory (LIMS) and plant-floor systems. XHQ unifies all the operational and management data in a single view, in real time, allowing you to take a snapshot, minute to minute or second to second, of all the enterprise.

XHQ can be integrated in the intranet or a website for operations management, integrating production data such as the use of raw material and equipment, stocks, as well as data related to the product (temperature, pressure, electrical current), quality and maintenance.

XHQ implements the concepts of Operational Dashboard and Management [2] by Key Performance Indicators (KPIs) [3].

XHQ is used in energy, petrochemical, and manufacturing industries to aggregate, draw relationships, and then graphically depict business and operational data.

XHQ Timeline
XHQ was created in 1996 by an American company called IndX Software Corp based on Aliso Viejo, California, USA.

In December 2003 Siemens expands its IT portfolio acquiring IndX [4].

In December 2009 Chemtech - A Siemens Company absorbs the company responsible for XHQ around the world [5].

XHQ Architecture
XHQ has a modular architecture as can be seen in the following picture:

XHQ Architecture Overview
XHQ Architecture Overview

Back-end Operational Systems
Comprised of databases and its respective connectors that give access to business real-time data: times series data (PHD, PI, OPC), real-time point data (Tags), relational databases (Oracle, MS-SQL), enterprise applications (SAP), etc.

Middle Tier
Comprised of XHQ set of servers. Each XHQ server plays a role in the system:

XHQ Enterprise Server manages the end-users views of data that are created by XHQ developers.

XHQ Solution Server has the Real-time Data Cache and the Relational Data Cache that removes the burden associated with backend data retrieval.

XHQ Alert Notification Server (XANS) is a subsystem of XHQ responsible for alerting end-users about any inconsistence existent in the system.

3rd Party Web Servers as IIS and Tomcat give end-users access to data processed by XHQ.

User Interface
Users can access XHQ processed data (Views) using PDAs, web browsers, etc.

Users also have access to View Statistics that is a kind of Google Analytics. It shows default reports about peak and average user count, user and view hits by month, user and view hits by week, view usage by user per day, view usage per day, etc. You can create your own analytics reports using custom SQL.

Starting with XHQ 4.0 there’s a separate application called Visual Composer that enables developers to create dynamic, high customizable data views. Visual Composer can use XHQ data collections as its data source.
Visual Composer focus in graphics/charts and tables/grids to show business strategic content.

XHQ behind the Curtains
XHQ does its job using a subscription model based on the client-server architecture. Clients are automatically notified of changes that occur on the monitored variables. For example, if a user uses a view that has 2 plant variables and their pool period (configured in the connector or on the variable itself) is set with 2 seconds, the user screen will automatically refresh (using Ajax) to show the new variable values at each 2 seconds. This is the so called real-time process management.

XHQ core is implemented in Java and uses a Java Applet that is loaded in the browser to present the data to the user.

XHQ makes extensive use of JavaScript to inject customization points into the software.

Servers configuration are kept in .properties files making it easy to edit.

Data presented to the user comes from “Collections” that use high performance data caches that are XHQ own local databases. You can use live data from the backend but it’s not advisable because of the overhead implied. The performance gains can be better verified when lots of users are using the same view.

Skills demanded by XHQ
To get XHQ up and running you’ll need the following skills:

SQL query skills. SQL is used all the time to retrieve the right data from the back-ends.

XML and XSLT skills. Both necessary to configure data points (Tags) in the system and to export data.

Previous software development skills using the .NET Framework or Java are important to develop extension points to XHQ.

JavaScript skills. Used to define custom system variables and client configuration.

HTML and CSS skills. Used to customize the user UI.

Web server administration using IIS and Tomcat is a plus when it comes to deploying the solution in the customer.

Computer network skills. Used to detected any problem between clients and servers.

Solid debugging skills related to the above mentioned technologies. If something goes wrong, you’ll need to check a lot of log files (there is one for each agent in the system).

XHQ Implementation
XHQ consultants/engineers are the guys responsible for studying the necessities of the customer interested in optimizing the enterprise.

The following are 10 basic steps used when XHQ is implemented as the choice for business optimization:

01 - XHQ is installed on client premises;
02 - Groups of users and use cases are defined;
03 - Connectors are created to access data sources scattered all over the enterprise;
04 - A solution model is defined;
05 - A navigation model is defined; 
06 - Views of data for different audiences and activities are built;
07 - System components and collections of data are linked for data retrieval;
08 - The solution is updated, tested and optimized;
09 - Steps 1 through 7 are iterated;
10 - Security is applied in the solution model through the use of roles/user groups.

XHQ Value as a RtPM Tool
XHQ aggregates value to your business as a RtPM (Real-time Process Management) tool:

Using XHQ, operational costs may decrease an average of 8% each year, while the production of high value products may increase 10.5%. This is because XHQ helps the management board in the decision taking process. [6]

The following are 10 basic reasons why XHQ aggregates value to the business:

01 - Directors and staff can take their decisions based on the same information;
02 - Response times are dramatically reduced;
03 - Information availability is made true from one area to another (and vice-versa);
04 - Interfaces between one area and another, usually managed by different teams and systems, can be closely monitored;
05 - User-friendly and self-explained process schematics simplify plan management;
06 - Reduced load on mission-critical systems: read only users can use only XHQ;
07 - Leverage of other investments: PIMS systems utilization is increased, and become mission-critical as well;
08 - Intangible gain: re-think strategies for company needs in terms of what information is
considered critical for business decisions;
09 - Integration with enterprise applications as SAP R/3, logistics is greatly improved by
watching supply and distribution movements;
10 - Transport can come and go (monitored) graphically.

XHQ Customers
XHQ is used throughout the world.

The following are some of the customers already using XHQ to optimize their business:

CSN, ExxonMobil, Chevron, Dow Chemical, Saudi Aramco among others.

Interested in optimizing your business?
If you’re looking for business optimization/intelligence, you can get in contact with Chemtech for more information.

Chemtech - Complete Solutions for Business Optimization

References
[1] SIMATIC IT XHQ official site

[2] Business Performance Management

[3] Key Performance Indicator

[4] Siemens expands its IT portfolio in process industries (PDF file)

[5] Chemtech absorbs the company responsible for XHQ around the world

[6] Siemens of Brazil Press Information (in Portuguese)

[7] XHQ for Steel Mills Real Time Performance Management (PDF file)

[8] XHQ can gather information from the whole oil & gas production chain

[9] Chemtech enters into the IndX’s biggest XHQ project in Brazil

Adding or removing Liferay portlets

I had to install the Blogs portlet in Liferay.

Liferay is the all purpose portal framework that Chemtech uses to build its website.

The Liferay portal already deployed on production server is the 3.4.5 version. When I tried to add the Blogs portlet through the Add Content menu option I couldn’t find it.

Liferay Add Content Menu

Googling about Liferay’s Blogs portlet didn’t help me. The only positive clue I had was

Liferay Portal Administrator's Guide, Third Edition

(page 124) which has a section dedicated to the Blogs portlet.

I tried to understand why the Blogs portlet wasn’t available in the Add Content window:

Liferay Add Content Window No Blogs portlet available

Was it because the blogs portlet didn’t make it into the version 4.3.5 of the portal? The answer is no. The blogs portlet is available in version 4.3.5 (with limitations if compared to the Blogs portlet of today’s Liferay version that is currently 5.2.3).

After a little bit of more googling I found Development in the ext environment wiki article. I read in item 4 that you can turn portlets you want to deploy on/off by editing the file

\ext\ext-web\docroot\WEB-INF\liferay-portlet-ext.xml

Mine was located in

E:\chemsite\tomcat\webapps\lportal\WEB-INF\liferay-portlet-ext.xml

I did just that turning the Blogs portlet ON setting the <include> property to true:

<!--
    Liferay Portlets

    To create a minimal installation of Liferay so that only the essential Liferay portlets are available, uncomment the following block and set the include attribute to false for the portlets you want to remove. To make a portlet available, set the include attribute to true. The struts-path attribute is shown so that it's easier for the editor of this file to associate a portlet id with a portlet.
-->

<portlet>
          <portlet-name>33</portlet-name>
          <struts-path>blogs</struts-path>
          <include>true</include>
</portlet>

I then rerun Liferay portal using Eclipse. For my surprise I could find the Collaboration category in the Add Content window with the Blogs entry available:

Liferay Add Content Window with Blogs portlet

Hope this shortens the path when you come to need to turn a portlet on/off.